diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 1e9f2f7a2f..8bc06b6577 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -211,12 +211,7 @@ namespace MediaBrowser.Api private void UpdateItem(BaseItemDto request, BaseItem item) { item.Name = request.Name; - - // Only set the forced value if they changed it, or there's already one - if (!string.Equals(item.SortName, request.SortName) || !string.IsNullOrEmpty(item.ForcedSortName)) - { - item.ForcedSortName = request.SortName; - } + item.ForcedSortName = request.ForcedSortName; var hasBudget = item as IHasBudget; if (hasBudget != null) diff --git a/MediaBrowser.Api/LocalizationService.cs b/MediaBrowser.Api/LocalizationService.cs index b3f6cbd976..60270a3895 100644 --- a/MediaBrowser.Api/LocalizationService.cs +++ b/MediaBrowser.Api/LocalizationService.cs @@ -10,8 +10,7 @@ namespace MediaBrowser.Api /// /// Class GetCultures /// - [Route("/Localization/Cultures", "GET")] - [Api(Description = "Gets known cultures")] + [Route("/Localization/Cultures", "GET", Summary = "Gets known cultures")] public class GetCultures : IReturn> { } @@ -19,8 +18,7 @@ namespace MediaBrowser.Api /// /// Class GetCountries /// - [Route("/Localization/Countries", "GET")] - [Api(Description = "Gets known countries")] + [Route("/Localization/Countries", "GET", Summary = "Gets known countries")] public class GetCountries : IReturn> { } @@ -28,8 +26,7 @@ namespace MediaBrowser.Api /// /// Class ParentalRatings /// - [Route("/Localization/ParentalRatings", "GET")] - [Api(Description = "Gets known parental ratings")] + [Route("/Localization/ParentalRatings", "GET", Summary = "Gets known parental ratings")] public class GetParentalRatings : IReturn> { } diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index f9b7608696..204a7aab45 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().ToList(); + var movies = user.RootFolder.GetRecursiveChildren(user).OfType().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 99a4d4fa7e..6243bf25f4 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> { /// @@ -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 45a16347bc..a71a85395a 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 { [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 { [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 { [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 b2de908d9f..94ff1b62e2 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 { /// /// Class InstallPackage /// - [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 { /// @@ -57,8 +56,7 @@ namespace MediaBrowser.Api /// /// Class InstallPackage /// - [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> { /// @@ -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>(result); diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index 793b666ea0..948a67f16f 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -14,8 +14,7 @@ namespace MediaBrowser.Api /// /// Class GetPackage /// - [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 { /// @@ -36,8 +35,7 @@ namespace MediaBrowser.Api /// /// Class GetPackages /// - [Route("/Packages", "GET")] - [Api(("Gets available packages"))] + [Route("/Packages", "GET", Summary = "Gets available packages")] public class GetPackages : IReturn> { /// @@ -57,8 +55,7 @@ namespace MediaBrowser.Api /// /// Class GetPackageVersionUpdates /// - [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> { /// @@ -72,8 +69,7 @@ namespace MediaBrowser.Api /// /// Class InstallPackage /// - [Route("/Packages/Installed/{Name}", "POST")] - [Api(("Installs a package"))] + [Route("/Packages/Installed/{Name}", "POST", Summary = "Installs a package")] public class InstallPackage : IReturnVoid { /// @@ -108,8 +104,7 @@ namespace MediaBrowser.Api /// /// Class CancelPackageInstallation /// - [Route("/Packages/Installing/{Id}", "DELETE")] - [Api(("Cancels a package installation"))] + [Route("/Packages/Installing/{Id}", "DELETE", Summary = "Cancels a package installation")] public class CancelPackageInstallation : IReturnVoid { /// diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 1001980ec1..7dcb06f7b3 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,16 +734,23 @@ 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"; @@ -1162,18 +1168,23 @@ namespace MediaBrowser.Api.Playback protected double? GetFramerateParam(StreamState state) { - if (state.VideoRequest != null && state.VideoRequest.Framerate.HasValue) + if (state.VideoRequest != null) { - return state.VideoRequest.Framerate.Value; - } - - if (state.VideoStream != null) - { - var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate; - - if (contentRate.HasValue && contentRate.Value > 23.976) + if (state.VideoRequest.Framerate.HasValue) { - return 23.976; + return state.VideoRequest.Framerate.Value; + } + + var maxrate = state.VideoRequest.MaxFramerate ?? 23.976; + + if (state.VideoStream != null) + { + var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate; + + if (contentRate.HasValue && contentRate.Value > maxrate) + { + return maxrate; + } } } @@ -1201,77 +1212,102 @@ 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) { - if (videoRequest != null) - { - videoRequest.VideoCodec = (VideoCodecs)Enum.Parse(typeof(VideoCodecs), val, true); - } + request.MediaSourceId = val; } else if (i == 3) { - request.AudioCodec = (AudioCodecs)Enum.Parse(typeof(AudioCodecs), val, true); + request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); } else if (i == 4) + { + if (videoRequest != null) + { + videoRequest.VideoCodec = val; + } + } + else if (i == 5) + { + request.AudioCodec = val; + } + 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) + { + videoRequest.MaxWidth = int.Parse(val, UsCulture); + } + } + else if (i == 12) + { + if (videoRequest != null) + { + videoRequest.MaxHeight = int.Parse(val, UsCulture); + } + } + else if (i == 13) + { + if (videoRequest != null) + { + videoRequest.Framerate = int.Parse(val, UsCulture); + } + } + else if (i == 14) { if (videoRequest != null) { request.StartTimeTicks = long.Parse(val, UsCulture); } } - else if (i == 10) + else if (i == 15) { if (videoRequest != null) { videoRequest.Profile = val; } } - else if (i == 11) + else if (i == 16) { if (videoRequest != null) { videoRequest.Level = val; } } - else if (i == 12) - { - request.ForcedMimeType = val; - } } } @@ -1297,7 +1333,7 @@ namespace MediaBrowser.Api.Playback var url = Request.PathInfo; - if (!request.AudioCodec.HasValue) + if (string.IsNullOrEmpty(request.AudioCodec)) { request.AudioCodec = InferAudioCodec(url); } @@ -1425,7 +1461,7 @@ namespace MediaBrowser.Api.Playback if (videoRequest != null) { - if (!videoRequest.VideoCodec.HasValue) + if (string.IsNullOrEmpty(videoRequest.VideoCodec)) { videoRequest.VideoCodec = InferVideoCodec(url); } @@ -1532,41 +1568,41 @@ namespace MediaBrowser.Api.Playback /// /// The URL. /// System.Nullable{AudioCodecs}. - 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 +1613,28 @@ namespace MediaBrowser.Api.Playback /// /// The URL. /// System.Nullable{VideoCodecs}. - 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 aec271ff20..eb8f415e0d 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 121957ecc9..66e8b0d149 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 8ae61b5219..9cb989fc21 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)) { - case AudioCodecs.Aac: - return ".aac"; - case AudioCodecs.Mp3: - return ".mp3"; - case AudioCodecs.Vorbis: - return ".ogg"; - case AudioCodecs.Wma: - return ".wma"; + 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)) + { + return ".wma"; } } } diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index df52e5e3ee..8db5920f6b 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 /// /// The audio codec. [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; } /// /// 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; } + /// /// Gets or sets the audio sample rate. /// @@ -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 /// /// The video codec. [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; } /// /// Gets or sets the video bit rate. @@ -145,6 +145,9 @@ namespace MediaBrowser.Api.Playback [ApiMember(Name = "Framerate", Description = "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")] public double? Framerate { get; set; } + [ApiMember(Name = "MaxFramerate", Description = "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")] + public double? MaxFramerate { get; set; } + /// /// Gets or sets the profile. /// diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 88daf9f623..ecc5c93ef2 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 e66f432df8..31463dc3f4 100644 --- a/MediaBrowser.Api/PluginService.cs +++ b/MediaBrowser.Api/PluginService.cs @@ -18,8 +18,7 @@ namespace MediaBrowser.Api /// /// Class Plugins /// - [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> { } @@ -27,8 +26,7 @@ namespace MediaBrowser.Api /// /// Class UninstallPlugin /// - [Route("/Plugins/{Id}", "DELETE")] - [Api(("Uninstalls a plugin"))] + [Route("/Plugins/{Id}", "DELETE", Summary = "Uninstalls a plugin")] public class UninstallPlugin : IReturnVoid { /// @@ -42,8 +40,7 @@ namespace MediaBrowser.Api /// /// Class GetPluginConfiguration /// - [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 { /// @@ -57,8 +54,7 @@ namespace MediaBrowser.Api /// /// Class UpdatePluginConfiguration /// - [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 { /// @@ -78,8 +74,7 @@ namespace MediaBrowser.Api /// /// Class GetPluginSecurityInfo /// - [Route("/Plugins/SecurityInfo", "GET")] - [Api(("Gets plugin registration information"))] + [Route("/Plugins/SecurityInfo", "GET", Summary = "Gets plugin registration information")] public class GetPluginSecurityInfo : IReturn { } @@ -87,14 +82,12 @@ namespace MediaBrowser.Api /// /// Class UpdatePluginSecurityInfo /// - [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 c143635bfa..0d3f5dfcdf 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; + /// /// Gets the data to send. /// @@ -46,7 +48,25 @@ namespace MediaBrowser.Api.ScheduledTasks /// Task{IEnumerable{TaskInfo}}. protected override Task> 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>(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 f46c6b8e30..662c728e46 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 /// /// Class GetSearchHints /// - [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 { /// @@ -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 e73e3490ec..a509c876ce 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -14,8 +14,7 @@ namespace MediaBrowser.Api /// /// Class GetSessions /// - [Route("/Sessions", "GET")] - [Api(("Gets a list of sessions"))] + [Route("/Sessions", "GET", Summary = "Gets a list of sessions")] public class GetSessions : IReturn> { /// @@ -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; } } /// /// Class BrowseTo /// - [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 { /// @@ -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 { /// @@ -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 { /// @@ -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 { /// @@ -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 { /// @@ -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 { /// diff --git a/MediaBrowser.Api/SystemService.cs b/MediaBrowser.Api/SystemService.cs index 9f5f3716ec..2f0741434a 100644 --- a/MediaBrowser.Api/SystemService.cs +++ b/MediaBrowser.Api/SystemService.cs @@ -8,8 +8,7 @@ namespace MediaBrowser.Api /// /// Class GetSystemInfo /// - [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 { @@ -18,18 +17,16 @@ namespace MediaBrowser.Api /// /// Class RestartApplication /// - [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 { } - + /// /// Class SystemInfoService /// diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index a805b7b551..7fa586a7d7 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -17,8 +17,7 @@ namespace MediaBrowser.Api /// /// Class GetNextUpEpisodes /// - [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, IHasItemFields { /// @@ -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, IHasItemFields { /// @@ -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, IHasItemFields { /// @@ -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, IHasItemFields { /// @@ -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 18c3bd0962..2f1b161078 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -17,8 +17,7 @@ namespace MediaBrowser.Api /// /// Class GetUsers /// - [Route("/Users", "GET")] - [Api(Description = "Gets a list of users")] + [Route("/Users", "GET", Summary = "Gets a list of users")] public class GetUsers : IReturn> { [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> { } @@ -37,8 +35,7 @@ namespace MediaBrowser.Api /// /// Class GetUser /// - [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 { /// @@ -52,8 +49,7 @@ namespace MediaBrowser.Api /// /// Class DeleteUser /// - [Route("/Users/{Id}", "DELETE")] - [Api(Description = "Deletes a user")] + [Route("/Users/{Id}", "DELETE", Summary = "Deletes a user")] public class DeleteUser : IReturnVoid { /// @@ -67,8 +63,7 @@ namespace MediaBrowser.Api /// /// Class AuthenticateUser /// - [Route("/Users/{Id}/Authenticate", "POST")] - [Api(Description = "Authenticates a user")] + [Route("/Users/{Id}/Authenticate", "POST", Summary = "Authenticates a user")] public class AuthenticateUser : IReturn { /// @@ -89,8 +84,7 @@ namespace MediaBrowser.Api /// /// Class AuthenticateUser /// - [Route("/Users/AuthenticateByName", "POST")] - [Api(Description = "Authenticates a user")] + [Route("/Users/AuthenticateByName", "POST", Summary = "Authenticates a user")] public class AuthenticateUserByName : IReturn { /// @@ -111,8 +105,7 @@ namespace MediaBrowser.Api /// /// Class UpdateUserPassword /// - [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 { /// @@ -143,8 +136,7 @@ namespace MediaBrowser.Api /// /// Class UpdateUser /// - [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 /// /// Class CreateUser /// - [Route("/Users", "POST")] - [Api(Description = "Creates a user")] + [Route("/Users", "POST", Summary = "Creates a user")] public class CreateUser : UserDto, IReturn { } diff --git a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs index 4ff34cfa12..33d3f368b6 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 /// The type of the T state type. public abstract class BasePeriodicWebSocketListener : IWebSocketListener, IDisposable where TStateType : class, new() + where TReturnDataType : class { /// /// The _active connections @@ -144,12 +145,15 @@ namespace MediaBrowser.Common.Net var data = await GetDataToSend(tuple.Item4).ConfigureAwait(false); - await connection.SendAsync(new WebSocketMessage + if (data != null) { - MessageType = Name, - Data = data + await connection.SendAsync(new WebSocketMessage + { + 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 a4592e654a..2b9a40ea06 100644 --- a/MediaBrowser.Controller/Dlna/CodecProfile.cs +++ b/MediaBrowser.Controller/Dlna/CodecProfile.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace MediaBrowser.Controller.Dlna @@ -6,18 +7,25 @@ namespace MediaBrowser.Controller.Dlna public class CodecProfile { public CodecType Type { get; set; } - public List Conditions { get; set; } + public ProfileCondition[] Conditions { get; set; } public string Codec { get; set; } public CodecProfile() { - Conditions = new List(); + Conditions = new ProfileCondition[] {}; } public List GetCodecs() { return (Codec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); } + + public bool ContainsCodec(string codec) + { + var codecs = GetCodecs(); + + return codecs.Count == 0 || codecs.Contains(codec, StringComparer.OrdinalIgnoreCase); + } } public enum CodecType @@ -57,9 +65,12 @@ namespace MediaBrowser.Controller.Dlna Width, Height, Has64BitOffsets, + VideoBitDepth, VideoBitrate, VideoFramerate, VideoLevel, - VideoProfile + VideoPacketLength, + VideoProfile, + VideoTimestamp } } diff --git a/MediaBrowser.Controller/Dlna/ContainerProfile.cs b/MediaBrowser.Controller/Dlna/ContainerProfile.cs new file mode 100644 index 0000000000..3bd3c9eaf6 --- /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 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 20c94ad50b..461c77537c 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. /// /// The headers. - public List Headers { get; set; } + public HttpHeaderInfo[] Headers { get; set; } public DeviceIdentification() { - Headers = new List(); + 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 49568e7d43..f3de1bc34a 100644 --- a/MediaBrowser.Controller/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Controller/Dlna/DeviceProfile.cs @@ -20,13 +20,15 @@ namespace MediaBrowser.Controller.Dlna /// /// The transcoding profiles. public TranscodingProfile[] TranscodingProfiles { get; set; } - + /// /// Gets or sets the direct play profiles. /// /// The direct play profiles. public DirectPlayProfile[] DirectPlayProfiles { get; set; } + public ContainerProfile[] ContainerProfiles { get; set; } + /// /// Gets or sets the identification. /// @@ -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; } + /// /// Controls the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace. /// @@ -62,13 +67,14 @@ namespace MediaBrowser.Controller.Dlna 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 53d32a2f8d..686b31287e 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 Conditions { get; set; } - - public DirectPlayProfile() + public List GetContainers() { - Conditions = new List(); - - Containers = new string[] { }; + return (Container ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); } public List GetAudioCodecs() diff --git a/MediaBrowser.Controller/Dlna/MediaProfile.cs b/MediaBrowser.Controller/Dlna/MediaProfile.cs index 5fa41b18aa..1d2613face 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 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 1073f74aaf..007cb632e4 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 @@ -15,12 +14,14 @@ namespace MediaBrowser.Controller.Dlna public TranscodeSeekInfo TranscodeSeekInfo { get; set; } - public List Settings { get; set; } + public TranscodingSetting[] Settings { get; set; } public TranscodingProfile() { - Settings = new List(); + Settings = new TranscodingSetting[] { }; } + + public bool EnableMpegtsM2TsMode { get; set; } } public class TranscodingSetting @@ -31,8 +32,7 @@ namespace MediaBrowser.Controller.Dlna public enum TranscodingSettingType { - Profile = 0, - MaxAudioChannels = 1 + VideoProfile = 0 } public enum TranscodeSeekInfo diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index b51824bdb9..5e6297d060 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -79,6 +79,7 @@ + diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index 24e9d83a03..c6da865cd7 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,989 +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 GetProfiles() { - var list = new List(); - - list.Add(new DeviceProfile + var list = new List { - 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", - - 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 List - { - 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 List - { - new TranscodingSetting - { - Name = TranscodingSettingType.MaxAudioChannels, - Value = "6" - } - } - }, - new TranscodingProfile - { - Container = "jpeg", - Type = DlnaProfileType.Photo - } - }, - - DirectPlayProfiles = new[] - { - new DirectPlayProfile - { - Containers = new[]{"avi"}, - VideoCodec = "mpeg4", - AudioCodec = "ac3,mp3", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"avi"}, - VideoCodec = "h264", - AudioCodec = "aac", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"mp4", "mov"}, - VideoCodec = "h264,mpeg4", - AudioCodec = "aac,ac3", - Type = DlnaProfileType.Video, - - Conditions = new List - { - new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.Has64BitOffsets, Value = "false", IsRequired=false} - } - }, - new DirectPlayProfile - { - Containers = new[]{"asf"}, - VideoCodec = "wmv2,wmv3,vc1", - AudioCodec = "wmav2,wmapro", - Type = DlnaProfileType.Video - }, - new DirectPlayProfile - { - Containers = new[]{"asf"}, - AudioCodec = "wmav2,wmapro,wmavoice", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"mp3"}, - AudioCodec = "mp3", - Type = DlnaProfileType.Audio - }, - new DirectPlayProfile - { - Containers = new[]{"jpeg"}, - Type = DlnaProfileType.Photo, - - Conditions = new List - { - 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 ="avi", - MimeType = "video/avi", - Type = DlnaProfileType.Video - } - }, - - CodecProfiles = new[] - { - new CodecProfile - { - Type = CodecType.VideoCodec, - Codec = "mpeg4", - Conditions = new List - { - 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 List - { - 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 List - { - 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 List - { - new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.AudioChannels, Value = "6", IsRequired=false} - } - }, - - new CodecProfile - { - Type = CodecType.VideoAudioCodec, - Codec = "aac", - Conditions = new List - { - new ProfileCondition{ Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.AudioChannels, Value = "6", IsRequired=false}, - new ProfileCondition{ Condition = ProfileConditionType.Equals, Property = ProfileConditionValue.AudioProfile, Value = "lc", IsRequired=false} - } - } - } - }); - - 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 - { - 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 - { - 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 - { - 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 - { - 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 - }, - } - }); + 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; @@ -1003,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) @@ -1046,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 800fb1b236..bea281b614 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -81,7 +81,28 @@ + + + + + + + + + + + + + + + + + + + + + @@ -97,9 +118,7 @@ MediaBrowser.Model - - - +