diff options
| author | Tim Hobbs <jesus.tesh@gmail.com> | 2014-03-24 09:37:44 -0700 |
|---|---|---|
| committer | Tim Hobbs <jesus.tesh@gmail.com> | 2014-03-24 09:37:44 -0700 |
| commit | 38a0af6e86d3bdf8794343b03d26659d4bf89093 (patch) | |
| tree | f3c92b89ae3e8a7e744ee13eb1b16139da690622 | |
| parent | 543ce24c1051d10b32c0dae5277ee37c27daceae (diff) | |
| parent | 501dedb13cd59dc2683ac4192cd11289bd304cfb (diff) | |
Merge remote-tracking branch 'upstream/master'
71 files changed, 4465 insertions, 1642 deletions
diff --git a/MediaBrowser.Api/LocalizationService.cs b/MediaBrowser.Api/LocalizationService.cs index b3f6cbd97..60270a389 100644 --- a/MediaBrowser.Api/LocalizationService.cs +++ b/MediaBrowser.Api/LocalizationService.cs @@ -10,8 +10,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetCultures /// </summary> - [Route("/Localization/Cultures", "GET")] - [Api(Description = "Gets known cultures")] + [Route("/Localization/Cultures", "GET", Summary = "Gets known cultures")] public class GetCultures : IReturn<List<CultureDto>> { } @@ -19,8 +18,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetCountries /// </summary> - [Route("/Localization/Countries", "GET")] - [Api(Description = "Gets known countries")] + [Route("/Localization/Countries", "GET", Summary = "Gets known countries")] public class GetCountries : IReturn<List<CountryInfo>> { } @@ -28,8 +26,7 @@ namespace MediaBrowser.Api /// <summary> /// Class ParentalRatings /// </summary> - [Route("/Localization/ParentalRatings", "GET")] - [Api(Description = "Gets known parental ratings")] + [Route("/Localization/ParentalRatings", "GET", Summary = "Gets known parental ratings")] public class GetParentalRatings : IReturn<List<ParentalRating>> { } diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index f9b760869..204a7aab4 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -117,10 +117,9 @@ namespace MediaBrowser.Api.Movies public object Get(GetMovieRecommendations request) { - var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null; + var user = _userManager.GetUserById(request.UserId.Value); - var folder = user.RootFolder; - var movies = folder.RecursiveChildren.OfType<Movie>().ToList(); + var movies = user.RootFolder.GetRecursiveChildren(user).OfType<Movie>().ToList(); var result = GetRecommendationCategories(user, movies, request.CategoryLimit, request.ItemLimit, request.GetItemFields().ToList()); diff --git a/MediaBrowser.Api/NewsService.cs b/MediaBrowser.Api/NewsService.cs index 99a4d4fa7..6243bf25f 100644 --- a/MediaBrowser.Api/NewsService.cs +++ b/MediaBrowser.Api/NewsService.cs @@ -5,8 +5,7 @@ using ServiceStack; namespace MediaBrowser.Api { - [Route("/News/Product", "GET")] - [Api(Description = "Gets the latest product news.")] + [Route("/News/Product", "GET", Summary = "Gets the latest product news.")] public class GetProductNews : IReturn<QueryResult<NewsItem>> { /// <summary> @@ -23,7 +22,7 @@ namespace MediaBrowser.Api [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? Limit { get; set; } } - + public class NewsService : BaseApiService { private readonly INewsService _newsService; @@ -37,8 +36,8 @@ namespace MediaBrowser.Api { var result = _newsService.GetProductNews(new NewsQuery { - StartIndex = request.StartIndex, - Limit = request.Limit + StartIndex = request.StartIndex, + Limit = request.Limit }); diff --git a/MediaBrowser.Api/NotificationsService.cs b/MediaBrowser.Api/NotificationsService.cs index 45a16347b..a71a85395 100644 --- a/MediaBrowser.Api/NotificationsService.cs +++ b/MediaBrowser.Api/NotificationsService.cs @@ -1,15 +1,14 @@ using MediaBrowser.Controller.Notifications; using MediaBrowser.Model.Notifications; +using ServiceStack; using System; using System.Linq; using System.Threading; using System.Threading.Tasks; -using ServiceStack; namespace MediaBrowser.Api { - [Route("/Notifications/{UserId}", "GET")] - [Api(Description = "Gets notifications")] + [Route("/Notifications/{UserId}", "GET", Summary = "Gets notifications")] public class GetNotifications : IReturn<NotificationResult> { [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] @@ -25,16 +24,14 @@ namespace MediaBrowser.Api public int? Limit { get; set; } } - [Route("/Notifications/{UserId}/Summary", "GET")] - [Api(Description = "Gets a notification summary for a user")] + [Route("/Notifications/{UserId}/Summary", "GET", Summary = "Gets a notification summary for a user")] public class GetNotificationsSummary : IReturn<NotificationsSummary> { [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public Guid UserId { get; set; } } - [Route("/Notifications/{UserId}", "POST")] - [Api(Description = "Adds a notifications")] + [Route("/Notifications/{UserId}", "POST", Summary = "Adds a notifications")] public class AddUserNotification : IReturn<Notification> { [ApiMember(Name = "Id", Description = "The Id of the new notification. If unspecified one will be provided.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] @@ -61,9 +58,8 @@ namespace MediaBrowser.Api [ApiMember(Name = "Level", Description = "The notification level", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] public NotificationLevel Level { get; set; } } - - [Route("/Notifications/{UserId}/Read", "POST")] - [Api(Description = "Marks notifications as read")] + + [Route("/Notifications/{UserId}/Read", "POST", Summary = "Marks notifications as read")] public class MarkRead : IReturnVoid { [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] @@ -73,8 +69,7 @@ namespace MediaBrowser.Api public string Ids { get; set; } } - [Route("/Notifications/{UserId}/Unread", "POST")] - [Api(Description = "Marks notifications as unread")] + [Route("/Notifications/{UserId}/Unread", "POST", Summary = "Marks notifications as unread")] public class MarkUnread : IReturnVoid { [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] diff --git a/MediaBrowser.Api/PackageReviewService.cs b/MediaBrowser.Api/PackageReviewService.cs index b2de908d9..94ff1b62e 100644 --- a/MediaBrowser.Api/PackageReviewService.cs +++ b/MediaBrowser.Api/PackageReviewService.cs @@ -1,21 +1,20 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Constants; +using MediaBrowser.Common.Constants; using MediaBrowser.Common.Net; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Serialization; using ServiceStack; +using System.Collections.Generic; +using System.Globalization; +using System.Net; +using System.Threading; +using System.Threading.Tasks; namespace MediaBrowser.Api { /// <summary> /// Class InstallPackage /// </summary> - [Route("/PackageReviews/{Id}", "POST")] - [Api(("Creates or updates a package review"))] + [Route("/Packages/Reviews/{Id}", "POST", Summary = "Creates or updates a package review")] public class CreateReviewRequest : IReturnVoid { /// <summary> @@ -57,8 +56,7 @@ namespace MediaBrowser.Api /// <summary> /// Class InstallPackage /// </summary> - [Route("/PackageReviews/{Id}", "GET")] - [Api(("Retrieve reviews for a package"))] + [Route("/Packages/{Id}/Reviews", "GET", Summary = "Gets reviews for a package")] public class ReviewRequest : IReturn<List<PackageReviewInfo>> { /// <summary> @@ -114,7 +112,7 @@ namespace MediaBrowser.Api public object Get(ReviewRequest request) { var parms = "?id=" + request.Id; - + if (request.MaxRating > 0) { parms += "&max=" + request.MaxRating; @@ -132,7 +130,7 @@ namespace MediaBrowser.Api parms += "&title=true"; } - var result = _httpClient.Get(Constants.MbAdminUrl + "/service/packageReview/retrieve"+parms, CancellationToken.None).Result; + var result = _httpClient.Get(Constants.MbAdminUrl + "/service/packageReview/retrieve" + parms, CancellationToken.None).Result; var reviews = _serializer.DeserializeFromStream<List<PackageReviewInfo>>(result); diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index 793b666ea..948a67f16 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -14,8 +14,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetPackage /// </summary> - [Route("/Packages/{Name}", "GET")] - [Api(("Gets a package, by name or assembly guid"))] + [Route("/Packages/{Name}", "GET", Summary = "Gets a package, by name or assembly guid")] public class GetPackage : IReturn<PackageInfo> { /// <summary> @@ -36,8 +35,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetPackages /// </summary> - [Route("/Packages", "GET")] - [Api(("Gets available packages"))] + [Route("/Packages", "GET", Summary = "Gets available packages")] public class GetPackages : IReturn<List<PackageInfo>> { /// <summary> @@ -57,8 +55,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetPackageVersionUpdates /// </summary> - [Route("/Packages/Updates", "GET")] - [Api(("Gets available package updates for currently installed packages"))] + [Route("/Packages/Updates", "GET", Summary = "Gets available package updates for currently installed packages")] public class GetPackageVersionUpdates : IReturn<List<PackageVersionInfo>> { /// <summary> @@ -72,8 +69,7 @@ namespace MediaBrowser.Api /// <summary> /// Class InstallPackage /// </summary> - [Route("/Packages/Installed/{Name}", "POST")] - [Api(("Installs a package"))] + [Route("/Packages/Installed/{Name}", "POST", Summary = "Installs a package")] public class InstallPackage : IReturnVoid { /// <summary> @@ -108,8 +104,7 @@ namespace MediaBrowser.Api /// <summary> /// Class CancelPackageInstallation /// </summary> - [Route("/Packages/Installing/{Id}", "DELETE")] - [Api(("Cancels a package installation"))] + [Route("/Packages/Installing/{Id}", "DELETE", Summary = "Cancels a package installation")] public class CancelPackageInstallation : IReturnVoid { /// <summary> diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 1001980ec..a6b3b7294 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -9,7 +9,6 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Drawing; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Library; @@ -735,14 +734,21 @@ namespace MediaBrowser.Api.Playback { if (audioStream != null) { - if (audioStream.Channels > 2 && request.AudioCodec.HasValue) + if (audioStream.Channels > 2 && string.Equals(request.AudioCodec, "wma", StringComparison.OrdinalIgnoreCase)) { - if (request.AudioCodec.Value == AudioCodecs.Wma) - { - // wmav2 currently only supports two channel output - return 2; - } + // wmav2 currently only supports two channel output + return 2; + } + } + + if (request.MaxAudioChannels.HasValue) + { + if (audioStream != null && audioStream.Channels.HasValue) + { + return Math.Min(request.MaxAudioChannels.Value, audioStream.Channels.Value); } + + return request.MaxAudioChannels.Value; } return request.AudioChannels; @@ -768,26 +774,26 @@ namespace MediaBrowser.Api.Playback { var codec = request.AudioCodec; - if (codec.HasValue) + if (!string.IsNullOrEmpty(codec)) { - if (codec == AudioCodecs.Aac) + if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase)) { return "aac -strict experimental"; } - if (codec == AudioCodecs.Mp3) + if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase)) { return "libmp3lame"; } - if (codec == AudioCodecs.Vorbis) + if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase)) { return "libvorbis"; } - if (codec == AudioCodecs.Wma) + if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase)) { return "wmav2"; } - return codec.ToString().ToLower(); + return codec.ToLower(); } return "copy"; @@ -802,26 +808,26 @@ namespace MediaBrowser.Api.Playback { var codec = request.VideoCodec; - if (codec.HasValue) + if (!string.IsNullOrEmpty(codec)) { - if (codec == VideoCodecs.H264) + if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase)) { return "libx264"; } - if (codec == VideoCodecs.Vpx) + if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase)) { return "libvpx"; } - if (codec == VideoCodecs.Wmv) + if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase)) { return "msmpeg4"; } - if (codec == VideoCodecs.Theora) + if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase)) { return "libtheora"; } - return codec.ToString().ToLower(); + return codec.ToLower(); } return "copy"; @@ -1201,77 +1207,81 @@ namespace MediaBrowser.Api.Playback if (i == 0) { - request.DeviceId = val; + // Device profile name } else if (i == 1) { - request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + request.DeviceId = val; } else if (i == 2) { + request.MediaSourceId = val; + } + else if (i == 3) + { + request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + else if (i == 4) + { if (videoRequest != null) { - videoRequest.VideoCodec = (VideoCodecs)Enum.Parse(typeof(VideoCodecs), val, true); + videoRequest.VideoCodec = val; } } - else if (i == 3) + else if (i == 5) { - request.AudioCodec = (AudioCodecs)Enum.Parse(typeof(AudioCodecs), val, true); + request.AudioCodec = val; } - else if (i == 4) + else if (i == 6) { if (videoRequest != null) { videoRequest.AudioStreamIndex = int.Parse(val, UsCulture); } } - else if (i == 5) + else if (i == 7) { if (videoRequest != null) { videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture); } } - else if (i == 6) + else if (i == 8) { if (videoRequest != null) { videoRequest.VideoBitRate = int.Parse(val, UsCulture); } } - else if (i == 7) + else if (i == 9) { request.AudioBitRate = int.Parse(val, UsCulture); } - else if (i == 8) + else if (i == 10) { - request.AudioChannels = int.Parse(val, UsCulture); + request.MaxAudioChannels = int.Parse(val, UsCulture); } - else if (i == 9) + else if (i == 11) { if (videoRequest != null) { request.StartTimeTicks = long.Parse(val, UsCulture); } } - else if (i == 10) + else if (i == 12) { if (videoRequest != null) { videoRequest.Profile = val; } } - else if (i == 11) + else if (i == 13) { if (videoRequest != null) { videoRequest.Level = val; } } - else if (i == 12) - { - request.ForcedMimeType = val; - } } } @@ -1297,7 +1307,7 @@ namespace MediaBrowser.Api.Playback var url = Request.PathInfo; - if (!request.AudioCodec.HasValue) + if (string.IsNullOrEmpty(request.AudioCodec)) { request.AudioCodec = InferAudioCodec(url); } @@ -1425,7 +1435,7 @@ namespace MediaBrowser.Api.Playback if (videoRequest != null) { - if (!videoRequest.VideoCodec.HasValue) + if (string.IsNullOrEmpty(videoRequest.VideoCodec)) { videoRequest.VideoCodec = InferVideoCodec(url); } @@ -1532,41 +1542,41 @@ namespace MediaBrowser.Api.Playback /// </summary> /// <param name="url">The URL.</param> /// <returns>System.Nullable{AudioCodecs}.</returns> - private AudioCodecs? InferAudioCodec(string url) + private string InferAudioCodec(string url) { var ext = Path.GetExtension(url); if (string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase)) { - return AudioCodecs.Mp3; + return "mp3"; } if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase)) { - return AudioCodecs.Aac; + return "aac"; } if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase)) { - return AudioCodecs.Wma; + return "wma"; } if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase)) { - return AudioCodecs.Vorbis; + return "vorbis"; } if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase)) { - return AudioCodecs.Vorbis; + return "vorbis"; } if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) { - return AudioCodecs.Vorbis; + return "vorbis"; } if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) { - return AudioCodecs.Vorbis; + return "vorbis"; } if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase)) { - return AudioCodecs.Vorbis; + return "vorbis"; } return null; @@ -1577,28 +1587,28 @@ namespace MediaBrowser.Api.Playback /// </summary> /// <param name="url">The URL.</param> /// <returns>System.Nullable{VideoCodecs}.</returns> - private VideoCodecs? InferVideoCodec(string url) + private string InferVideoCodec(string url) { var ext = Path.GetExtension(url); if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase)) { - return VideoCodecs.Wmv; + return "wmv"; } if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) { - return VideoCodecs.Vpx; + return "vpx"; } if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) { - return VideoCodecs.Theora; + return "theora"; } if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase)) { - return VideoCodecs.H264; + return "h264"; } - return VideoCodecs.Copy; + return "copy"; } } } diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index aec271ff2..eb8f415e0 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -91,11 +91,11 @@ namespace MediaBrowser.Api.Playback.Hls { var state = GetState(request, CancellationToken.None).Result; - if (!state.VideoRequest.VideoBitRate.HasValue && (!state.VideoRequest.VideoCodec.HasValue || state.VideoRequest.VideoCodec.Value != VideoCodecs.Copy)) + if (!state.VideoRequest.VideoBitRate.HasValue && (string.IsNullOrEmpty(state.VideoRequest.VideoCodec) || !string.Equals(state.VideoRequest.VideoCodec, "copy", StringComparison.OrdinalIgnoreCase))) { throw new ArgumentException("A video bitrate is required"); } - if (!state.Request.AudioBitRate.HasValue && (!state.Request.AudioCodec.HasValue || state.Request.AudioCodec.Value != AudioCodecs.Copy)) + if (!state.Request.AudioBitRate.HasValue && (string.IsNullOrEmpty(state.Request.AudioCodec) || !string.Equals(state.Request.AudioCodec, "copy", StringComparison.OrdinalIgnoreCase))) { throw new ArgumentException("An audio bitrate is required"); } diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 121957ecc..66e8b0d14 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -136,11 +136,11 @@ namespace MediaBrowser.Api.Playback.Hls { var state = await GetState(request, CancellationToken.None).ConfigureAwait(false); - if (!state.VideoRequest.VideoBitRate.HasValue && (!state.VideoRequest.VideoCodec.HasValue || state.VideoRequest.VideoCodec.Value != VideoCodecs.Copy)) + if (!state.VideoRequest.VideoBitRate.HasValue && (string.IsNullOrEmpty(state.VideoRequest.VideoCodec) || !string.Equals(state.VideoRequest.VideoCodec, "copy", StringComparison.OrdinalIgnoreCase))) { throw new ArgumentException("A video bitrate is required"); } - if (!state.Request.AudioBitRate.HasValue && (!state.Request.AudioCodec.HasValue || state.Request.AudioCodec.Value != AudioCodecs.Copy)) + if (!state.Request.AudioBitRate.HasValue && (string.IsNullOrEmpty(state.Request.AudioCodec) || !string.Equals(state.Request.AudioCodec, "copy", StringComparison.OrdinalIgnoreCase))) { throw new ArgumentException("An audio bitrate is required"); } diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 8ae61b521..9cb989fc2 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -50,39 +50,49 @@ namespace MediaBrowser.Api.Playback.Progressive var videoRequest = state.Request as VideoStreamRequest; // Try to infer based on the desired video codec - if (videoRequest != null && videoRequest.VideoCodec.HasValue) + if (videoRequest != null && !string.IsNullOrEmpty(videoRequest.VideoCodec)) { if (state.IsInputVideo) { - switch (videoRequest.VideoCodec.Value) + if (string.Equals(videoRequest.VideoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { - case VideoCodecs.H264: - return ".ts"; - case VideoCodecs.Theora: - return ".ogv"; - case VideoCodecs.Vpx: - return ".webm"; - case VideoCodecs.Wmv: - return ".asf"; + return ".ts"; + } + if (string.Equals(videoRequest.VideoCodec, "theora", StringComparison.OrdinalIgnoreCase)) + { + return ".ogv"; + } + if (string.Equals(videoRequest.VideoCodec, "vpx", StringComparison.OrdinalIgnoreCase)) + { + return ".webm"; + } + if (string.Equals(videoRequest.VideoCodec, "wmv", StringComparison.OrdinalIgnoreCase)) + { + return ".asf"; } } } // Try to infer based on the desired audio codec - if (state.Request.AudioCodec.HasValue) + if (!string.IsNullOrEmpty(state.Request.AudioCodec)) { if (!state.IsInputVideo) { - switch (state.Request.AudioCodec.Value) + if (string.Equals("aac", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase)) + { + return ".aac"; + } + if (string.Equals("mp3", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase)) + { + return ".mp3"; + } + if (string.Equals("vorbis", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase)) + { + return ".ogg"; + } + if (string.Equals("wma", state.Request.AudioCodec, StringComparison.OrdinalIgnoreCase)) { - case AudioCodecs.Aac: - return ".aac"; - case AudioCodecs.Mp3: - return ".mp3"; - case AudioCodecs.Vorbis: - return ".ogg"; - case AudioCodecs.Wma: - return ".wma"; + return ".wma"; } } } diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index df52e5e3e..3439621e9 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Model.Dto; -using ServiceStack; +using ServiceStack; namespace MediaBrowser.Api.Playback { @@ -26,7 +25,7 @@ namespace MediaBrowser.Api.Playback /// </summary> /// <value>The audio codec.</value> [ApiMember(Name = "AudioCodec", Description = "Optional. Specify a audio codec to encode to, e.g. mp3. If omitted the server will auto-select using the url's extension. Options: aac, mp3, vorbis, wma.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public AudioCodecs? AudioCodec { get; set; } + public string AudioCodec { get; set; } /// <summary> /// Gets or sets the start time ticks. @@ -49,6 +48,9 @@ namespace MediaBrowser.Api.Playback [ApiMember(Name = "AudioChannels", Description = "Optional. Specify a specific number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? AudioChannels { get; set; } + [ApiMember(Name = "MaxAudioChannels", Description = "Optional. Specify a maximum number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? MaxAudioChannels { get; set; } + /// <summary> /// Gets or sets the audio sample rate. /// </summary> @@ -69,8 +71,6 @@ namespace MediaBrowser.Api.Playback public bool ThrowDebugError { get; set; } public string Params { get; set; } - - public string ForcedMimeType { get; set; } } public class VideoStreamRequest : StreamRequest @@ -80,7 +80,7 @@ namespace MediaBrowser.Api.Playback /// </summary> /// <value>The video codec.</value> [ApiMember(Name = "VideoCodec", Description = "Optional. Specify a video codec to encode to, e.g. h264. If omitted the server will auto-select using the url's extension. Options: h264, mpeg4, theora, vpx, wmv.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public VideoCodecs? VideoCodec { get; set; } + public string VideoCodec { get; set; } /// <summary> /// Gets or sets the video bit rate. diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 88daf9f62..ecc5c93ef 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -79,16 +79,6 @@ namespace MediaBrowser.Api.Playback public string GetMimeType(string outputPath) { - if (!string.IsNullOrWhiteSpace(Request.ForcedMimeType)) - { - if (VideoRequest == null) - { - return "audio/" + Request.ForcedMimeType; - } - - return "video/" + Request.ForcedMimeType; - } - return MimeTypes.GetMimeType(outputPath); } } diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs index e66f432df..31463dc3f 100644 --- a/MediaBrowser.Api/PluginService.cs +++ b/MediaBrowser.Api/PluginService.cs @@ -18,8 +18,7 @@ namespace MediaBrowser.Api /// <summary> /// Class Plugins /// </summary> - [Route("/Plugins", "GET")] - [Api(("Gets a list of currently installed plugins"))] + [Route("/Plugins", "GET", Summary = "Gets a list of currently installed plugins")] public class GetPlugins : IReturn<List<PluginInfo>> { } @@ -27,8 +26,7 @@ namespace MediaBrowser.Api /// <summary> /// Class UninstallPlugin /// </summary> - [Route("/Plugins/{Id}", "DELETE")] - [Api(("Uninstalls a plugin"))] + [Route("/Plugins/{Id}", "DELETE", Summary = "Uninstalls a plugin")] public class UninstallPlugin : IReturnVoid { /// <summary> @@ -42,8 +40,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetPluginConfiguration /// </summary> - [Route("/Plugins/{Id}/Configuration", "GET")] - [Api(("Gets a plugin's configuration"))] + [Route("/Plugins/{Id}/Configuration", "GET", Summary = "Gets a plugin's configuration")] public class GetPluginConfiguration { /// <summary> @@ -57,8 +54,7 @@ namespace MediaBrowser.Api /// <summary> /// Class UpdatePluginConfiguration /// </summary> - [Route("/Plugins/{Id}/Configuration", "POST")] - [Api(("Updates a plugin's configuration"))] + [Route("/Plugins/{Id}/Configuration", "POST", Summary = "Updates a plugin's configuration")] public class UpdatePluginConfiguration : IRequiresRequestStream, IReturnVoid { /// <summary> @@ -78,8 +74,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetPluginSecurityInfo /// </summary> - [Route("/Plugins/SecurityInfo", "GET")] - [Api(("Gets plugin registration information"))] + [Route("/Plugins/SecurityInfo", "GET", Summary = "Gets plugin registration information")] public class GetPluginSecurityInfo : IReturn<PluginSecurityInfo> { } @@ -87,14 +82,12 @@ namespace MediaBrowser.Api /// <summary> /// Class UpdatePluginSecurityInfo /// </summary> - [Route("/Plugins/SecurityInfo", "POST")] - [Api("Updates plugin registration information")] + [Route("/Plugins/SecurityInfo", "POST", Summary = "Updates plugin registration information")] public class UpdatePluginSecurityInfo : PluginSecurityInfo, IReturnVoid { } - [Route("/Plugins/RegistrationRecords/{Name}", "GET")] - [Api("Gets registration status for a feature")] + [Route("/Plugins/RegistrationRecords/{Name}", "GET", Summary = "Gets registration status for a feature")] public class GetRegistrationStatus { [ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs index c143635bf..0d3f5dfcd 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs @@ -39,6 +39,8 @@ namespace MediaBrowser.Api.ScheduledTasks TaskManager = taskManager; } + private bool _lastResponseHadTasksRunning = true; + /// <summary> /// Gets the data to send. /// </summary> @@ -46,7 +48,25 @@ namespace MediaBrowser.Api.ScheduledTasks /// <returns>Task{IEnumerable{TaskInfo}}.</returns> protected override Task<IEnumerable<TaskInfo>> GetDataToSend(object state) { - return Task.FromResult(TaskManager.ScheduledTasks + var tasks = TaskManager.ScheduledTasks.ToList(); + + var anyRunning = tasks.Any(i => i.State != TaskState.Idle); + + if (anyRunning) + { + _lastResponseHadTasksRunning = true; + } + else + { + if (!_lastResponseHadTasksRunning) + { + return Task.FromResult<IEnumerable<TaskInfo>>(null); + } + + _lastResponseHadTasksRunning = false; + } + + return Task.FromResult(tasks .OrderBy(i => i.Name) .Select(ScheduledTaskHelpers.GetTaskInfo) .Where(i => !i.IsHidden)); diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index f46c6b8e3..662c728e4 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -1,5 +1,4 @@ -using System; -using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -8,6 +7,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Search; using ServiceStack; +using System; using System.Linq; using System.Threading.Tasks; @@ -16,8 +16,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetSearchHints /// </summary> - [Route("/Search/Hints", "GET")] - [Api(Description = "Gets search hints based on a search term")] + [Route("/Search/Hints", "GET", Summary = "Gets search hints based on a search term")] public class GetSearchHints : IReturn<SearchHintResult> { /// <summary> @@ -66,7 +65,7 @@ namespace MediaBrowser.Api [ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string IncludeItemTypes { get; set; } - + public GetSearchHints() { IncludeArtists = true; diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs index e73e3490e..a509c876c 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -14,8 +14,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetSessions /// </summary> - [Route("/Sessions", "GET")] - [Api(("Gets a list of sessions"))] + [Route("/Sessions", "GET", Summary = "Gets a list of sessions")] public class GetSessions : IReturn<List<SessionInfoDto>> { /// <summary> @@ -28,15 +27,14 @@ namespace MediaBrowser.Api [ApiMember(Name = "ControllableByUserId", Description = "Optional. Filter by sessions that a given user is allowed to remote control.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public Guid? ControllableByUserId { get; set; } - [ApiMember(Name = "DeviceId", Description = "Optional. Filter by device id.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + [ApiMember(Name = "DeviceId", Description = "Optional. Filter by device id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string DeviceId { get; set; } } /// <summary> /// Class BrowseTo /// </summary> - [Route("/Sessions/{Id}/Viewing", "POST")] - [Api(("Instructs a session to browse to an item or view"))] + [Route("/Sessions/{Id}/Viewing", "POST", Summary = "Instructs a session to browse to an item or view")] public class BrowseTo : IReturnVoid { /// <summary> @@ -77,8 +75,7 @@ namespace MediaBrowser.Api public string Context { get; set; } } - [Route("/Sessions/{Id}/Playing", "POST")] - [Api(("Instructs a session to play an item"))] + [Route("/Sessions/{Id}/Playing", "POST", Summary = "Instructs a session to play an item")] public class Play : IReturnVoid { /// <summary> @@ -110,8 +107,7 @@ namespace MediaBrowser.Api public PlayCommand PlayCommand { get; set; } } - [Route("/Sessions/{Id}/Playing/{Command}", "POST")] - [Api(("Issues a playstate command to a client"))] + [Route("/Sessions/{Id}/Playing/{Command}", "POST", Summary = "Issues a playstate command to a client")] public class SendPlaystateCommand : IReturnVoid { /// <summary> @@ -135,8 +131,7 @@ namespace MediaBrowser.Api public PlaystateCommand Command { get; set; } } - [Route("/Sessions/{Id}/System/{Command}", "POST")] - [Api(("Issues a system command to a client"))] + [Route("/Sessions/{Id}/System/{Command}", "POST", Summary = "Issues a system command to a client")] public class SendSystemCommand : IReturnVoid { /// <summary> @@ -154,8 +149,7 @@ namespace MediaBrowser.Api public SystemCommand Command { get; set; } } - [Route("/Sessions/{Id}/Message", "POST")] - [Api(("Issues a command to a client to display a message to the user"))] + [Route("/Sessions/{Id}/Message", "POST", Summary = "Issues a command to a client to display a message to the user")] public class SendMessageCommand : IReturnVoid { /// <summary> @@ -175,8 +169,7 @@ namespace MediaBrowser.Api public long? TimeoutMs { get; set; } } - [Route("/Sessions/{Id}/Users/{UserId}", "POST")] - [Api(("Adds an additional user to a session"))] + [Route("/Sessions/{Id}/Users/{UserId}", "POST", Summary = "Adds an additional user to a session")] public class AddUserToSession : IReturnVoid { [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] @@ -186,8 +179,7 @@ namespace MediaBrowser.Api public Guid UserId { get; set; } } - [Route("/Sessions/{Id}/Users/{UserId}", "DELETE")] - [Api(("Removes an additional user from a session"))] + [Route("/Sessions/{Id}/Users/{UserId}", "DELETE", Summary = "Removes an additional user from a session")] public class RemoveUserFromSession : IReturnVoid { [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] @@ -197,8 +189,7 @@ namespace MediaBrowser.Api public Guid UserId { get; set; } } - [Route("/Sessions/{Id}/Capabilities", "POST")] - [Api(("Updates capabilities for a device"))] + [Route("/Sessions/{Id}/Capabilities", "POST", Summary = "Updates capabilities for a device")] public class PostCapabilities : IReturnVoid { /// <summary> diff --git a/MediaBrowser.Api/SystemService.cs b/MediaBrowser.Api/SystemService.cs index 9f5f3716e..2f0741434 100644 --- a/MediaBrowser.Api/SystemService.cs +++ b/MediaBrowser.Api/SystemService.cs @@ -8,8 +8,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetSystemInfo /// </summary> - [Route("/System/Info", "GET")] - [Api(Description = "Gets information about the server")] + [Route("/System/Info", "GET", Summary = "Gets information about the server")] public class GetSystemInfo : IReturn<SystemInfo> { @@ -18,18 +17,16 @@ namespace MediaBrowser.Api /// <summary> /// Class RestartApplication /// </summary> - [Route("/System/Restart", "POST")] - [Api(("Restarts the application, if needed"))] + [Route("/System/Restart", "POST", Summary = "Restarts the application, if needed")] public class RestartApplication { } - [Route("/System/Shutdown", "POST")] - [Api(("Shuts down the application"))] + [Route("/System/Shutdown", "POST", Summary = "Shuts down the application")] public class ShutdownApplication { } - + /// <summary> /// Class SystemInfoService /// </summary> diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index a805b7b55..7fa586a7d 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -17,8 +17,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetNextUpEpisodes /// </summary> - [Route("/Shows/NextUp", "GET")] - [Api(("Gets a list of next up episodes"))] + [Route("/Shows/NextUp", "GET", Summary = "Gets a list of next up episodes")] public class GetNextUpEpisodes : IReturn<ItemsResult>, IHasItemFields { /// <summary> @@ -53,8 +52,7 @@ namespace MediaBrowser.Api public string SeriesId { get; set; } } - [Route("/Shows/Upcoming", "GET")] - [Api(("Gets a list of upcoming episodes"))] + [Route("/Shows/Upcoming", "GET", Summary = "Gets a list of upcoming episodes")] public class GetUpcomingEpisodes : IReturn<ItemsResult>, IHasItemFields { /// <summary> @@ -86,14 +84,12 @@ namespace MediaBrowser.Api public string Fields { get; set; } } - [Route("/Shows/{Id}/Similar", "GET")] - [Api(Description = "Finds tv shows similar to a given one.")] + [Route("/Shows/{Id}/Similar", "GET", Summary = "Finds tv shows similar to a given one.")] public class GetSimilarShows : BaseGetSimilarItemsFromItem { } - [Route("/Shows/{Id}/Episodes", "GET")] - [Api(Description = "Gets episodes for a tv season")] + [Route("/Shows/{Id}/Episodes", "GET", Summary = "Gets episodes for a tv season")] public class GetEpisodes : IReturn<ItemsResult>, IHasItemFields { /// <summary> @@ -129,8 +125,7 @@ namespace MediaBrowser.Api public string AdjacentTo { get; set; } } - [Route("/Shows/{Id}/Seasons", "GET")] - [Api(Description = "Gets seasons for a tv series")] + [Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")] public class GetSeasons : IReturn<ItemsResult>, IHasItemFields { /// <summary> @@ -320,7 +315,7 @@ namespace MediaBrowser.Api return 0; }) - .ThenByDescending(i =>i.Item2) + .ThenByDescending(i => i.Item2) .ThenByDescending(i => i.Item1.PremiereDate ?? DateTime.MinValue) .Select(i => i.Item1); } diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 18c3bd096..2f1b16107 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -17,8 +17,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetUsers /// </summary> - [Route("/Users", "GET")] - [Api(Description = "Gets a list of users")] + [Route("/Users", "GET", Summary = "Gets a list of users")] public class GetUsers : IReturn<List<UserDto>> { [ApiMember(Name = "IsHidden", Description = "Optional filter by IsHidden=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] @@ -28,8 +27,7 @@ namespace MediaBrowser.Api public bool? IsDisabled { get; set; } } - [Route("/Users/Public", "GET")] - [Api(Description = "Gets a list of publicly visible users for display on a login screen.")] + [Route("/Users/Public", "GET", Summary = "Gets a list of publicly visible users for display on a login screen.")] public class GetPublicUsers : IReturn<List<UserDto>> { } @@ -37,8 +35,7 @@ namespace MediaBrowser.Api /// <summary> /// Class GetUser /// </summary> - [Route("/Users/{Id}", "GET")] - [Api(Description = "Gets a user by Id")] + [Route("/Users/{Id}", "GET", Summary = "Gets a user by Id")] public class GetUser : IReturn<UserDto> { /// <summary> @@ -52,8 +49,7 @@ namespace MediaBrowser.Api /// <summary> /// Class DeleteUser /// </summary> - [Route("/Users/{Id}", "DELETE")] - [Api(Description = "Deletes a user")] + [Route("/Users/{Id}", "DELETE", Summary = "Deletes a user")] public class DeleteUser : IReturnVoid { /// <summary> @@ -67,8 +63,7 @@ namespace MediaBrowser.Api /// <summary> /// Class AuthenticateUser /// </summary> - [Route("/Users/{Id}/Authenticate", "POST")] - [Api(Description = "Authenticates a user")] + [Route("/Users/{Id}/Authenticate", "POST", Summary = "Authenticates a user")] public class AuthenticateUser : IReturn<AuthenticationResult> { /// <summary> @@ -89,8 +84,7 @@ namespace MediaBrowser.Api /// <summary> /// Class AuthenticateUser /// </summary> - [Route("/Users/AuthenticateByName", "POST")] - [Api(Description = "Authenticates a user")] + [Route("/Users/AuthenticateByName", "POST", Summary = "Authenticates a user")] public class AuthenticateUserByName : IReturn<AuthenticationResult> { /// <summary> @@ -111,8 +105,7 @@ namespace MediaBrowser.Api /// <summary> /// Class UpdateUserPassword /// </summary> - [Route("/Users/{Id}/Password", "POST")] - [Api(Description = "Updates a user's password")] + [Route("/Users/{Id}/Password", "POST", Summary = "Updates a user's password")] public class UpdateUserPassword : IReturnVoid { /// <summary> @@ -143,8 +136,7 @@ namespace MediaBrowser.Api /// <summary> /// Class UpdateUser /// </summary> - [Route("/Users/{Id}", "POST")] - [Api(Description = "Updates a user")] + [Route("/Users/{Id}", "POST", Summary = "Updates a user")] public class UpdateUser : UserDto, IReturnVoid { } @@ -152,8 +144,7 @@ namespace MediaBrowser.Api /// <summary> /// Class CreateUser /// </summary> - [Route("/Users", "POST")] - [Api(Description = "Creates a user")] + [Route("/Users", "POST", Summary = "Creates a user")] public class CreateUser : UserDto, IReturn<UserDto> { } diff --git a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs index 4ff34cfa1..33d3f368b 100644 --- a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs @@ -1,11 +1,11 @@ -using System.Globalization; -using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Net; namespace MediaBrowser.Common.Net { @@ -16,6 +16,7 @@ namespace MediaBrowser.Common.Net /// <typeparam name="TStateType">The type of the T state type.</typeparam> public abstract class BasePeriodicWebSocketListener<TReturnDataType, TStateType> : IWebSocketListener, IDisposable where TStateType : class, new() + where TReturnDataType : class { /// <summary> /// The _active connections @@ -144,12 +145,15 @@ namespace MediaBrowser.Common.Net var data = await GetDataToSend(tuple.Item4).ConfigureAwait(false); - await connection.SendAsync(new WebSocketMessage<TReturnDataType> + if (data != null) { - MessageType = Name, - Data = data + await connection.SendAsync(new WebSocketMessage<TReturnDataType> + { + MessageType = Name, + Data = data - }, tuple.Item2.Token).ConfigureAwait(false); + }, tuple.Item2.Token).ConfigureAwait(false); + } tuple.Item5.Release(); } diff --git a/MediaBrowser.Controller/Dlna/CodecProfile.cs b/MediaBrowser.Controller/Dlna/CodecProfile.cs index bff374298..5621c7ef2 100644 --- a/MediaBrowser.Controller/Dlna/CodecProfile.cs +++ b/MediaBrowser.Controller/Dlna/CodecProfile.cs @@ -6,12 +6,12 @@ namespace MediaBrowser.Controller.Dlna public class CodecProfile { public CodecType Type { get; set; } - public List<ProfileCondition> Conditions { get; set; } + public ProfileCondition[] Conditions { get; set; } public string Codec { get; set; } public CodecProfile() { - Conditions = new List<ProfileCondition>(); + Conditions = new ProfileCondition[] {}; } public List<string> GetCodecs() @@ -32,6 +32,12 @@ namespace MediaBrowser.Controller.Dlna public ProfileConditionType Condition { get; set; } public ProfileConditionValue Property { get; set; } public string Value { get; set; } + public bool IsRequired { get; set; } + + public ProfileCondition() + { + IsRequired = true; + } } public enum ProfileConditionType @@ -46,11 +52,17 @@ namespace MediaBrowser.Controller.Dlna { AudioChannels, AudioBitrate, + AudioProfile, Filesize, Width, Height, + Has64BitOffsets, + VideoBitDepth, VideoBitrate, VideoFramerate, - VideoLevel + VideoLevel, + VideoPacketLength, + VideoProfile, + VideoTimestamp } } diff --git a/MediaBrowser.Controller/Dlna/ContainerProfile.cs b/MediaBrowser.Controller/Dlna/ContainerProfile.cs new file mode 100644 index 000000000..3bd3c9eaf --- /dev/null +++ b/MediaBrowser.Controller/Dlna/ContainerProfile.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Linq; + +namespace MediaBrowser.Controller.Dlna +{ + public class ContainerProfile + { + public DlnaProfileType Type { get; set; } + public ProfileCondition[] Conditions { get; set; } + public string Container { get; set; } + + public ContainerProfile() + { + Conditions = new ProfileCondition[] { }; + } + + public List<string> GetContainers() + { + return (Container ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + } + } +} diff --git a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs index 20c94ad50..461c77537 100644 --- a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs +++ b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; - + namespace MediaBrowser.Controller.Dlna { public class DeviceIdentification @@ -55,11 +54,11 @@ namespace MediaBrowser.Controller.Dlna /// Gets or sets the headers. /// </summary> /// <value>The headers.</value> - public List<HttpHeaderInfo> Headers { get; set; } + public HttpHeaderInfo[] Headers { get; set; } public DeviceIdentification() { - Headers = new List<HttpHeaderInfo>(); + Headers = new HttpHeaderInfo[] {}; } } @@ -73,6 +72,7 @@ namespace MediaBrowser.Controller.Dlna public enum HeaderMatchType { Equals = 0, - Substring = 1 + Regex = 1, + Substring = 2 } } diff --git a/MediaBrowser.Controller/Dlna/DeviceProfile.cs b/MediaBrowser.Controller/Dlna/DeviceProfile.cs index 91be73bba..f3de1bc34 100644 --- a/MediaBrowser.Controller/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Controller/Dlna/DeviceProfile.cs @@ -20,13 +20,15 @@ namespace MediaBrowser.Controller.Dlna /// </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; } + public ContainerProfile[] ContainerProfiles { get; set; } + /// <summary> /// Gets or sets the identification. /// </summary> @@ -40,6 +42,9 @@ namespace MediaBrowser.Controller.Dlna public string ModelDescription { get; set; } public string ModelNumber { get; set; } public string ModelUrl { get; set; } + public bool IgnoreTranscodeByteRangeRequests { get; set; } + public bool SupportsAlbumArtInDidl { get; set; } + /// <summary> /// Controls the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace. /// </summary> @@ -60,12 +65,16 @@ namespace MediaBrowser.Controller.Dlna public int TimelineOffsetSeconds { get; set; } + public bool RequiresPlainVideoItems { get; set; } + public bool RequiresPlainFolders { get; set; } + public DeviceProfile() { DirectPlayProfiles = new DirectPlayProfile[] { }; TranscodingProfiles = new TranscodingProfile[] { }; MediaProfiles = new MediaProfile[] { }; CodecProfiles = new CodecProfile[] { }; + ContainerProfiles = new ContainerProfile[] { }; } } } diff --git a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs index 53d32a2f8..686b31287 100644 --- a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs +++ b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs @@ -5,19 +5,15 @@ namespace MediaBrowser.Controller.Dlna { public class DirectPlayProfile { - public string[] Containers { get; set; } + public string Container { get; set; } public string AudioCodec { get; set; } public string VideoCodec { get; set; } public DlnaProfileType Type { get; set; } - public List<ProfileCondition> Conditions { get; set; } - - public DirectPlayProfile() + public List<string> GetContainers() { - Conditions = new List<ProfileCondition>(); - - Containers = new string[] { }; + return (Container ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); } public List<string> GetAudioCodecs() diff --git a/MediaBrowser.Controller/Dlna/MediaProfile.cs b/MediaBrowser.Controller/Dlna/MediaProfile.cs index 5fa41b18a..1d2613fac 100644 --- a/MediaBrowser.Controller/Dlna/MediaProfile.cs +++ b/MediaBrowser.Controller/Dlna/MediaProfile.cs @@ -13,6 +13,13 @@ namespace MediaBrowser.Controller.Dlna public string OrgPn { get; set; } public string MimeType { get; set; } + public ProfileCondition[] Conditions { get; set; } + + public MediaProfile() + { + Conditions = new ProfileCondition[] {}; + } + public List<string> GetAudioCodecs() { return (AudioCodec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); diff --git a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs index 530a44b8c..1ce2adb1b 100644 --- a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs +++ b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; - + namespace MediaBrowser.Controller.Dlna { public class TranscodingProfile @@ -11,12 +10,18 @@ namespace MediaBrowser.Controller.Dlna public string VideoCodec { get; set; } public string AudioCodec { get; set; } - public List<TranscodingSetting> Settings { get; set; } + public bool EstimateContentLength { get; set; } + + public TranscodeSeekInfo TranscodeSeekInfo { get; set; } + + public TranscodingSetting[] Settings { get; set; } public TranscodingProfile() { - Settings = new List<TranscodingSetting>(); + Settings = new TranscodingSetting[] { }; } + + public bool EnableMpegtsM2TsMode { get; set; } } public class TranscodingSetting @@ -27,6 +32,14 @@ namespace MediaBrowser.Controller.Dlna public enum TranscodingSettingType { - Profile + VideoLevel = 0, + VideoProfile = 1, + MaxAudioChannels = 2 + } + + public enum TranscodeSeekInfo + { + Auto = 0, + Bytes = 1 } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index b51824bdb..5e6297d06 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -79,6 +79,7 @@ <Compile Include="Collections\CollectionCreationOptions.cs" /> <Compile Include="Collections\ICollectionManager.cs" /> <Compile Include="Dlna\CodecProfile.cs" /> + <Compile Include="Dlna\ContainerProfile.cs" /> <Compile Include="Dlna\DeviceIdentification.cs" /> <Compile Include="Dlna\DirectPlayProfile.cs" /> <Compile Include="Dlna\IDlnaManager.cs" /> diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index be7295e12..c6da865cd 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Dlna; +using MediaBrowser.Dlna.Profiles; using MediaBrowser.Model.Serialization; using System.Collections.Generic; using System.Linq; @@ -13,849 +14,42 @@ namespace MediaBrowser.Dlna private IApplicationPaths _appPaths; private readonly IXmlSerializer _xmlSerializer; private readonly IFileSystem _fileSystem; + private readonly IJsonSerializer _jsonSerializer; - public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem) + public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem, IJsonSerializer jsonSerializer) { _xmlSerializer = xmlSerializer; _fileSystem = fileSystem; + _jsonSerializer = jsonSerializer; - //GetProfiles(); + GetProfiles(); } public IEnumerable<DeviceProfile> GetProfiles() { - var list = new List<DeviceProfile>(); - - list.Add(new DeviceProfile - { - Name = "Samsung TV (B Series)", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - FriendlyName = "^TV$", - ModelNumber = @"1\.0", - ModelName = "Samsung DTV DMR" - }, - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio, - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - Type = DlnaProfileType.Audio, - }, - new DirectPlayProfile - { - Containers = new[]{"mkv"}, - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"avi"}, - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"mp4"}, - Type = DlnaProfileType.Video - } - }, - - MediaProfiles = new[] - { - new MediaProfile - { - Container ="avi", - MimeType = "video/x-msvideo", - Type = DlnaProfileType.Video - }, - - new MediaProfile - { - Container ="mkv", - MimeType = "video/x-mkv", - Type = DlnaProfileType.Video - } - } - }); - - list.Add(new DeviceProfile - { - Name = "Samsung TV (E/F-series)", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - FriendlyName = @"(^\[TV\][A-Z]{2}\d{2}(E|F)[A-Z]?\d{3,4}.*)|^\[TV\] Samsung|(^\[TV\]Samsung [A-Z]{2}\d{2}(E|F)[A-Z]?\d{3,4}.*)", - ModelNumber = @"(1\.0)|(AllShare1\.0)" - }, - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"mkv"}, - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"avi"}, - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"mp4"}, - Type = DlnaProfileType.Video - } - }, - - MediaProfiles = new[] - { - new MediaProfile - { - Container ="avi", - MimeType = "video/x-msvideo", - Type = DlnaProfileType.Video - }, - - new MediaProfile - { - Container ="mkv", - MimeType = "video/x-mkv", - Type = DlnaProfileType.Video - } - } - }); - - list.Add(new DeviceProfile - { - Name = "Samsung TV (C/D-series)", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - FriendlyName = @"(^TV-\d{2}C\d{3}.*)|(^\[TV\][A-Z]{2}\d{2}(D)[A-Z]?\d{3,4}.*)|^\[TV\] Samsung", - ModelNumber = @"(1\.0)|(AllShare1\.0)" - }, - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"mkv"}, - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"avi"}, - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"mp4"}, - Type = DlnaProfileType.Video - } - }, - - MediaProfiles = new[] - { - new MediaProfile - { - Container ="avi", - MimeType = "video/x-msvideo", - Type = DlnaProfileType.Video - }, - - new MediaProfile - { - Container ="mkv", - MimeType = "video/x-mkv", - Type = DlnaProfileType.Video - } - } - }); - - list.Add(new DeviceProfile - { - Name = "Xbox 360", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - ModelName = "Xbox 360" - }, - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"avi"}, - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"mp4"}, - Type = DlnaProfileType.Video - } - }, - - MediaProfiles = new[] - { - new MediaProfile - { - Container ="avi", - MimeType = "video/avi", - Type = DlnaProfileType.Video - } - } - }); - - list.Add(new DeviceProfile - { - Name = "Xbox One", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - ModelName = "Xbox One", - FriendlyName = "Xbox-SystemOS" - }, - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"avi"}, - Type = DlnaProfileType.Video - } - }, - - MediaProfiles = new[] - { - new MediaProfile - { - Container ="avi", - MimeType = "video/x-msvideo", - Type = DlnaProfileType.Video - } - } - }); - - list.Add(new DeviceProfile - { - Name = "Sony Bravia (2012)", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - FriendlyName = @"BRAVIA KDL-\d{2}[A-Z]X\d5(\d|G).*" - }, - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"avi"}, - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"asf"}, - Type = DlnaProfileType.Audio - } - }, - - MediaProfiles = new[] - { - new MediaProfile - { - Container ="avi", - MimeType = "video/avi", - Type = DlnaProfileType.Video - }, - - new MediaProfile - { - Container ="asf", - MimeType = "video/x-ms-wmv", - Type = DlnaProfileType.Audio - } - } - }); - - list.Add(new DeviceProfile - { - Name = "Sony Bravia (2013)", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - FriendlyName = @"BRAVIA (KDL-\d{2}W[689]\d{2}A.*)|(KD-\d{2}X9\d{3}A.*)" - }, - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"wma"}, - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"avi"}, - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"mp4"}, - Type = DlnaProfileType.Video - } - }, - - MediaProfiles = new[] - { - new MediaProfile - { - Container ="avi", - MimeType = "video/avi", - Type = DlnaProfileType.Video - }, - - new MediaProfile - { - Container ="mp4", - MimeType = "video/mp4", - Type = DlnaProfileType.Video - }, - - new MediaProfile - { - Container ="ts", - MimeType = "video/mpeg", - Type = DlnaProfileType.Video - }, - - new MediaProfile - { - Container ="wma", - MimeType = "video/x-ms-wma", - Type = DlnaProfileType.Audio - } - } - }); - - list.Add(new DeviceProfile - { - //Panasonic Viera (2011|2012) Without AVI Support - Name = "Panasonic Viera E/S/ST/VT (2011)", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - FriendlyName = @"(VIERA (E|S)T?(3|5)0?.*)|(VIERA VT30.*)", - Manufacturer = "Panasonic" - }, - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"mkv"}, - Type = DlnaProfileType.Video - } - } - }); - - list.Add(new DeviceProfile - { - //Panasonic Viera (2011|2012) With AVI Support - Name = "Panasonic Viera G/GT/DT/UT/VT (2011/2012)", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - FriendlyName = @"(VIERA (G|D|U)T?(3|5)0?.*)|(VIERA VT50.*)", - Manufacturer = "Panasonic" - }, - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"mkv"}, - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"avi"}, - Type = DlnaProfileType.Video - } - }, - - MediaProfiles = new[] - { - new MediaProfile - { - Container ="avi", - MimeType = "video/divx", - Type = DlnaProfileType.Video - } - } - }); - - list.Add(new DeviceProfile - { - Name = "Philips (2010-)", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - FriendlyName = ".*PHILIPS.*", - ModelName = "WD TV HD Live" - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3", "wma"}, - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Containers = new[]{"avi"}, - Type = DlnaProfileType.Video - }, - - new DirectPlayProfile - { - Containers = new[]{"mkv"}, - Type = DlnaProfileType.Video - } - }, - - MediaProfiles = new[] - { - new MediaProfile - { - Container ="avi", - MimeType = "video/avi", - Type = DlnaProfileType.Video - }, - - new MediaProfile - { - Container ="mkv", - MimeType = "video/x-matroska", - Type = DlnaProfileType.Video - } - } - }); - - list.Add(new DeviceProfile - { - Name = "WDTV Live", - ClientType = "DLNA", - - TimelineOffsetSeconds = 5, - - Identification = new DeviceIdentification - { - ModelName = "WD TV HD Live", - - Headers = new List<HttpHeaderInfo> - { - new HttpHeaderInfo{ Name="User-Agent", Value="alphanetworks", Match= HeaderMatchType.Substring}, - new HttpHeaderInfo{ Name="User-Agent", Value="ALPHA Networks", Match= HeaderMatchType.Substring} - } - }, - - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio, - AudioCodec = "mp3" - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video, - VideoCodec = "h264", - AudioCodec = "aac" - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"avi"}, - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1", - AudioCodec = "ac3,dca,mp2,mp3,pcm" - }, - - new DirectPlayProfile - { - Containers = new[]{"mpeg"}, - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video", - AudioCodec = "ac3,dca,mp2,mp3,pcm" - }, - - new DirectPlayProfile - { - Containers = new[]{"mkv"}, - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1", - AudioCodec = "ac3,dca,aac,mp2,mp3,pcm" - }, - - new DirectPlayProfile - { - Containers = new[]{"ts"}, - Type = DlnaProfileType.Video, - VideoCodec = "mpeg1video,mpeg2video,h264,vc1", - AudioCodec = "ac3,dca,mp2,mp3" - }, - - new DirectPlayProfile - { - Containers = new[]{"mp4", "mov"}, - Type = DlnaProfileType.Video, - VideoCodec = "h264,mpeg4", - AudioCodec = "ac3,aac,mp2,mp3" - }, - - new DirectPlayProfile - { - Containers = new[]{"asf"}, - Type = DlnaProfileType.Video, - VideoCodec = "vc1", - AudioCodec = "wmav2,wmapro" - }, - - new DirectPlayProfile - { - Containers = new[]{"asf"}, - Type = DlnaProfileType.Video, - VideoCodec = "mpeg2video", - AudioCodec = "mp2,ac3" - }, - - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - AudioCodec = "mp2,mp3", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Containers = new[]{"mp4"}, - AudioCodec = "mp4", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Containers = new[]{"flac"}, - AudioCodec = "flac", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Containers = new[]{"asf"}, - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Containers = new[]{"ogg"}, - AudioCodec = "vorbis", - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Type = DlnaProfileType.Photo, - - Containers = new[]{"jpeg", "png", "gif", "bmp", "tiff"}, - - Conditions = new List<ProfileCondition> - { - new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.Width, Value = "1920"}, - new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.Height, Value = "1080"} - } - } - }, - - MediaProfiles = new[] - { - new MediaProfile - { - Container ="ts", - OrgPn = "MPEG_TS_SD_NA", - Type = DlnaProfileType.Video - } - }, - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.VideoCodec, - Codec= "h264", - - Conditions = new List<ProfileCondition> - { - new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.Width, Value = "1920"}, - new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.Height, Value = "1080"}, - new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.VideoLevel, Value = "41"} - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudioCodec, - Codec= "aac", - - Conditions = new List<ProfileCondition> - { - new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.AudioChannels, Value = "2"} - } - } - } - }); - - list.Add(new DeviceProfile - { - // Linksys DMA2100us does not need any transcoding of the formats we support statically - Name = "Linksys DMA2100", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - ModelName = "DMA2100us" - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3", "flac", "m4a", "wma"}, - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Containers = new[]{"avi", "mp4", "mkv", "ts"}, - Type = DlnaProfileType.Video - } - } - }); - - list.Add(new DeviceProfile - { - Name = "Denon AVR", - ClientType = "DLNA", - - Identification = new DeviceIdentification - { - FriendlyName = @"Denon:\[AVR:.*", - Manufacturer = "Denon" - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3", "flac", "m4a", "wma"}, - Type = DlnaProfileType.Audio - }, - } - }); + var list = new List<DeviceProfile> + { + new SamsungSmartTvProfile(), + new Xbox360Profile(), + new XboxOneProfile(), + new SonyPs3Profile(), + new SonyBravia2010Profile(), + new SonyBravia2011Profile(), + new SonyBravia2012Profile(), + new SonyBravia2013Profile(), + new SonyBlurayPlayer2013Profile(), + new SonyBlurayPlayerProfile(), + new PanasonicVieraProfile(), + new WdtvLiveProfile(), + new DenonAvrProfile(), + new LinksysDMA2100Profile(), + new LgTvProfile() + }; foreach (var item in list) { - //_xmlSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name)); + //_xmlSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".xml"); + //_jsonSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name) + ".json"); } return list; @@ -863,37 +57,7 @@ namespace MediaBrowser.Dlna public DeviceProfile GetDefaultProfile() { - return new DeviceProfile - { - TranscodingProfiles = new[] - { - new TranscodingProfile - { - Container = "mp3", - Type = DlnaProfileType.Audio - }, - new TranscodingProfile - { - Container = "ts", - Type = DlnaProfileType.Video - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"mp3", "wma"}, - Type = DlnaProfileType.Audio - }, - - new DirectPlayProfile - { - Containers = new[]{"avi", "mp4"}, - Type = DlnaProfileType.Video - } - } - }; + return new DefaultProfile(); } public DeviceProfile GetProfile(DeviceIdentification deviceInfo) @@ -906,55 +70,55 @@ namespace MediaBrowser.Dlna { if (!string.IsNullOrWhiteSpace(profileInfo.DeviceDescription)) { - if (!Regex.IsMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription)) + if (deviceInfo.DeviceDescription == null || !Regex.IsMatch(deviceInfo.DeviceDescription, profileInfo.DeviceDescription)) return false; } if (!string.IsNullOrWhiteSpace(profileInfo.FriendlyName)) { - if (!Regex.IsMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName)) + if (deviceInfo.FriendlyName == null || !Regex.IsMatch(deviceInfo.FriendlyName, profileInfo.FriendlyName)) return false; } if (!string.IsNullOrWhiteSpace(profileInfo.Manufacturer)) { - if (!Regex.IsMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer)) + if (deviceInfo.Manufacturer == null || !Regex.IsMatch(deviceInfo.Manufacturer, profileInfo.Manufacturer)) return false; } if (!string.IsNullOrWhiteSpace(profileInfo.ManufacturerUrl)) { - if (!Regex.IsMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl)) + if (deviceInfo.ManufacturerUrl == null || !Regex.IsMatch(deviceInfo.ManufacturerUrl, profileInfo.ManufacturerUrl)) return false; } if (!string.IsNullOrWhiteSpace(profileInfo.ModelDescription)) { - if (!Regex.IsMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription)) + if (deviceInfo.ModelDescription == null || !Regex.IsMatch(deviceInfo.ModelDescription, profileInfo.ModelDescription)) return false; } if (!string.IsNullOrWhiteSpace(profileInfo.ModelName)) { - if (!Regex.IsMatch(deviceInfo.ModelName, profileInfo.ModelName)) + if (deviceInfo.ModelName == null || !Regex.IsMatch(deviceInfo.ModelName, profileInfo.ModelName)) return false; } if (!string.IsNullOrWhiteSpace(profileInfo.ModelNumber)) { - if (!Regex.IsMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber)) + if (deviceInfo.ModelNumber == null || !Regex.IsMatch(deviceInfo.ModelNumber, profileInfo.ModelNumber)) return false; } if (!string.IsNullOrWhiteSpace(profileInfo.ModelUrl)) { - if (!Regex.IsMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl)) + if (deviceInfo.ModelUrl == null || !Regex.IsMatch(deviceInfo.ModelUrl, profileInfo.ModelUrl)) return false; } if (!string.IsNullOrWhiteSpace(profileInfo.SerialNumber)) { - if (!Regex.IsMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber)) + if (deviceInfo.SerialNumber == null || !Regex.IsMatch(deviceInfo.SerialNumber, profileInfo.SerialNumber)) return false; } diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index 800fb1b23..bea281b61 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -81,7 +81,28 @@ <Compile Include="PlayTo\uIcon.cs" /> <Compile Include="PlayTo\uParser.cs" /> <Compile Include="PlayTo\uPnpNamespaces.cs" /> + <Compile Include="Profiles\DefaultProfile.cs" /> + <Compile Include="Profiles\DenonAvrProfile.cs" /> + <Compile Include="Profiles\LgTvProfile.cs" /> + <Compile Include="Profiles\LinksysDMA2100Profile.cs" /> + <Compile Include="Profiles\PanasonicVieraProfile.cs" /> + <Compile Include="Profiles\SamsungSmartTvProfile.cs" /> + <Compile Include="Profiles\SonyBlurayPlayer2013Profile.cs" /> + <Compile Include="Profiles\SonyBlurayPlayerProfile.cs" /> + <Compile Include="Profiles\SonyBravia2010Profile.cs" /> + <Compile Include="Profiles\SonyBravia2011Profile.cs" /> + <Compile Include="Profiles\SonyBravia2012Profile.cs" /> + <Compile Include="Profiles\SonyBravia2013Profile.cs" /> + <Compile Include="Profiles\SonyPs3Profile.cs" /> + <Compile Include="Profiles\WdtvLiveProfile.cs" /> + <Compile Include="Profiles\Xbox360Profile.cs" /> + <Compile Include="Profiles\XboxOneProfile.cs" /> <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> <ItemGroup> <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj"> @@ -97,9 +118,7 @@ <Name>MediaBrowser.Model</Name> </ProjectReference> </ItemGroup> - <ItemGroup> - <Folder Include="Server\" /> - </ItemGroup> + <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/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs index 5952a213a..2b43c019c 100644 --- a/MediaBrowser.Dlna/PlayTo/Device.cs +++ b/MediaBrowser.Dlna/PlayTo/Device.cs @@ -681,7 +681,10 @@ 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; + deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port); diff --git a/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs b/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs index 4b40daf70..c57e95c19 100644 --- a/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs +++ b/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs @@ -34,6 +34,8 @@ namespace MediaBrowser.Dlna.PlayTo public string ModelNumber { get; set; } + public string ModelUrl { get; set; } + public string Manufacturer { get; set; } public string ManufacturerUrl { get; set; } @@ -72,7 +74,8 @@ namespace MediaBrowser.Dlna.PlayTo ModelName = ModelName, ModelNumber = ModelNumber, FriendlyName = Name, - ManufacturerUrl = ManufacturerUrl + ManufacturerUrl = ManufacturerUrl, + ModelUrl = ModelUrl }; } } diff --git a/MediaBrowser.Dlna/PlayTo/DlnaController.cs b/MediaBrowser.Dlna/PlayTo/DlnaController.cs index e94663802..ecda07f0b 100644 --- a/MediaBrowser.Dlna/PlayTo/DlnaController.cs +++ b/MediaBrowser.Dlna/PlayTo/DlnaController.cs @@ -270,7 +270,7 @@ namespace MediaBrowser.Dlna.PlayTo playlistItem.StartPositionTicks = newItem.StartPositionTicks; playlistItem.StreamUrl = newItem.StreamUrl; playlistItem.Didl = newItem.Didl; - return _device.SetAvTransport(playlistItem.StreamUrl, playlistItem.DlnaHeaders, playlistItem.Didl); + return _device.SetAvTransport(playlistItem.StreamUrl, GetDlnaHeaders(playlistItem), playlistItem.Didl); } return _device.Seek(TimeSpan.FromTicks(command.SeekPositionTicks ?? 0)); @@ -391,16 +391,23 @@ namespace MediaBrowser.Dlna.PlayTo private PlaylistItem CreatePlaylistItem(BaseItem item, long startPostionTicks, string serverAddress) { - var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = item.Id }).ToList(); + var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery + { + ItemId = item.Id + + }).ToList(); var deviceInfo = _device.Properties; - var playlistItem = GetPlaylistItem(item, _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification())); + var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()); + + var playlistItem = GetPlaylistItem(item, streams, profile); playlistItem.StartPositionTicks = startPostionTicks; + playlistItem.DeviceProfileName = profile.Name; if (playlistItem.MediaType == DlnaProfileType.Audio) { - playlistItem.StreamUrl = StreamHelper.GetAudioUrl(playlistItem, serverAddress); + playlistItem.StreamUrl = StreamHelper.GetAudioUrl(deviceInfo, playlistItem, streams, serverAddress); } else { @@ -410,32 +417,92 @@ namespace MediaBrowser.Dlna.PlayTo var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams); playlistItem.Didl = didl; - var header = StreamHelper.GetDlnaHeaders(playlistItem); - playlistItem.DlnaHeaders = header; return playlistItem; } - private PlaylistItem GetPlaylistItem(BaseItem item, DeviceProfile profile) + private string GetDlnaHeaders(PlaylistItem item) + { + var orgOp = item.Transcode ? ";DLNA.ORG_OP=00" : ";DLNA.ORG_OP=01"; + + var orgCi = item.Transcode ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1"; + + const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000"; + + string contentFeatures; + + var container = item.Container.TrimStart('.'); + + if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=MP3"; + } + else if (string.Equals(container, "wma", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=WMABASE"; + } + else if (string.Equals(container, "wmw", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=WMVMED_BASE"; + } + else if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=WMVMED_BASE"; + } + else if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=AVI"; + } + else if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=MATROSKA"; + } + else if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC"; + } + else if (string.Equals(container, "mpeg", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; + } + else if (string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; + } + else if (item.MediaType == DlnaProfileType.Video) + { + // Default to AVI for video + contentFeatures = "DLNA.ORG_PN=AVI"; + } + else + { + // Default to MP3 for audio + contentFeatures = "DLNA.ORG_PN=MP3"; + } + + return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + } + + private PlaylistItem GetPlaylistItem(BaseItem item, List<MediaStream> mediaStreams, DeviceProfile profile) { var video = item as Video; if (video != null) { - return new PlaylistItemFactory(_itemRepository).Create(video, profile); + return new PlaylistItemFactory().Create(video, mediaStreams, profile); } var audio = item as Audio; if (audio != null) { - return new PlaylistItemFactory(_itemRepository).Create(audio, profile); + return new PlaylistItemFactory().Create(audio, mediaStreams, profile); } var photo = item as Photo; if (photo != null) { - return new PlaylistItemFactory(_itemRepository).Create(photo, profile); + return new PlaylistItemFactory().Create(photo, profile); } throw new ArgumentException("Unrecognized item type."); @@ -482,11 +549,18 @@ namespace MediaBrowser.Dlna.PlayTo await _device.SetStop(); return true; } + nextTrack.PlayState = 1; - _logger.Debug("{0} - SetAvTransport Uri: {1} DlnaHeaders: {2}", _device.Properties.Name, nextTrack.StreamUrl, nextTrack.DlnaHeaders); - await _device.SetAvTransport(nextTrack.StreamUrl, nextTrack.DlnaHeaders, nextTrack.Didl); + + var dlnaheaders = GetDlnaHeaders(nextTrack); + + _logger.Debug("{0} - SetAvTransport Uri: {1} DlnaHeaders: {2}", _device.Properties.Name, nextTrack.StreamUrl, dlnaheaders); + + await _device.SetAvTransport(nextTrack.StreamUrl, dlnaheaders, nextTrack.Didl); + if (nextTrack.StartPositionTicks > 0 && !nextTrack.Transcode) await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks)); + return true; } @@ -508,7 +582,7 @@ namespace MediaBrowser.Dlna.PlayTo return Task.FromResult(false); prevTrack.PlayState = 1; - return _device.SetAvTransport(prevTrack.StreamUrl, prevTrack.DlnaHeaders, prevTrack.Didl); + return _device.SetAvTransport(prevTrack.StreamUrl, GetDlnaHeaders(prevTrack), prevTrack.Didl); } #endregion diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs index d02da303b..ca76116fe 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs @@ -7,6 +7,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Session; using System; using System.Collections.Concurrent; using System.Linq; @@ -16,7 +17,6 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Session; namespace MediaBrowser.Dlna.PlayTo { @@ -54,10 +54,8 @@ namespace MediaBrowser.Dlna.PlayTo _config = config; } - public async void Start() + public void Start() { - _logger.Log(LogSeverity.Info, "PlayTo-Manager starting"); - _locations = new ConcurrentDictionary<string, DateTime>(); foreach (var network in NetworkInterface.GetAllNetworkInterfaces()) @@ -73,7 +71,7 @@ namespace MediaBrowser.Dlna.PlayTo IPAddress localIp = null; - foreach (UnicastIPAddressInformation ipInfo in network.GetIPProperties().UnicastAddresses) + foreach (var ipInfo in network.GetIPProperties().UnicastAddresses) { if (ipInfo.Address.AddressFamily == AddressFamily.InterNetwork) { @@ -95,8 +93,6 @@ namespace MediaBrowser.Dlna.PlayTo { _logger.ErrorException("Failed to Initilize Socket", e); } - - await Task.Delay(100).ConfigureAwait(false); } } @@ -139,7 +135,7 @@ namespace MediaBrowser.Dlna.PlayTo _logger.Info("SSDP listener - Task completed"); } - catch (OperationCanceledException c) + catch (OperationCanceledException) { } catch (Exception e) @@ -158,7 +154,7 @@ namespace MediaBrowser.Dlna.PlayTo { await CreateController(uri).ConfigureAwait(false); } - catch (OperationCanceledException c) + catch (OperationCanceledException) { } catch (Exception ex) @@ -180,10 +176,12 @@ namespace MediaBrowser.Dlna.PlayTo { socket.SendTo(request, new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900)); - await Task.Delay(10000).ConfigureAwait(false); + var delay = _config.Configuration.DlnaOptions.ClientDiscoveryIntervalSeconds * 1000; + + await Task.Delay(delay).ConfigureAwait(false); } } - catch (OperationCanceledException c) + catch (OperationCanceledException) { } catch (Exception ex) diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs index 1304f61b1..3992fbfbf 100644 --- a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs +++ b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Dlna; +using System.Collections.Generic; namespace MediaBrowser.Dlna.PlayTo { @@ -14,16 +15,29 @@ namespace MediaBrowser.Dlna.PlayTo public string Container { get; set; } - public string MimeType { get; set; } - public int PlayState { get; set; } public string StreamUrl { get; set; } - public string DlnaHeaders { get; set; } - public string Didl { get; set; } public long StartPositionTicks { get; set; } + + public string VideoCodec { get; set; } + + public string AudioCodec { get; set; } + + public List<TranscodingSetting> TranscodingSettings { get; set; } + + public int? AudioStreamIndex { get; set; } + + public int? SubtitleStreamIndex { get; set; } + + public string DeviceProfileName { get; set; } + + public PlaylistItem() + { + TranscodingSettings = new List<TranscodingSetting>(); + } } }
\ No newline at end of file diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs index 6817c4eaa..e4c49a224 100644 --- a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs +++ b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs @@ -1,9 +1,9 @@ using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; @@ -12,15 +12,9 @@ namespace MediaBrowser.Dlna.PlayTo { public class PlaylistItemFactory { - private readonly IItemRepository _itemRepo; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - public PlaylistItemFactory(IItemRepository itemRepo) - { - _itemRepo = itemRepo; - } - - public PlaylistItem Create(Audio item, DeviceProfile profile) + public PlaylistItem Create(Audio item, List<MediaStream> mediaStreams, DeviceProfile profile) { var playlistItem = new PlaylistItem { @@ -28,23 +22,21 @@ namespace MediaBrowser.Dlna.PlayTo MediaType = DlnaProfileType.Audio }; - var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery - { - ItemId = item.Id, - Type = MediaStreamType.Audio - }); - var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); - var directPlay = profile.DirectPlayProfiles - .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream)); - - if (directPlay != null) + if (profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec) + .All(i => IsCodecProfileSupported(i, item.Path, null, audioStream))) { - playlistItem.Transcode = false; - playlistItem.Container = Path.GetExtension(item.Path); + var directPlay = profile.DirectPlayProfiles + .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream)); - return playlistItem; + if (directPlay != null) + { + playlistItem.Transcode = false; + playlistItem.Container = Path.GetExtension(item.Path); + + return playlistItem; + } } var transcodingProfile = profile.TranscodingProfiles @@ -53,11 +45,10 @@ namespace MediaBrowser.Dlna.PlayTo if (transcodingProfile != null) { playlistItem.Transcode = true; - + playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList(); playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.'); + playlistItem.AudioCodec = transcodingProfile.AudioCodec; } - - AttachMediaProfile(playlistItem, profile); return playlistItem; } @@ -87,16 +78,14 @@ namespace MediaBrowser.Dlna.PlayTo if (transcodingProfile != null) { playlistItem.Transcode = true; - + playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList(); playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.'); } - - AttachMediaProfile(playlistItem, profile); return playlistItem; } - public PlaylistItem Create(Video item, DeviceProfile profile) + public PlaylistItem Create(Video item, List<MediaStream> mediaStreams, DeviceProfile profile) { var playlistItem = new PlaylistItem { @@ -104,24 +93,22 @@ namespace MediaBrowser.Dlna.PlayTo MediaType = DlnaProfileType.Video }; - var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery - { - ItemId = item.Id - - }).ToList(); - var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); - var directPlay = profile.DirectPlayProfiles - .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream)); - - if (directPlay != null) + if (profile.CodecProfiles.Where(i => i.Type == CodecType.VideoCodec || i.Type == CodecType.VideoAudioCodec) + .All(i => IsCodecProfileSupported(i, item.Path, videoStream, audioStream))) { - playlistItem.Transcode = false; - playlistItem.Container = Path.GetExtension(item.Path); + var directPlay = profile.DirectPlayProfiles + .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream)); - return playlistItem; + if (directPlay != null) + { + playlistItem.Transcode = false; + playlistItem.Container = Path.GetExtension(item.Path); + + return playlistItem; + } } var transcodingProfile = profile.TranscodingProfiles @@ -130,63 +117,29 @@ namespace MediaBrowser.Dlna.PlayTo if (transcodingProfile != null) { playlistItem.Transcode = true; + playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList(); playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.'); + playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',').FirstOrDefault(); + playlistItem.VideoCodec = transcodingProfile.VideoCodec; } - AttachMediaProfile(playlistItem, profile); - return playlistItem; } - private void AttachMediaProfile(PlaylistItem item, DeviceProfile profile) - { - var mediaProfile = GetMediaProfile(item, profile); - - if (mediaProfile != null) - { - item.MimeType = (mediaProfile.MimeType ?? string.Empty).Split('/').LastOrDefault(); - - // TODO: Org_pn? - } - } - - private MediaProfile GetMediaProfile(PlaylistItem item, DeviceProfile profile) - { - return profile.MediaProfiles.FirstOrDefault(i => - { - if (i.Type == item.MediaType) - { - if (string.Equals(item.Container.TrimStart('.'), i.Container.TrimStart('.'), StringComparison.OrdinalIgnoreCase)) - { - // TODO: Enforce codecs - return true; - } - } - - return false; - }); - } - private bool IsSupported(DirectPlayProfile profile, Photo item) { var mediaPath = item.Path; - if (profile.Containers.Length > 0) + if (profile.Container.Length > 0) { // Check container type var mediaContainer = Path.GetExtension(mediaPath); - if (!profile.Containers.Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase))) + if (!profile.GetContainers().Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase))) { return false; } } - // Check additional conditions - if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, null, null))) - { - return false; - } - return true; } @@ -194,22 +147,16 @@ namespace MediaBrowser.Dlna.PlayTo { var mediaPath = item.Path; - if (profile.Containers.Length > 0) + if (profile.Container.Length > 0) { // Check container type var mediaContainer = Path.GetExtension(mediaPath); - if (!profile.Containers.Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase))) + if (!profile.GetContainers().Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase))) { return false; } } - // Check additional conditions - if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, null, audioStream))) - { - return false; - } - return true; } @@ -222,11 +169,11 @@ namespace MediaBrowser.Dlna.PlayTo var mediaPath = item.Path; - if (profile.Containers.Length > 0) + if (profile.Container.Length > 0) { // Check container type var mediaContainer = Path.GetExtension(mediaPath); - if (!profile.Containers.Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase))) + if (!profile.GetContainers().Any(i => string.Equals("." + i.TrimStart('.'), mediaContainer, StringComparison.OrdinalIgnoreCase))) { return false; } @@ -254,12 +201,6 @@ namespace MediaBrowser.Dlna.PlayTo } } - // Check additional conditions - if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream))) - { - return false; - } - return true; } @@ -281,6 +222,24 @@ namespace MediaBrowser.Dlna.PlayTo return true; } + private bool IsCodecProfileSupported(CodecProfile profile, string mediaPath, MediaStream videoStream, MediaStream audioStream) + { + var codecs = profile.GetCodecs(); + var stream = profile.Type == CodecType.VideoCodec ? videoStream : audioStream; + var existingCodec = (stream == null ? null : stream.Codec) ?? string.Empty; + + if (codecs.Count == 0 || codecs.Contains(existingCodec, StringComparer.OrdinalIgnoreCase)) + { + // Check additional conditions + if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream))) + { + return false; + } + } + + return true; + } + /// <summary> /// Determines whether [is condition satisfied] [the specified condition]. /// </summary> @@ -292,30 +251,75 @@ namespace MediaBrowser.Dlna.PlayTo /// <exception cref="System.InvalidOperationException">Unexpected ProfileConditionType</exception> private bool IsConditionSatisfied(ProfileCondition condition, string mediaPath, MediaStream videoStream, MediaStream audioStream) { - var actualValue = GetConditionValue(condition, mediaPath, videoStream, audioStream); + if (condition.Property == ProfileConditionValue.Has64BitOffsets) + { + // TODO: Determine how to evaluate this + } - if (actualValue.HasValue) + if (condition.Property == ProfileConditionValue.VideoProfile) { - long expected; - if (long.TryParse(condition.Value, NumberStyles.Any, _usCulture, out expected)) + var profile = videoStream == null ? null : videoStream.Profile; + + if (!string.IsNullOrWhiteSpace(profile)) { switch (condition.Condition) { case ProfileConditionType.Equals: - return actualValue.Value == expected; - case ProfileConditionType.GreaterThanEqual: - return actualValue.Value >= expected; - case ProfileConditionType.LessThanEqual: - return actualValue.Value <= expected; + return string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase); case ProfileConditionType.NotEquals: - return actualValue.Value != expected; + return !string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase); default: throw new InvalidOperationException("Unexpected ProfileConditionType"); } } } - return false; + else if (condition.Property == ProfileConditionValue.AudioProfile) + { + var profile = audioStream == null ? null : audioStream.Profile; + + if (!string.IsNullOrWhiteSpace(profile)) + { + switch (condition.Condition) + { + case ProfileConditionType.Equals: + return string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase); + case ProfileConditionType.NotEquals: + return !string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase); + default: + throw new InvalidOperationException("Unexpected ProfileConditionType"); + } + } + } + + else + { + var actualValue = GetConditionValue(condition, mediaPath, videoStream, audioStream); + + if (actualValue.HasValue) + { + long expected; + if (long.TryParse(condition.Value, NumberStyles.Any, _usCulture, out expected)) + { + switch (condition.Condition) + { + case ProfileConditionType.Equals: + return actualValue.Value == expected; + case ProfileConditionType.GreaterThanEqual: + return actualValue.Value >= expected; + case ProfileConditionType.LessThanEqual: + return actualValue.Value <= expected; + case ProfileConditionType.NotEquals: + return actualValue.Value != expected; + default: + throw new InvalidOperationException("Unexpected ProfileConditionType"); + } + } + } + } + + // Value doesn't exist in metadata. Fail it if required. + return !condition.IsRequired; } /// <summary> @@ -347,6 +351,12 @@ 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 7a4928e5c..f540a8004 100644 --- a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs +++ b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs @@ -49,7 +49,7 @@ namespace MediaBrowser.Dlna.PlayTo { Url = url.ToString(), UserAgent = USERAGENT, - LogRequest = _config.Configuration.DlnaOptions.EnablePlayToDebugLogging + LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging }; options.RequestHeaders["HOST"] = ip + ":" + port; @@ -88,7 +88,7 @@ namespace MediaBrowser.Dlna.PlayTo { Url = url.ToString(), UserAgent = USERAGENT, - LogRequest = _config.Configuration.DlnaOptions.EnablePlayToDebugLogging + LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging }; options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName; @@ -112,7 +112,7 @@ namespace MediaBrowser.Dlna.PlayTo { Url = url.ToString(), UserAgent = USERAGENT, - LogRequest = _config.Configuration.DlnaOptions.EnablePlayToDebugLogging + LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging }; options.RequestHeaders["SOAPAction"] = soapAction; diff --git a/MediaBrowser.Dlna/PlayTo/StreamHelper.cs b/MediaBrowser.Dlna/PlayTo/StreamHelper.cs index cb2b72a03..6cd66c16a 100644 --- a/MediaBrowser.Dlna/PlayTo/StreamHelper.cs +++ b/MediaBrowser.Dlna/PlayTo/StreamHelper.cs @@ -1,6 +1,5 @@ -using MediaBrowser.Model.Dto; +using MediaBrowser.Controller.Dlna; using MediaBrowser.Model.Entities; -using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -10,90 +9,20 @@ namespace MediaBrowser.Dlna.PlayTo class StreamHelper { /// <summary> - /// Gets the dlna headers. - /// </summary> - /// <param name="item">The item.</param> - /// <returns></returns> - internal static string GetDlnaHeaders(PlaylistItem item) - { - var orgOp = item.Transcode ? ";DLNA.ORG_OP=00" : ";DLNA.ORG_OP=01"; - - var orgCi = item.Transcode ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1"; - - const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000"; - - var contentFeatures = string.Empty; - - if (string.Equals(item.Container, "mp3", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MP3"; - } - else if (string.Equals(item.Container, "wma", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=WMABASE"; - } - else if (string.Equals(item.Container, "wmw", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=WMVMED_BASE"; - } - else if (string.Equals(item.Container, "asf", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=WMVMED_BASE"; - } - else if (string.Equals(item.Container, "avi", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=AVI"; - } - else if (string.Equals(item.Container, "mkv", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MATROSKA"; - } - else if (string.Equals(item.Container, "mp4", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC"; - } - else if (string.Equals(item.Container, "mpeg", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; - } - else if (string.Equals(item.Container, "ts", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; - } - else if (item.MediaType == Controller.Dlna.DlnaProfileType.Video) - { - //Default to AVI for video - contentFeatures = "DLNA.ORG_PN=AVI"; - } - else - { - //Default to MP3 for audio - contentFeatures = "DLNA.ORG_PN=MP3"; - } - - return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); - } - - #region Audio - - /// <summary> /// Gets the audio URL. /// </summary> + /// <param name="deviceProperties">The device properties.</param> /// <param name="item">The item.</param> + /// <param name="streams">The streams.</param> /// <param name="serverAddress">The server address.</param> /// <returns>System.String.</returns> - internal static string GetAudioUrl(PlaylistItem item, string serverAddress) + internal static string GetAudioUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress) { - if (!item.Transcode) - return string.Format("{0}/audio/{1}/stream{2}?Static=True", serverAddress, item.ItemId, item.Container); + var dlnaCommand = BuildDlnaUrl(item.DeviceProfileName, item.MediaSourceId, deviceProperties.UUID, !item.Transcode, null, item.AudioCodec, item.AudioStreamIndex, item.SubtitleStreamIndex, null, 128000, item.StartPositionTicks, item.TranscodingSettings); - return string.Format("{0}/audio/{1}/stream.mp3?AudioCodec=Mp3", serverAddress, item.ItemId); + return string.Format("{0}/audio/{1}/stream{2}?{3}", serverAddress, item.ItemId, "." + item.Container.TrimStart('.'), dlnaCommand); } - #endregion - - #region Video - /// <summary> /// Gets the video URL. /// </summary> @@ -104,97 +33,41 @@ namespace MediaBrowser.Dlna.PlayTo /// <returns>The url to send to the device</returns> internal static string GetVideoUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress) { - string dlnaCommand = string.Empty; - if (!item.Transcode) - { - dlnaCommand = BuildDlnaUrl(deviceProperties.UUID, !item.Transcode, null, null, null, null, null, null, null, null, null, null, item.MimeType); - return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand); - } - var videostream = streams.Where(m => m.Type == MediaStreamType.Video).OrderBy(m => m.IsDefault).FirstOrDefault(); - var audiostream = streams.Where(m => m.Type == MediaStreamType.Audio).OrderBy(m => m.IsDefault).FirstOrDefault(); - - var videoCodec = GetVideoCodec(videostream); - var audioCodec = GetAudioCodec(audiostream); - int? videoBitrate = null; - int? audioBitrate = null; - int? audioChannels = null; - - if (videoCodec != VideoCodecs.Copy) - videoBitrate = 2000000; + var dlnaCommand = BuildDlnaUrl(item.DeviceProfileName, item.MediaSourceId, deviceProperties.UUID, !item.Transcode, item.VideoCodec, item.AudioCodec, item.AudioStreamIndex, item.SubtitleStreamIndex, 1500000, 128000, item.StartPositionTicks, item.TranscodingSettings); - if (audioCodec != AudioCodecs.Copy) - { - audioBitrate = 128000; - audioChannels = 2; - } - - dlnaCommand = BuildDlnaUrl(deviceProperties.UUID, !item.Transcode, videoCodec, audioCodec, null, null, videoBitrate, audioChannels, audioBitrate, item.StartPositionTicks, "baseline", "3", item.MimeType); return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand); } /// <summary> - /// Gets the video codec. - /// </summary> - /// <param name="videoStream">The video stream.</param> - /// <returns></returns> - private static VideoCodecs GetVideoCodec(MediaStream videoStream) - { - switch (videoStream.Codec.ToLower()) - { - case "h264": - case "mpeg4": - return VideoCodecs.Copy; - - } - return VideoCodecs.H264; - } - - /// <summary> - /// Gets the audio codec. - /// </summary> - /// <param name="audioStream">The audio stream.</param> - /// <returns></returns> - private static AudioCodecs GetAudioCodec(MediaStream audioStream) - { - if (audioStream != null) - { - switch (audioStream.Codec.ToLower()) - { - case "aac": - case "mp3": - case "wma": - return AudioCodecs.Copy; - - } - } - return AudioCodecs.Aac; - } - - /// <summary> /// Builds the dlna URL. /// </summary> - private static string BuildDlnaUrl(string deviceID, bool isStatic, VideoCodecs? videoCodec, AudioCodecs? audioCodec, int? subtitleIndex, int? audiostreamIndex, int? videoBitrate, int? audiochannels, int? audioBitrate, long? startPositionTicks, string profile, string videoLevel, string mimeType) + private static string BuildDlnaUrl(string deviceProfileName, string mediaSourceId, string deviceID, bool isStatic, string videoCodec, string audioCodec, int? audiostreamIndex, int? subtitleIndex, int? videoBitrate, int? audioBitrate, long? startPositionTicks, List<TranscodingSetting> settings) { - var usCulture = new CultureInfo("en-US"); + var profile = settings.Where(i => i.Name == TranscodingSettingType.VideoProfile).Select(i => i.Value).FirstOrDefault(); + var videoLevel = settings.Where(i => i.Name == TranscodingSettingType.VideoLevel).Select(i => i.Value).FirstOrDefault(); + var maxAudioChannels = settings.Where(i => i.Name == TranscodingSettingType.MaxAudioChannels).Select(i => i.Value).FirstOrDefault(); - var dlnaparam = string.Format("Params={0};", deviceID); - dlnaparam += isStatic ? "true;" : "false;"; - dlnaparam += videoCodec.HasValue ? videoCodec.Value + ";" : ";"; - dlnaparam += audioCodec.HasValue ? audioCodec.Value + ";" : ";"; - dlnaparam += audiostreamIndex.HasValue ? audiostreamIndex.Value.ToString(usCulture) + ";" : ";"; - dlnaparam += subtitleIndex.HasValue ? subtitleIndex.Value.ToString(usCulture) + ";" : ";"; - dlnaparam += videoBitrate.HasValue ? videoBitrate.Value.ToString(usCulture) + ";" : ";"; - dlnaparam += audioBitrate.HasValue ? audioBitrate.Value.ToString(usCulture) + ";" : ";"; - dlnaparam += audiochannels.HasValue ? audiochannels.Value.ToString(usCulture) + ";" : ";"; - dlnaparam += startPositionTicks.HasValue ? startPositionTicks.Value.ToString(usCulture) + ";" : ";"; - dlnaparam += profile + ";"; - dlnaparam += videoLevel + ";"; - dlnaparam += mimeType + ";"; + var usCulture = new CultureInfo("en-US"); - return dlnaparam; + var list = new List<string> + { + deviceProfileName ?? string.Empty, + deviceID ?? string.Empty, + mediaSourceId ?? string.Empty, + isStatic.ToString().ToLower(), + videoCodec ?? string.Empty, + audioCodec ?? string.Empty, + audiostreamIndex.HasValue ? audiostreamIndex.Value.ToString(usCulture) : string.Empty, + subtitleIndex.HasValue ? subtitleIndex.Value.ToString(usCulture) : string.Empty, + videoBitrate.HasValue ? videoBitrate.Value.ToString(usCulture) : string.Empty, + audioBitrate.HasValue ? audioBitrate.Value.ToString(usCulture) : string.Empty, + maxAudioChannels ?? string.Empty, + startPositionTicks.HasValue ? startPositionTicks.Value.ToString(usCulture) : string.Empty, + profile ?? string.Empty, + videoLevel ?? string.Empty + }; + + return string.Format("Params={0}", string.Join(";", list.ToArray())); } - - #endregion - } }
\ No newline at end of file diff --git a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs new file mode 100644 index 000000000..a1c661275 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs @@ -0,0 +1,59 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class DefaultProfile : DeviceProfile + { + public DefaultProfile() + { + ProtocolInfo = "DLNA"; + + ClientType = "DLNA"; + Manufacturer = "Media Browser"; + ModelDescription = "Media Browser"; + ModelName = "Media Browser"; + ModelNumber = "Media Browser"; + ModelUrl = "http://mediabrowser3.com/"; + ManufacturerUrl = "http://mediabrowser3.com/"; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + + new TranscodingProfile + { + Container = "ts", + Type = DlnaProfileType.Video, + AudioCodec = "aac", + VideoCodec = "h264", + + Settings = new [] + { + new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"}, + new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"} + } + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "mp3,wma", + Type = DlnaProfileType.Audio + }, + + new DirectPlayProfile + { + Container = "avi,mp4", + Type = DlnaProfileType.Video + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs b/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs new file mode 100644 index 000000000..cca6ab6bb --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/DenonAvrProfile.cs @@ -0,0 +1,27 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class DenonAvrProfile : DefaultProfile + { + public DenonAvrProfile() + { + Name = "Denon AVR"; + + Identification = new DeviceIdentification + { + FriendlyName = @"Denon:\[AVR:.*", + Manufacturer = "Denon" + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "mp3,flac,m4a,wma", + Type = DlnaProfileType.Audio + }, + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/LgTvProfile.cs b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs new file mode 100644 index 000000000..ec20c9df8 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/LgTvProfile.cs @@ -0,0 +1,192 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class LgTvProfile : DefaultProfile + { + public LgTvProfile() + { + Name = "LG Smart TV"; + + TimelineOffsetSeconds = 10; + + Identification = new DeviceIdentification + { + FriendlyName = @"LG.*", + + Headers = new[] + { + new HttpHeaderInfo + { + Name = "User-Agent", + Value = "LG", + Match = HeaderMatchType.Substring + } + } + }; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new TranscodingProfile + { + Container = "ts", + AudioCodec = "ac3", + VideoCodec = "h264", + Type = DlnaProfileType.Video + }, + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "aac,ac3,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mkv", + VideoCodec = "h264", + AudioCodec = "aac,ac3,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp4", + VideoCodec = "h264,mpeg4", + AudioCodec = "aac,ac3,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "mpeg4", + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "h264", + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoLevel, + Value = "41" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "ac3,aac,mp3", + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "6" + } + } + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs b/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs new file mode 100644 index 000000000..e7086c205 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/LinksysDMA2100Profile.cs @@ -0,0 +1,33 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class LinksysDMA2100Profile : DefaultProfile + { + public LinksysDMA2100Profile() + { + // Linksys DMA2100us does not need any transcoding of the formats we support statically + Name = "Linksys DMA2100"; + + Identification = new DeviceIdentification + { + ModelName = "DMA2100us" + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "mp3,flac,m4a,wma", + Type = DlnaProfileType.Audio + }, + + new DirectPlayProfile + { + Container = "avi,mp4,mkv,ts", + Type = DlnaProfileType.Video + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs b/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs new file mode 100644 index 000000000..6755c0680 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs @@ -0,0 +1,186 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class PanasonicVieraProfile : DefaultProfile + { + public PanasonicVieraProfile() + { + Name = "Panasonic Viera"; + + Identification = new DeviceIdentification + { + FriendlyName = @"VIERA", + Manufacturer = "Panasonic", + + Headers = new[] + { + new HttpHeaderInfo + { + Name = "User-Agent", + Value = "Panasonic MIL DLNA", + Match = HeaderMatchType.Substring + } + } + }; + + TimelineOffsetSeconds = 10; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new TranscodingProfile + { + Container = "ts", + AudioCodec = "ac3", + VideoCodec = "h264", + Type = DlnaProfileType.Video + }, + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "mpeg", + VideoCodec = "mpeg2video,mpeg4", + AudioCodec = "ac3,mp3", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "mkv", + VideoCodec = "h264", + AudioCodec = "aac,ac3,mp3,pcm", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "aac,mp3", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "mp4", + VideoCodec = "h264", + AudioCodec = "aac,ac3,mp3,pcm", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "mov", + VideoCodec = "h264", + AudioCodec = "aac,pcm", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "avi", + VideoCodec = "mpeg4", + AudioCodec = "pcm", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "flv", + VideoCodec = "h264", + AudioCodec = "aac", + Type = DlnaProfileType.Video + }, + + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + + new DirectPlayProfile + { + Container = "mp4", + AudioCodec = "aac", + Type = DlnaProfileType.Audio + }, + + new DirectPlayProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitDepth, + Value = "8", + IsRequired = false + } + } + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs new file mode 100644 index 000000000..fa6b1201a --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs @@ -0,0 +1,315 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class SamsungSmartTvProfile : DefaultProfile + { + public SamsungSmartTvProfile() + { + Name = "Samsung Smart TV"; + + SupportsAlbumArtInDidl = true; + + Identification = new DeviceIdentification + { + ModelUrl = "samsung.com" + }; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new TranscodingProfile + { + Container = "ts", + AudioCodec = "ac3", + VideoCodec = "h264", + Type = DlnaProfileType.Video + }, + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "asf", + VideoCodec = "h264,mpeg4,mjpeg", + AudioCodec = "mp3,ac3,wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "avi", + VideoCodec = "h264,mpeg4,mjpeg", + AudioCodec = "mp3,ac3,dca", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mkv", + VideoCodec = "h264,mpeg4,mjpeg4", + AudioCodec = "mp3,ac3,dca,aac", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp4", + VideoCodec = "h264,mpeg4", + AudioCodec = "mp3,aac", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "3gpp", + VideoCodec = "h264,mpeg4", + AudioCodec = "aac,he-aac", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mpg,mpeg", + VideoCodec = "mpeg1video,mpeg2video,h264", + AudioCodec = "ac3,mp2,mp3,aac", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "vro,vob", + VideoCodec = "mpeg1video,mpeg2video", + AudioCodec = "ac3,mp2,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "mpeg2video,h264,vc1", + AudioCodec = "ac3,aac,mp3,eac3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "asf", + VideoCodec = "wmv2,wmv3", + AudioCodec = "wmav2,wmavoice", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "mpeg2video", + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "30720000" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "mpeg4", + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "8192000" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "h264", + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "37500000" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoLevel, + Value = "41" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "wmv2,wmv3,vc1", + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "25600000" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "ac3,wmav2,dca,aac,mp3", + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "6" + } + } + } + }; + + MediaProfiles = new[] + { + 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 new file mode 100644 index 000000000..49aa47027 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs @@ -0,0 +1,180 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class SonyBlurayPlayer2013Profile : DefaultProfile + { + public SonyBlurayPlayer2013Profile() + { + Identification = new DeviceIdentification + { + FriendlyName = @"Blu-ray Disc Player", + Manufacturer = "Sony", + ModelNumber = "BDP-2013" + }; + + ModelName = "Windows Media Player Sharing"; + ModelNumber = "3.0"; + Manufacturer = "Microsoft Corporation"; + + 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"; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + + new TranscodingProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "ac3", + Type = DlnaProfileType.Video + }, + + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "mpeg1video,mpeg2video,h264", + AudioCodec = "ac3,aac,mp3,pcm", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mpeg", + VideoCodec = "mpeg1video,mpeg2video", + AudioCodec = "ac3,mp3,mp2,pcm", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp4", + VideoCodec = "mpeg4,h264", + AudioCodec = "ac3,aac,pcm,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "avi", + VideoCodec = "mpeg4,h264", + AudioCodec = "ac3,aac,mp3,pcm", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mkv", + VideoCodec = "mpeg4,h264", + AudioCodec = "ac3,dca,aac,mp3,pcm", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "mp4", + AudioCodec = "aac", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "asf", + AudioCodec = "wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "h264", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30", + IsRequired = false + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "ac3", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "6", + IsRequired = false + } + } + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs new file mode 100644 index 000000000..512172670 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs @@ -0,0 +1,261 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class SonyBlurayPlayerProfile : DefaultProfile + { + public SonyBlurayPlayerProfile() + { + Identification = new DeviceIdentification + { + FriendlyName = @"Blu-ray Disc Player", + Manufacturer = "Sony", + + Headers = new[] + { + new HttpHeaderInfo + { + Name = "X-AV-Client-Info", + Value = @"(Blu-ray Disc Player|Home Theater System|Home Theatre System|Media Player)", + Match = HeaderMatchType.Regex + }, + + new HttpHeaderInfo + { + Name = "X-AV-Physical-Unit-Info", + Value = @"(Blu-ray Disc Player|Home Theater System|Home Theatre System|Media Player)", + Match = HeaderMatchType.Regex + } + } + }; + + ModelName = "Windows Media Player Sharing"; + ModelNumber = "3.0"; + Manufacturer = "Microsoft Corporation"; + + 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"; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + + new TranscodingProfile + { + Container = "ts", + VideoCodec = "mpeg2video", + AudioCodec = "ac3", + Type = DlnaProfileType.Video + }, + + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "mpeg1video,mpeg2video,h264", + AudioCodec = "ac3,aac,mp3,pcm", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mpeg", + VideoCodec = "mpeg1video,mpeg2video", + AudioCodec = "ac3,mp3,pcm", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "avi,mp4", + VideoCodec = "mpeg4,h264", + AudioCodec = "ac3,aac,mp3,pcm", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "asf", + AudioCodec = "wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "h264", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30", + IsRequired = false + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoLevel, + Value = "41", + IsRequired = false + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "15360000", + IsRequired = false + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "ac3", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "6", + IsRequired = false + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "aac", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "2", + IsRequired = false + } + } + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + MediaProfiles = new[] + { + new MediaProfile + { + Container = "ts", + VideoCodec = "h264,mpeg4,vc1", + AudioCodec = "ac3,aac,mp3", + MimeType = "video/vnd.dlna.mpeg-tts", + OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "avi", + MimeType = "video/mpeg", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "mkv", + MimeType = "video/vnd.dlna.mpeg-tts", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "ts", + MimeType = "video/vnd.dlna.mpeg-tts", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "mp4", + MimeType = "video/mpeg", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "mpeg", + MimeType = "video/mpeg", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "mp3", + MimeType = "audio/mpeg", + Type = DlnaProfileType.Audio + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs new file mode 100644 index 000000000..042cc0a96 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs @@ -0,0 +1,286 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class SonyBravia2010Profile : DefaultProfile + { + public SonyBravia2010Profile() + { + Name = "Sony Bravia (2010)"; + + Identification = new DeviceIdentification + { + FriendlyName = @"KDL-\d{2}[EHLNPB]X\d[01]\d.*", + Manufacturer = "Sony", + + Headers = new[] + { + new HttpHeaderInfo + { + Name = "X-AV-Client-Info", + Value = @".*KDL-\d{2}[EHLNPB]X\d[01]\d.*", + Match = HeaderMatchType.Regex + } + } + }; + + ModelName = "Windows Media Player Sharing"; + ModelNumber = "3.0"; + ModelUrl = "http://www.microsoft.com/"; + Manufacturer = "Microsoft Corporation"; + ManufacturerUrl = "http://www.microsoft.com/"; + SonyAggregationFlags = "10"; + 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"; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new TranscodingProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "ac3,aac", + Type = DlnaProfileType.Video, + EnableMpegtsM2TsMode = true + }, + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "ac3,aac,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "mpeg1video,mpeg2video", + AudioCodec = "mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mpeg", + VideoCodec = "mpeg2video,mpeg1video", + AudioCodec = "mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + } + }; + + MediaProfiles = new[] + { + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + 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"} + } + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + 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"} + } + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + AudioCodec="ac3,aac,mp3", + MimeType = "video/vnd.dlna.mpeg-tts", + OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="mpeg2video", + MimeType = "video/vnd.dlna.mpeg-tts", + OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "mpeg", + VideoCodec="mpeg1video,mpeg2video", + MimeType = "video/mpeg", + OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL", + Type = DlnaProfileType.Video + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "h264", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "20000000" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoLevel, + Value = "41" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "mpeg2video", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "20000000" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "ac3", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "6" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "aac", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "2" + }, + new ProfileCondition + { + Condition = ProfileConditionType.NotEquals, + Property = ProfileConditionValue.AudioProfile, + Value = "he-aac" + } + } + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs new file mode 100644 index 000000000..401c40c36 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs @@ -0,0 +1,304 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class SonyBravia2011Profile : DefaultProfile + { + public SonyBravia2011Profile() + { + Name = "Sony Bravia (2011)"; + + Identification = new DeviceIdentification + { + FriendlyName = @"KDL-\d{2}([A-Z]X\d2\d|CX400).*", + Manufacturer = "Sony", + + Headers = new[] + { + new HttpHeaderInfo + { + Name = "X-AV-Client-Info", + Value = @".*KDL-\d{2}([A-Z]X\d2\d|CX400).*", + Match = HeaderMatchType.Regex + } + } + }; + + ModelName = "Windows Media Player Sharing"; + ModelNumber = "3.0"; + ModelUrl = "http://www.microsoft.com/"; + Manufacturer = "Microsoft Corporation"; + ManufacturerUrl = "http://www.microsoft.com/"; + SonyAggregationFlags = "10"; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new TranscodingProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "ac3,aac", + Type = DlnaProfileType.Video, + EnableMpegtsM2TsMode = true + }, + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "ac3,aac,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "mpeg2video", + AudioCodec = "mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp4", + VideoCodec = "h264,mpeg4", + AudioCodec = "ac3,aac,mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mpeg", + VideoCodec = "mpeg2video,mpeg1video", + AudioCodec = "mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "asf", + VideoCodec = "wmv2,wmv3,vc1", + AudioCodec = "wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "asf", + AudioCodec = "wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Audio + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + MediaProfiles = new[] + { + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + 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"} + } + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + 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"} + } + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + AudioCodec="ac3,aac,mp3", + MimeType = "video/vnd.dlna.mpeg-tts", + OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="mpeg2video", + MimeType = "video/vnd.dlna.mpeg-tts", + OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "mpeg", + VideoCodec="mpeg1video,mpeg2video", + MimeType = "video/mpeg", + OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL", + Type = DlnaProfileType.Video + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "h264", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "20000000" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoLevel, + Value = "41" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "mpeg2video", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "20000000" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "ac3", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "6" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "aac", + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "2" + }, + new ProfileCondition + { + Condition = ProfileConditionType.NotEquals, + Property = ProfileConditionValue.AudioProfile, + Value = "he-aac" + } + } + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs new file mode 100644 index 000000000..2d24c406e --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs @@ -0,0 +1,246 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class SonyBravia2012Profile : DefaultProfile + { + public SonyBravia2012Profile() + { + Name = "Sony Bravia (2012)"; + + Identification = new DeviceIdentification + { + FriendlyName = @"KDL-\d{2}[A-Z]X\d5(\d|G).*", + Manufacturer = "Sony", + + Headers = new[] + { + new HttpHeaderInfo + { + Name = "X-AV-Client-Info", + Value = @".*KDL-\d{2}[A-Z]X\d5(\d|G).*", + Match = HeaderMatchType.Regex + } + } + }; + + ModelName = "Windows Media Player Sharing"; + ModelNumber = "3.0"; + ModelUrl = "http://www.microsoft.com/"; + Manufacturer = "Microsoft Corporation"; + ManufacturerUrl = "http://www.microsoft.com/"; + SonyAggregationFlags = "10"; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new TranscodingProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "ac3,aac", + Type = DlnaProfileType.Video, + EnableMpegtsM2TsMode = true + }, + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "ac3,aac,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "mpeg2video", + AudioCodec = "mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp4", + VideoCodec = "h264,mpeg4", + AudioCodec = "ac3,aac,mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "avi", + VideoCodec = "mpeg4", + AudioCodec = "ac3,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mpeg", + VideoCodec = "mpeg2video,mpeg1video", + AudioCodec = "mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "asf", + VideoCodec = "wmv2,wmv3,vc1", + AudioCodec = "wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "asf", + AudioCodec = "wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + MediaProfiles = new[] + { + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + 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"} + } + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + 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"} + } + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + AudioCodec="ac3,aac,mp3", + MimeType = "video/vnd.dlna.mpeg-tts", + OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="mpeg2video", + MimeType = "video/vnd.dlna.mpeg-tts", + OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "mpeg", + VideoCodec="mpeg1video,mpeg2video", + MimeType = "video/mpeg", + OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL", + Type = DlnaProfileType.Video + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "ac3", + + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "6" + } + } + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs new file mode 100644 index 000000000..10f712958 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs @@ -0,0 +1,264 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class SonyBravia2013Profile : DefaultProfile + { + public SonyBravia2013Profile() + { + Name = "Sony Bravia (2013)"; + + Identification = new DeviceIdentification + { + FriendlyName = @"KDL-\d{2}[WR][5689]\d{2}A.*", + Manufacturer = "Sony", + + Headers = new[] + { + new HttpHeaderInfo + { + Name = "X-AV-Client-Info", + Value = @".*KDL-\d{2}[WR][5689]\d{2}A.*", + Match = HeaderMatchType.Regex + } + } + }; + + ModelName = "Windows Media Player Sharing"; + ModelNumber = "3.0"; + ModelUrl = "http://www.microsoft.com/"; + Manufacturer = "Microsoft Corporation"; + ManufacturerUrl = "http://www.microsoft.com/"; + SonyAggregationFlags = "10"; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + Type = DlnaProfileType.Audio + }, + new TranscodingProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "ac3,aac", + Type = DlnaProfileType.Video, + EnableMpegtsM2TsMode = true + }, + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "ac3,eac3,aac,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "ts", + VideoCodec = "mpeg2video", + AudioCodec = "mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp4", + VideoCodec = "h264,mpeg4", + AudioCodec = "ac3,eac3,aac,mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mov", + VideoCodec = "h264,mpeg4,mjpeg", + AudioCodec = "ac3,eac3,aac,mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mkv", + VideoCodec = "h264,mpeg4,vp8", + AudioCodec = "ac3,eac3,aac,mp3,mp2,pcm,vorbis", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "avi", + VideoCodec = "mpeg4", + AudioCodec = "ac3,eac3,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "avi", + VideoCodec = "mjpeg", + AudioCodec = "pcm", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mpeg", + VideoCodec = "mpeg2video,mpeg1video", + AudioCodec = "mp3,mp2", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "asf", + VideoCodec = "wmv2,wmv3,vc1", + AudioCodec = "wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "mp4", + AudioCodec = "aac", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "wav", + AudioCodec = "pcm", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "asf", + AudioCodec = "wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + MediaProfiles = new[] + { + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + 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"} + } + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + 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"} + } + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="h264", + AudioCodec="ac3,aac,mp3", + MimeType = "video/vnd.dlna.mpeg-tts", + OrgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "ts", + VideoCodec="mpeg2video", + MimeType = "video/vnd.dlna.mpeg-tts", + OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "mpeg", + VideoCodec="mpeg1video,mpeg2video", + MimeType = "video/mpeg", + OrgPn="MPEG_PS_NTSC,MPEG_PS_PAL", + Type = DlnaProfileType.Video + } + }; + + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs b/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs new file mode 100644 index 000000000..e5fc1ed07 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/SonyPs3Profile.cs @@ -0,0 +1,233 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class SonyPs3Profile : DefaultProfile + { + public SonyPs3Profile() + { + Name = "Sony Bravia (2010)"; + + Identification = new DeviceIdentification + { + Headers = new[] + { + new HttpHeaderInfo + { + Name = "User-Agent", + Value = @"PLAYSTATION 3", + Match = HeaderMatchType.Substring + }, + + new HttpHeaderInfo + { + Name = "X-AV-Client-Info", + Value = @"PLAYSTATION 3", + Match = HeaderMatchType.Substring + } + } + }; + + SonyAggregationFlags = "10"; + XDlnaDoc = "DMS-1.50"; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new TranscodingProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "mp3", + Type = DlnaProfileType.Video + }, + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "h264", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30", + IsRequired = false + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "15360000", + IsRequired = false + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoLevel, + Value = "41", + IsRequired = false + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "ac3", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "6", + IsRequired = false + }, + + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioBitrate, + Value = "640000", + IsRequired = false + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "wmapro", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "2" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "aac", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.NotEquals, + Property = ProfileConditionValue.AudioProfile, + Value = "he-aac", + IsRequired = false + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "aac", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "2" + }, + new ProfileCondition + { + Condition = ProfileConditionType.NotEquals, + Property = ProfileConditionValue.AudioProfile, + Value = "he-aac" + } + } + } + }; + + MediaProfiles = new[] + { + new MediaProfile + { + Container = "mp4,mov", + AudioCodec="aac", + MimeType = "video/mp4", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "avi", + MimeType = "video/divx", + OrgPn="AVI", + Type = DlnaProfileType.Video + }, + + new MediaProfile + { + Container = "wav", + MimeType = "audio/wav", + Type = DlnaProfileType.Audio + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs b/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs new file mode 100644 index 000000000..52d4a5f29 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs @@ -0,0 +1,241 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class WdtvLiveProfile : DefaultProfile + { + public WdtvLiveProfile() + { + Name = "WDTV Live"; + + TimelineOffsetSeconds = 5; + IgnoreTranscodeByteRangeRequests = true; + + Identification = new DeviceIdentification + { + ModelName = "WD TV HD Live", + + Headers = new [] + { + new HttpHeaderInfo {Name = "User-Agent", Value = "alphanetworks", Match = HeaderMatchType.Substring}, + new HttpHeaderInfo + { + Name = "User-Agent", + Value = "ALPHA Networks", + Match = HeaderMatchType.Substring + } + } + }; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + Type = DlnaProfileType.Audio, + AudioCodec = "mp3" + }, + new TranscodingProfile + { + Container = "ts", + Type = DlnaProfileType.Video, + VideoCodec = "h264", + AudioCodec = "aac", + + Settings = new [] + { + new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"}, + new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"} + } + }, + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "avi", + Type = DlnaProfileType.Video, + VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1", + AudioCodec = "ac3,dca,mp2,mp3,pcm" + }, + + new DirectPlayProfile + { + Container = "mpeg", + Type = DlnaProfileType.Video, + VideoCodec = "mpeg1video,mpeg2video", + AudioCodec = "ac3,dca,mp2,mp3,pcm" + }, + + new DirectPlayProfile + { + Container = "mkv", + Type = DlnaProfileType.Video, + VideoCodec = "mpeg1video,mpeg2video,mpeg4,h264,vc1", + AudioCodec = "ac3,dca,aac,mp2,mp3,pcm" + }, + + new DirectPlayProfile + { + Container = "ts", + Type = DlnaProfileType.Video, + VideoCodec = "mpeg1video,mpeg2video,h264,vc1", + AudioCodec = "ac3,dca,mp2,mp3" + }, + + new DirectPlayProfile + { + Container = "mp4,mov", + Type = DlnaProfileType.Video, + VideoCodec = "h264,mpeg4", + AudioCodec = "ac3,aac,mp2,mp3" + }, + + new DirectPlayProfile + { + Container = "asf", + Type = DlnaProfileType.Video, + VideoCodec = "vc1", + AudioCodec = "wmav2,wmapro" + }, + + new DirectPlayProfile + { + Container = "asf", + Type = DlnaProfileType.Video, + VideoCodec = "mpeg2video", + AudioCodec = "mp2,ac3" + }, + + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp2,mp3", + Type = DlnaProfileType.Audio + }, + + new DirectPlayProfile + { + Container = "mp4", + AudioCodec = "mp4", + Type = DlnaProfileType.Audio + }, + + new DirectPlayProfile + { + Container = "flac", + AudioCodec = "flac", + Type = DlnaProfileType.Audio + }, + + new DirectPlayProfile + { + Container = "asf", + AudioCodec = "wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Audio + }, + + new DirectPlayProfile + { + Container = "ogg", + AudioCodec = "vorbis", + Type = DlnaProfileType.Audio + }, + + new DirectPlayProfile + { + Type = DlnaProfileType.Photo, + + Container = "jpeg,png,gif,bmp,tiff" + } + }; + + MediaProfiles = new[] + { + new MediaProfile + { + Container = "ts", + OrgPn = "MPEG_TS_SD_NA", + Type = DlnaProfileType.Video + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "h264", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoLevel, + Value = "41" + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "aac", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "2" + } + } + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs new file mode 100644 index 000000000..7216457a3 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs @@ -0,0 +1,312 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class Xbox360Profile : DefaultProfile + { + public Xbox360Profile() + { + Name = "Xbox 360"; + + ModelName = "Windows Media Player Sharing"; + ModelNumber = "12.0"; + ModelUrl = "http://www.microsoft.com/"; + Manufacturer = "Microsoft Corporation"; + ManufacturerUrl = "http://www.microsoft.com/"; + XDlnaDoc = "DMS-1.50"; + + TimelineOffsetSeconds = 40; + RequiresPlainFolders = true; + RequiresPlainVideoItems = true; + + Identification = new DeviceIdentification + { + ModelName = "Xbox 360", + + Headers = new [] + { + new HttpHeaderInfo {Name = "User-Agent", Value = "Xbox", Match = HeaderMatchType.Substring}, + new HttpHeaderInfo {Name = "User-Agent", Value = "Xenon", Match = HeaderMatchType.Substring} + } + }; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new TranscodingProfile + { + Container = "asf", + VideoCodec = "wmv2", + AudioCodec = "wmav2", + Type = DlnaProfileType.Video, + TranscodeSeekInfo = TranscodeSeekInfo.Bytes, + EstimateContentLength = true, + + Settings = new [] + { + new TranscodingSetting {Name = TranscodingSettingType.MaxAudioChannels, Value = "6"}, + new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"}, + new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"} + } + }, + new TranscodingProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "avi", + VideoCodec = "mpeg4", + AudioCodec = "ac3,mp3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "avi", + VideoCodec = "h264", + AudioCodec = "aac", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "mp4,mov", + VideoCodec = "h264,mpeg4", + AudioCodec = "aac,ac3", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "asf", + VideoCodec = "wmv2,wmv3,vc1", + AudioCodec = "wmav2,wmapro", + Type = DlnaProfileType.Video + }, + new DirectPlayProfile + { + Container = "asf", + AudioCodec = "wmav2,wmapro,wmavoice", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new DirectPlayProfile + { + Container = "jpeg", + Type = DlnaProfileType.Photo + } + }; + + MediaProfiles = new[] + { + new MediaProfile + { + Container = "avi", + MimeType = "video/avi", + Type = DlnaProfileType.Video + } + }; + + ContainerProfiles = new[] + { + new ContainerProfile + { + Type = DlnaProfileType.Video, + Container = "mp4,mov", + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Has64BitOffsets, + Value = "false", + IsRequired = false + } + } + }, + + new ContainerProfile + { + Type = DlnaProfileType.Photo, + + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + } + } + } + }; + + CodecProfiles = new[] + { + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "mpeg4", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1280" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "720" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30", + IsRequired = false + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "5120000", + IsRequired = false + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "h264", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoLevel, + Value = "41", + IsRequired = false + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "10240000", + IsRequired = false + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoCodec, + Codec = "wmv2,wmv3,vc1", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Width, + Value = "1920" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.Height, + Value = "1080" + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoFramerate, + Value = "30", + IsRequired = false + }, + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.VideoBitrate, + Value = "15360000", + IsRequired = false + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "ac3,wmav2,wmapro", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "6", + IsRequired = false + } + } + }, + + new CodecProfile + { + Type = CodecType.VideoAudioCodec, + Codec = "aac", + Conditions = new [] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "6", + IsRequired = false + }, + new ProfileCondition + { + Condition = ProfileConditionType.Equals, + Property = ProfileConditionValue.AudioProfile, + Value = "lc", + IsRequired = false + } + } + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs b/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs new file mode 100644 index 000000000..0daa5d7a2 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs @@ -0,0 +1,54 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class XboxOneProfile : DefaultProfile + { + public XboxOneProfile() + { + Name = "Xbox One"; + + Identification = new DeviceIdentification + { + ModelName = "Xbox One", + FriendlyName = "Xbox-SystemOS" + }; + + TranscodingProfiles = new[] + { + new TranscodingProfile + { + Container = "mp3", + AudioCodec = "mp3", + Type = DlnaProfileType.Audio + }, + new TranscodingProfile + { + Container = "ts", + VideoCodec = "h264", + AudioCodec = "aac", + Type = DlnaProfileType.Video + } + }; + + DirectPlayProfiles = new[] + { + new DirectPlayProfile + { + Container = "mp3,wma", + Type = DlnaProfileType.Audio + } + }; + + MediaProfiles = new[] + { + new MediaProfile + { + Container = "avi", + MimeType = "video/x-msvideo", + Type = DlnaProfileType.Video + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Server/DlnaServerEntryPoint.cs b/MediaBrowser.Dlna/Server/DlnaServerEntryPoint.cs new file mode 100644 index 000000000..f1af0af28 --- /dev/null +++ b/MediaBrowser.Dlna/Server/DlnaServerEntryPoint.cs @@ -0,0 +1,115 @@ +using MediaBrowser.Common; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Plugins; +using MediaBrowser.Model.Logging; +using System; + +namespace MediaBrowser.Dlna.Server +{ + public class DlnaServerEntryPoint : IServerEntryPoint + { + private readonly IServerConfigurationManager _config; + private readonly ILogger _logger; + + private SsdpHandler _ssdpHandler; + private readonly IApplicationHost _appHost; + + public DlnaServerEntryPoint(IServerConfigurationManager config, ILogManager logManager, IApplicationHost appHost) + { + _config = config; + _appHost = appHost; + _logger = logManager.GetLogger("DlnaServer"); + } + + public void Run() + { + _config.ConfigurationUpdated += ConfigurationUpdated; + + //ReloadServer(); + } + + void ConfigurationUpdated(object sender, EventArgs e) + { + //ReloadServer(); + } + + private void ReloadServer() + { + var isStarted = _ssdpHandler != null; + + if (_config.Configuration.DlnaOptions.EnableServer && !isStarted) + { + StartServer(); + } + else if (!_config.Configuration.DlnaOptions.EnableServer && isStarted) + { + DisposeServer(); + } + } + + private readonly object _syncLock = new object(); + private void StartServer() + { + var signature = GenerateServerSignature(); + + lock (_syncLock) + { + try + { + _ssdpHandler = new SsdpHandler(_logger, _config, signature); + } + catch (Exception ex) + { + _logger.ErrorException("Error starting Dlna server", ex); + } + } + } + + private void DisposeServer() + { + lock (_syncLock) + { + if (_ssdpHandler != null) + { + try + { + _ssdpHandler.Dispose(); + } + catch (Exception ex) + { + _logger.ErrorException("Error disposing Dlna server", ex); + } + _ssdpHandler = null; + } + } + } + + private string GenerateServerSignature() + { + var os = Environment.OSVersion; + var pstring = os.Platform.ToString(); + switch (os.Platform) + { + case PlatformID.Win32NT: + case PlatformID.Win32S: + case PlatformID.Win32Windows: + pstring = "WIN"; + break; + } + + return String.Format( + "{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 MediaBrowser/{4}", + pstring, + IntPtr.Size * 8, + os.Version.Major, + os.Version.Minor, + _appHost.ApplicationVersion + ); + } + + public void Dispose() + { + DisposeServer(); + } + } +} diff --git a/MediaBrowser.Dlna/Server/Headers.cs b/MediaBrowser.Dlna/Server/Headers.cs new file mode 100644 index 000000000..859ae7fbf --- /dev/null +++ b/MediaBrowser.Dlna/Server/Headers.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace MediaBrowser.Dlna.Server +{ + public class Headers : IDictionary<string, string> + { + private readonly bool _asIs = false; + 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) + { + _asIs = asIs; + } + + public Headers() + : this(asIs: false) + { + } + + public int Count + { + get + { + return _dict.Count; + } + } + public string HeaderBlock + { + get + { + var hb = new StringBuilder(); + foreach (var h in this) + { + hb.AppendFormat("{0}: {1}\r\n", h.Key, h.Value); + } + return hb.ToString(); + } + } + public Stream HeaderStream + { + get + { + return new MemoryStream(Encoding.ASCII.GetBytes(HeaderBlock)); + } + } + public bool IsReadOnly + { + get + { + return false; + } + } + public ICollection<string> Keys + { + get + { + return _dict.Keys; + } + } + public ICollection<string> Values + { + get + { + return _dict.Values; + } + } + + + public string this[string key] + { + get + { + return _dict[Normalize(key)]; + } + set + { + _dict[Normalize(key)] = value; + } + } + + + private string Normalize(string header) + { + if (!_asIs) + { + header = header.ToLower(); + } + header = header.Trim(); + if (!Validator.IsMatch(header)) + { + throw new ArgumentException("Invalid header: " + header); + } + return header; + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return _dict.GetEnumerator(); + } + + public void Add(KeyValuePair<string, string> item) + { + Add(item.Key, item.Value); + } + + public void Add(string key, string value) + { + _dict.Add(Normalize(key), value); + } + + public void Clear() + { + _dict.Clear(); + } + + public bool Contains(KeyValuePair<string, string> item) + { + var p = new KeyValuePair<string, string>(Normalize(item.Key), item.Value); + return _dict.Contains(p); + } + + public bool ContainsKey(string key) + { + return _dict.ContainsKey(Normalize(key)); + } + + public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + + public IEnumerator<KeyValuePair<string, string>> GetEnumerator() + { + return _dict.GetEnumerator(); + } + + public bool Remove(string key) + { + return _dict.Remove(Normalize(key)); + } + + public bool Remove(KeyValuePair<string, string> item) + { + return Remove(item.Key); + } + + public override string ToString() + { + return string.Format("({0})", string.Join(", ", (from x in _dict + select string.Format("{0}={1}", x.Key, x.Value)))); + } + + public bool TryGetValue(string key, out string value) + { + return _dict.TryGetValue(Normalize(key), out value); + } + } +} diff --git a/MediaBrowser.Dlna/Server/RawHeaders.cs b/MediaBrowser.Dlna/Server/RawHeaders.cs new file mode 100644 index 000000000..f57e6b9f3 --- /dev/null +++ b/MediaBrowser.Dlna/Server/RawHeaders.cs @@ -0,0 +1,16 @@ +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 new file mode 100644 index 000000000..63c2abbec --- /dev/null +++ b/MediaBrowser.Dlna/Server/SsdpHandler.cs @@ -0,0 +1,260 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace MediaBrowser.Dlna.Server +{ + public class SsdpHandler : IDisposable + { + private readonly ILogger _logger; + private readonly IServerConfigurationManager _config; + private readonly string _serverSignature; + private bool _isDisposed = false; + + const string SSDPAddr = "239.255.255.250"; + const int SSDPPort = 1900; + + private readonly IPEndPoint _ssdpEndp = new IPEndPoint(IPAddress.Parse(SSDPAddr), SSDPPort); + private readonly IPAddress _ssdpIp = IPAddress.Parse(SSDPAddr); + + private UdpClient _udpClient; + + private readonly Dictionary<Guid, List<UpnpDevice>> _devices = new Dictionary<Guid, List<UpnpDevice>>(); + + public SsdpHandler(ILogger logger, IServerConfigurationManager config, string serverSignature) + { + _logger = logger; + _config = config; + _serverSignature = serverSignature; + + Start(); + } + + private IEnumerable<UpnpDevice> Devices + { + get + { + UpnpDevice[] devs; + lock (_devices) + { + devs = _devices.Values.SelectMany(i => i).ToArray(); + } + return devs; + } + } + + private void Start() + { + _udpClient = new UdpClient(); + _udpClient.Client.UseOnlyOverlappedIO = true; + _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + _udpClient.ExclusiveAddressUse = false; + _udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, SSDPPort)); + _udpClient.JoinMulticastGroup(_ssdpIp, 2); + _logger.Info("SSDP service started"); + Receive(); + } + + private void Receive() + { + try + { + _udpClient.BeginReceive(ReceiveCallback, null); + } + catch (ObjectDisposedException) + { + } + } + + private void ReceiveCallback(IAsyncResult result) + { + try + { + var endpoint = new IPEndPoint(IPAddress.None, SSDPPort); + var received = _udpClient.EndReceive(result, ref endpoint); + + if (_config.Configuration.DlnaOptions.EnableDebugLogging) + { + _logger.Debug("{0} - SSDP Received a datagram", endpoint); + } + + using (var reader = new StreamReader(new MemoryStream(received), Encoding.ASCII)) + { + var proto = (reader.ReadLine() ?? string.Empty).Trim(); + var method = proto.Split(new[] { ' ' }, 2)[0]; + var headers = new Headers(); + for (var line = reader.ReadLine(); line != null; line = reader.ReadLine()) + { + line = line.Trim(); + if (string.IsNullOrEmpty(line)) + { + break; + } + var parts = line.Split(new char[] { ':' }, 2); + headers[parts[0]] = parts[1].Trim(); + } + + if (_config.Configuration.DlnaOptions.EnableDebugLogging) + { + _logger.Debug("{0} - Datagram method: {1}", endpoint, method); + //_logger.Debug(headers); + } + + if (string.Equals(method, "M-SEARCH", StringComparison.OrdinalIgnoreCase)) + { + RespondToSearch(endpoint, headers["st"]); + } + } + } + catch (Exception ex) + { + _logger.ErrorException("Failed to read SSDP message", ex); + } + + if (!_isDisposed) + { + Receive(); + } + } + + private void RespondToSearch(IPEndPoint endpoint, string req) + { + if (req == "ssdp:all") + { + req = null; + } + + if (_config.Configuration.DlnaOptions.EnableDebugLogging) + { + _logger.Debug("RespondToSearch"); + } + + foreach (var d in Devices) + { + if (!string.IsNullOrEmpty(req) && req != d.Type) + { + continue; + } + + SendSearchResponse(endpoint, d); + } + } + + private void SendSearchResponse(IPEndPoint endpoint, UpnpDevice dev) + { + var headers = new RawHeaders(); + headers.Add("CACHE-CONTROL", "max-age = 600"); + headers.Add("DATE", DateTime.Now.ToString("R")); + headers.Add("EXT", ""); + headers.Add("LOCATION", dev.Descriptor.ToString()); + headers.Add("SERVER", _serverSignature); + headers.Add("ST", dev.Type); + headers.Add("USN", dev.USN); + + SendDatagram(endpoint, String.Format("HTTP/1.1 200 OK\r\n{0}\r\n", headers.HeaderBlock), false); + _logger.Info("{1} - Responded to a {0} request", dev.Type, endpoint); + } + + private void SendDatagram(IPEndPoint endpoint, string msg, bool sticky) + { + if (_isDisposed) + { + return; + } + //var dgram = new Datagram(endpoint, msg, sticky); + //if (messageQueue.Count == 0) + //{ + // dgram.Send(); + //} + //messageQueue.Enqueue(dgram); + //queueTimer.Enabled = true; + } + + private void NotifyAll() + { + _logger.Debug("NotifyAll"); + foreach (var d in Devices) + { + NotifyDevice(d, "alive", false); + } + } + + private void NotifyDevice(UpnpDevice dev, string type, bool sticky) + { + _logger.Debug("NotifyDevice"); + var headers = new RawHeaders(); + headers.Add("HOST", "239.255.255.250:1900"); + headers.Add("CACHE-CONTROL", "max-age = 600"); + headers.Add("LOCATION", dev.Descriptor.ToString()); + headers.Add("SERVER", _serverSignature); + headers.Add("NTS", "ssdp:" + type); + headers.Add("NT", dev.Type); + headers.Add("USN", dev.USN); + + SendDatagram(_ssdpEndp, String.Format("NOTIFY * HTTP/1.1\r\n{0}\r\n", headers.HeaderBlock), sticky); + _logger.Debug("{0} said {1}", dev.USN, type); + } + + private void RegisterNotification(Guid UUID, Uri Descriptor) + { + List<UpnpDevice> list; + lock (_devices) + { + if (!_devices.TryGetValue(UUID, out list)) + { + _devices.Add(UUID, list = new List<UpnpDevice>()); + } + } + + foreach (var t in new[] { "upnp:rootdevice", "urn:schemas-upnp-org:device:MediaServer:1", "urn:schemas-upnp-org:service:ContentDirectory:1", "uuid:" + UUID }) + { + list.Add(new UpnpDevice(UUID, t, Descriptor)); + } + + NotifyAll(); + _logger.Debug("Registered mount {0}", UUID); + } + + internal void UnregisterNotification(Guid UUID) + { + List<UpnpDevice> dl; + lock (_devices) + { + if (!_devices.TryGetValue(UUID, out dl)) + { + return; + } + _devices.Remove(UUID); + } + foreach (var d in dl) + { + NotifyDevice(d, "byebye", true); + } + _logger.Debug("Unregistered mount {0}", UUID); + } + + public void Dispose() + { + _isDisposed = true; + //while (messageQueue.Count != 0) + //{ + // datagramPosted.WaitOne(); + //} + + _udpClient.DropMulticastGroup(_ssdpIp); + _udpClient.Close(); + + //notificationTimer.Enabled = false; + //queueTimer.Enabled = false; + //notificationTimer.Dispose(); + //queueTimer.Dispose(); + //datagramPosted.Dispose(); + } + } +} diff --git a/MediaBrowser.Dlna/Server/UpnpDevice.cs b/MediaBrowser.Dlna/Server/UpnpDevice.cs new file mode 100644 index 000000000..96e37eb07 --- /dev/null +++ b/MediaBrowser.Dlna/Server/UpnpDevice.cs @@ -0,0 +1,28 @@ +using System; + +namespace MediaBrowser.Dlna.Server +{ + public sealed class UpnpDevice + { + public readonly Uri Descriptor; + public readonly string Type; + public readonly string USN; + public readonly Guid Uuid; + + public UpnpDevice(Guid aUuid, string aType, Uri aDescriptor) + { + Uuid = aUuid; + Type = aType; + Descriptor = aDescriptor; + + if (Type.StartsWith("uuid:")) + { + USN = Type; + } + else + { + USN = String.Format("uuid:{0}::{1}", Uuid.ToString(), Type); + } + } + } +} diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index 91ac67a1f..8de54f34a 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -1030,7 +1030,7 @@ namespace MediaBrowser.Model.ApiClient /// <param name="timer">The timer.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - Task CreateLiveTvTimerAsync(TimerInfoDto timer, CancellationToken cancellationToken); + Task CreateLiveTvTimerAsync(BaseTimerInfoDto timer, CancellationToken cancellationToken); /// <summary> /// Updates the live tv timer asynchronous. diff --git a/MediaBrowser.Model/Configuration/DlnaOptions.cs b/MediaBrowser.Model/Configuration/DlnaOptions.cs index b2503ebc7..00fdaa444 100644 --- a/MediaBrowser.Model/Configuration/DlnaOptions.cs +++ b/MediaBrowser.Model/Configuration/DlnaOptions.cs @@ -4,11 +4,15 @@ namespace MediaBrowser.Model.Configuration public class DlnaOptions { public bool EnablePlayTo { get; set; } - public bool EnablePlayToDebugLogging { get; set; } + public bool EnableServer { get; set; } + public bool EnableDebugLogging { get; set; } + public int ClientDiscoveryIntervalSeconds { get; set; } public DlnaOptions() { EnablePlayTo = true; + EnableServer = true; + ClientDiscoveryIntervalSeconds = 60; } } } diff --git a/MediaBrowser.Model/Dto/StreamOptions.cs b/MediaBrowser.Model/Dto/StreamOptions.cs index 17fd06cb6..c38707e53 100644 --- a/MediaBrowser.Model/Dto/StreamOptions.cs +++ b/MediaBrowser.Model/Dto/StreamOptions.cs @@ -10,7 +10,7 @@ /// Omit to copy /// </summary> /// <value>The video codec.</value> - public VideoCodecs? VideoCodec { get; set; } + public string VideoCodec { get; set; } /// <summary> /// Gets or sets the video bit rate. @@ -113,7 +113,7 @@ /// Omit to copy the original stream /// </summary> /// <value>The audio encoding format.</value> - public AudioCodecs? AudioCodec { get; set; } + public string AudioCodec { get; set; } /// <summary> /// Gets or sets the item id. @@ -158,68 +158,4 @@ /// <value>The device id.</value> public string DeviceId { get; set; } } - - /// <summary> - /// These are the codecs the api is capable of encoding to - /// </summary> - public enum AudioCodecs - { - /// <summary> - /// The aac - /// </summary> - Aac, - /// <summary> - /// The MP3 - /// </summary> - Mp3, - /// <summary> - /// The vorbis - /// </summary> - Vorbis, - /// <summary> - /// The wma - /// </summary> - Wma, - /// <summary> - /// The copy - /// </summary> - Copy - } - - /// <summary> - /// Enum VideoCodecs - /// </summary> - public enum VideoCodecs - { - H263, - - /// <summary> - /// The H264 - /// </summary> - H264, - - /// <summary> - /// The mpeg4 - /// </summary> - Mpeg4, - - /// <summary> - /// The theora - /// </summary> - Theora, - - /// <summary> - /// The VPX - /// </summary> - Vpx, - - /// <summary> - /// The WMV - /// </summary> - Wmv, - /// <summary> - /// The copy - /// </summary> - Copy - } } diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs index 0198cc399..393233c1b 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs @@ -1,81 +1,15 @@ -using System; +using MediaBrowser.Model.Entities; +using System; using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics; using System.Runtime.Serialization; -using MediaBrowser.Model.Entities; namespace MediaBrowser.Model.LiveTv { [DebuggerDisplay("Name = {Name}")] - public class SeriesTimerInfoDto : INotifyPropertyChanged + public class SeriesTimerInfoDto : BaseTimerInfoDto { /// <summary> - /// Id of the recording. - /// </summary> - public string Id { get; set; } - - /// <summary> - /// Gets or sets the external identifier. - /// </summary> - /// <value>The external identifier.</value> - public string ExternalId { get; set; } - - /// <summary> - /// ChannelId of the recording. - /// </summary> - public string ChannelId { get; set; } - - /// <summary> - /// Gets or sets the name of the service. - /// </summary> - /// <value>The name of the service.</value> - public string ServiceName { get; set; } - - /// <summary> - /// Gets or sets the external channel identifier. - /// </summary> - /// <value>The external channel identifier.</value> - public string ExternalChannelId { get; set; } - - /// <summary> - /// ChannelName of the recording. - /// </summary> - public string ChannelName { get; set; } - - /// <summary> - /// Gets or sets the program identifier. - /// </summary> - /// <value>The program identifier.</value> - public string ProgramId { get; set; } - - /// <summary> - /// Gets or sets the external program identifier. - /// </summary> - /// <value>The external program identifier.</value> - public string ExternalProgramId { get; set; } - - /// <summary> - /// Name of the recording. - /// </summary> - public string Name { get; set; } - - /// <summary> - /// Description of the recording. - /// </summary> - public string Overview { get; set; } - - /// <summary> - /// The start date of the recording, in UTC. - /// </summary> - public DateTime StartDate { get; set; } - - /// <summary> - /// The end date of the recording, in UTC. - /// </summary> - public DateTime EndDate { get; set; } - - /// <summary> /// Gets or sets a value indicating whether [record any time]. /// </summary> /// <value><c>true</c> if [record any time]; otherwise, <c>false</c>.</value> @@ -106,36 +40,6 @@ namespace MediaBrowser.Model.LiveTv public DayPattern? DayPattern { get; set; } /// <summary> - /// Gets or sets the priority. - /// </summary> - /// <value>The priority.</value> - public int Priority { get; set; } - - /// <summary> - /// Gets or sets the pre padding seconds. - /// </summary> - /// <value>The pre padding seconds.</value> - public int PrePaddingSeconds { get; set; } - - /// <summary> - /// Gets or sets the post padding seconds. - /// </summary> - /// <value>The post padding seconds.</value> - public int PostPaddingSeconds { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether this instance is pre padding required. - /// </summary> - /// <value><c>true</c> if this instance is pre padding required; otherwise, <c>false</c>.</value> - public bool IsPrePaddingRequired { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether this instance is post padding required. - /// </summary> - /// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value> - public bool IsPostPaddingRequired { get; set; } - - /// <summary> /// Gets or sets the image tags. /// </summary> /// <value>The image tags.</value> @@ -156,7 +60,5 @@ namespace MediaBrowser.Model.LiveTv ImageTags = new Dictionary<ImageType, Guid>(); Days = new List<DayOfWeek>(); } - - public event PropertyChangedEventHandler PropertyChanged; } } diff --git a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs index a330f44d8..137c95719 100644 --- a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs @@ -3,9 +3,48 @@ using System.ComponentModel; namespace MediaBrowser.Model.LiveTv { - public class TimerInfoDto : INotifyPropertyChanged + public class TimerInfoDto : BaseTimerInfoDto { /// <summary> + /// Gets or sets the status. + /// </summary> + /// <value>The status.</value> + public RecordingStatus Status { get; set; } + + /// <summary> + /// Gets or sets the series timer identifier. + /// </summary> + /// <value>The series timer identifier.</value> + public string SeriesTimerId { get; set; } + + /// <summary> + /// Gets or sets the external series timer identifier. + /// </summary> + /// <value>The external series timer identifier.</value> + public string ExternalSeriesTimerId { get; set; } + + /// <summary> + /// Gets or sets the run time ticks. + /// </summary> + /// <value>The run time ticks.</value> + public long? RunTimeTicks { get; set; } + + /// <summary> + /// Gets or sets the program information. + /// </summary> + /// <value>The program information.</value> + public ProgramInfoDto ProgramInfo { get; set; } + + } + + public class BaseTimerInfoDto : INotifyPropertyChanged + { + /// <summary> + /// Occurs when a property value changes. + /// </summary> + public event PropertyChangedEventHandler PropertyChanged; + + /// <summary> /// Id of the recording. /// </summary> public string Id { get; set; } @@ -26,19 +65,13 @@ namespace MediaBrowser.Model.LiveTv /// </summary> /// <value>The external channel identifier.</value> public string ExternalChannelId { get; set; } - + /// <summary> /// ChannelName of the recording. /// </summary> public string ChannelName { get; set; } /// <summary> - /// Gets or sets the name of the service. - /// </summary> - /// <value>The name of the service.</value> - public string ServiceName { get; set; } - - /// <summary> /// Gets or sets the program identifier. /// </summary> /// <value>The program identifier.</value> @@ -49,7 +82,7 @@ namespace MediaBrowser.Model.LiveTv /// </summary> /// <value>The external program identifier.</value> public string ExternalProgramId { get; set; } - + /// <summary> /// Name of the recording. /// </summary> @@ -71,22 +104,16 @@ namespace MediaBrowser.Model.LiveTv public DateTime EndDate { get; set; } /// <summary> - /// Gets or sets the status. - /// </summary> - /// <value>The status.</value> - public RecordingStatus Status { get; set; } - - /// <summary> - /// Gets or sets the series timer identifier. + /// Gets or sets the name of the service. /// </summary> - /// <value>The series timer identifier.</value> - public string SeriesTimerId { get; set; } + /// <value>The name of the service.</value> + public string ServiceName { get; set; } /// <summary> - /// Gets or sets the external series timer identifier. + /// Gets or sets the priority. /// </summary> - /// <value>The external series timer identifier.</value> - public string ExternalSeriesTimerId { get; set; } + /// <value>The priority.</value> + public int Priority { get; set; } /// <summary> /// Gets or sets the pre padding seconds. @@ -111,28 +138,5 @@ namespace MediaBrowser.Model.LiveTv /// </summary> /// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value> public bool IsPostPaddingRequired { get; set; } - - /// <summary> - /// Gets or sets the run time ticks. - /// </summary> - /// <value>The run time ticks.</value> - public long? RunTimeTicks { get; set; } - - /// <summary> - /// Gets or sets the priority. - /// </summary> - /// <value>The priority.</value> - public int Priority { get; set; } - - /// <summary> - /// Gets or sets the program information. - /// </summary> - /// <value>The program information.</value> - public ProgramInfoDto ProgramInfo { get; set; } - - /// <summary> - /// Occurs when a property value changes. - /// </summary> - public event PropertyChangedEventHandler PropertyChanged; } } diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index ad2852a91..098d1295f 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints CreateRules(device); } - catch (Exception ex) + catch (Exception) { //_logger.ErrorException("Error creating port forwarding rules", ex); } diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 879fbc1b6..e49244edf 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -266,7 +266,7 @@ namespace MediaBrowser.ServerApplication { MigrateUserFolders(); } - catch (IOException ex) + catch (IOException) { } @@ -498,7 +498,7 @@ namespace MediaBrowser.ServerApplication var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger); RegisterSingleInstance<IAppThemeManager>(appThemeManager); - var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager); + var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, JsonSerializer); RegisterSingleInstance<IDlnaManager>(dlnaManager); var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor); diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index 765cae612..ea1905bad 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -3809,7 +3809,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi var deferred = $.Deferred(); var msg = [itemId, canSeek, queueableMediaTypes]; - + if (mediaSourceId) { msg.push(mediaSourceId); } @@ -4029,7 +4029,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi self.createPackageReview = function (review) { - var url = self.getUrl("PackageReviews/" + review.id, review); + var url = self.getUrl("Packages/Reviews/" + review.id, review); return self.ajax({ type: "POST", @@ -4058,7 +4058,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi options.ForceTitle = true; } - var url = self.getUrl("PackageReviews/" + packageId, options); + var url = self.getUrl("Packages/" + packageId + "Reviews", options); return self.ajax({ type: "GET", diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 7396527bb..a5074d3c8 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="MediaBrowser.ApiClient.Javascript" version="3.0.247" targetFramework="net45" /> + <package id="MediaBrowser.ApiClient.Javascript" version="3.0.248" targetFramework="net45" /> </packages>
\ No newline at end of file diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 12219e81d..c550b350c 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.343</version> + <version>3.0.345</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.343" /> + <dependency id="MediaBrowser.Common" version="3.0.345" /> <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 495dc3f2b..a6fa5c152 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.343</version> + <version>3.0.345</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 398adc207..cc87b0030 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.343</version> + <version>3.0.345</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.343" /> + <dependency id="MediaBrowser.Common" version="3.0.345" /> </dependencies> </metadata> <files> |
