diff options
Diffstat (limited to 'MediaBrowser.Api')
20 files changed, 234 insertions, 231 deletions
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 1e9f2f7a2..8bc06b657 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 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..7dcb06f7b 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"; @@ -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.VideoRequest.Framerate.HasValue) + { + return state.VideoRequest.Framerate.Value; + } - if (state.VideoStream != null) - { - var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate; + var maxrate = state.VideoRequest.MaxFramerate ?? 23.976; - if (contentRate.HasValue && contentRate.Value > 23.976) + if (state.VideoStream != null) { - return 23.976; + 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) { + 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) + { + 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 /// </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 +1613,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..8db5920f6 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. @@ -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; } + /// <summary> /// Gets or sets the profile. /// </summary> 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> { } |
