diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index ae9c79c0e8..84bd291a4c 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -68,7 +68,7 @@ namespace MediaBrowser.Api.LiveTv [Route("/LiveTv/Recordings/Groups", "GET")] [Api(Description = "Gets live tv recording groups")] - public class GetRecordingGroups : IReturn> + public class GetRecordingGroups : IReturn> { [ApiMember(Name = "UserId", Description = "Optional filter by user and attach user data.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string UserId { get; set; } @@ -208,6 +208,14 @@ namespace MediaBrowser.Api.LiveTv public string Id { get; set; } } + [Route("/LiveTv/Recordings/Groups/{Id}", "GET")] + [Api(Description = "Gets a recording group")] + public class GetRecordingGroup : IReturn + { + [ApiMember(Name = "Id", Description = "Recording group Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } + public class LiveTvService : BaseApiService { private readonly ILiveTvManager _liveTvManager; @@ -427,5 +435,17 @@ namespace MediaBrowser.Api.LiveTv return ToOptimizedResult(result); } + + public object Get(GetRecordingGroup request) + { + var result = _liveTvManager.GetRecordingGroups(new RecordingGroupQuery + { + + }, CancellationToken.None).Result; + + var group = result.Items.FirstOrDefault(i => string.Equals(i.Id, request.Id, StringComparison.OrdinalIgnoreCase)); + + return ToOptimizedResult(group); + } } } \ No newline at end of file diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 999260b8d2..5009addee3 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -677,9 +677,12 @@ namespace MediaBrowser.Api.Playback /// Task. protected async Task StartFfMpeg(StreamState state, string outputPath) { - var parentPath = Path.GetDirectoryName(outputPath); + if (!File.Exists(MediaEncoder.EncoderPath)) + { + throw new InvalidOperationException("ffmpeg was not found at " + MediaEncoder.EncoderPath); + } - Directory.CreateDirectory(parentPath); + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); if (state.IsInputVideo && state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath)) { diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 6144bdd710..8623e2ff6c 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Querying; using System; using System.Collections.Generic; @@ -18,7 +19,7 @@ namespace MediaBrowser.Controller.Entities.Movies } public List LocalTrailerIds { get; set; } - + /// /// Gets or sets the remote trailers. /// @@ -43,5 +44,12 @@ namespace MediaBrowser.Controller.Entities.Movies { return config.BlockUnratedMovies; } + + public override IEnumerable GetChildren(User user, bool includeLinkedChildren) + { + var children = base.GetChildren(user, includeLinkedChildren); + + return LibraryManager.Sort(children, user, new[] { ItemSortBy.ProductionYear, ItemSortBy.PremiereDate, ItemSortBy.SortName }, SortOrder.Ascending); + } } } diff --git a/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs b/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs index 7be1873966..fa4231612b 100644 --- a/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs +++ b/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs @@ -4,9 +4,9 @@ namespace MediaBrowser.Server.Implementations.Drawing { public class PlayedIndicatorDrawer { - private const int IndicatorHeight = 50; - public const int IndicatorWidth = 50; - private const int FontSize = 50; + private const int IndicatorHeight = 40; + public const int IndicatorWidth = 40; + private const int FontSize = 40; private const int OffsetFromTopRightCorner = 10; public void DrawPlayedIndicator(Graphics graphics, Size imageSize) @@ -17,7 +17,7 @@ namespace MediaBrowser.Server.Implementations.Drawing { graphics.FillEllipse(backdroundBrush, x, OffsetFromTopRightCorner, IndicatorWidth, IndicatorHeight); - x = imageSize.Width - 55 - OffsetFromTopRightCorner; + x = imageSize.Width - 45 - OffsetFromTopRightCorner; using (var font = new Font("Webdings", FontSize, FontStyle.Regular, GraphicsUnit.Pixel)) { diff --git a/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs b/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs index 11d812a431..695c6390a7 100644 --- a/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs +++ b/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs @@ -1,16 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; namespace MediaBrowser.Server.Implementations.Drawing { public class UnplayedCountIndicator { - private const int IndicatorHeight = 50; - public const int IndicatorWidth = 50; + private const int IndicatorHeight = 41; + public const int IndicatorWidth = 41; private const int OffsetFromTopRightCorner = 10; public void DrawUnplayedCountIndicator(Graphics graphics, Size imageSize, int count) @@ -23,13 +18,13 @@ namespace MediaBrowser.Server.Implementations.Drawing var text = count.ToString(); - x = imageSize.Width - 50 - OffsetFromTopRightCorner; - var y = OffsetFromTopRightCorner + 7; - var fontSize = 30; + x = imageSize.Width - IndicatorWidth - OffsetFromTopRightCorner; + var y = OffsetFromTopRightCorner + 6; + var fontSize = 24; if (text.Length == 1) { - x += 11; + x += 10; } else if (text.Length == 2) { @@ -37,9 +32,9 @@ namespace MediaBrowser.Server.Implementations.Drawing } else if (text.Length == 3) { - //x += 1; - y += 3; - fontSize = 24; + x += 1; + y += 1; + fontSize = 20; } using (var font = new Font("Sans-Serif", fontSize, FontStyle.Regular, GraphicsUnit.Pixel)) diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs index 187dc19bf8..990b695ae4 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs @@ -863,8 +863,10 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder throw new ArgumentNullException("outputPath"); } + // apply some filters to thumbnail extracted below (below) crop any black lines that we made and get the correct ar then scale to width 600. + // This filter chain may have adverse effects on recorded tv thumbnails if ar changes during presentation ex. commercials @ diff ar var vf = "crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,scale=600:600/dar"; - // apply some filters to thumbnail extracted below (below) crop any black lines that we made and get the correct ar then scale to width 600. This filter chain may have adverse effects on recorded tv thumbnails if ar changes during presentation ex. commercials @ diff ar + if (threedFormat.HasValue) { switch (threedFormat.Value) @@ -888,8 +890,9 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder } } + // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case. var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"thumbnail,{2}\" -f image2 \"{1}\"", inputPath, outputPath, vf) : - string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, outputPath, vf); //use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back jic + string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, outputPath, vf); var probeSize = GetProbeSizeArgument(type); diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index 592cf2bad4..73f0207b8d 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -395,10 +395,10 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi throw new Error("null id"); } - var options = { - + var options = { + }; - + if (userId) { options.userId = userId; } @@ -456,6 +456,21 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi }); }; + self.getLiveTvRecordingGroup = function (id) { + + if (!id) { + throw new Error("null id"); + } + + var url = self.getUrl("LiveTv/Recordings/Groups/" + id); + + return self.ajax({ + type: "GET", + url: url, + dataType: "json" + }); + }; + self.getLiveTvRecording = function (id, userId) { if (!id) { @@ -559,7 +574,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi self.getNewLiveTvTimerDefaults = function (options) { options = options || {}; - + var url = self.getUrl("LiveTv/Timers/Defaults", options); return self.ajax({ diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 7c295df9db..c0e73ca455 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file