Browse Source

more support for episodes directly in a series folder

Luke Pulverenti 11 years ago
parent
commit
40959a816f

+ 33 - 3
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -1,12 +1,12 @@
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Model.LiveTv;
 using MediaBrowser.Model.Querying;
 using ServiceStack.ServiceHost;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
 
 namespace MediaBrowser.Api.LiveTv
 {
@@ -58,6 +58,22 @@ namespace MediaBrowser.Api.LiveTv
         public string ChannelId { get; set; }
     }
 
+    [Route("/LiveTv/Recordings/{Id}", "GET")]
+    [Api(Description = "Gets a live tv recording")]
+    public class GetRecording : IReturn<RecordingInfoDto>
+    {
+        [ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Id { get; set; }
+    }
+
+    [Route("/LiveTv/Timers/{Id}", "GET")]
+    [Api(Description = "Gets a live tv timer")]
+    public class GetTimer : IReturn<TimerInfoDto>
+    {
+        [ApiMember(Name = "Id", Description = "Timer Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Id { get; set; }
+    }
+
     [Route("/LiveTv/Timers", "GET")]
     [Api(Description = "Gets live tv timers")]
     public class GetTimers : IReturn<QueryResult<TimerInfoDto>>
@@ -182,6 +198,20 @@ namespace MediaBrowser.Api.LiveTv
             return ToOptimizedResult(result);
         }
 
+        public object Get(GetRecording request)
+        {
+            var result = _liveTvManager.GetRecording(request.Id, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        public object Get(GetTimer request)
+        {
+            var result = _liveTvManager.GetTimer(request.Id, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
         public object Get(GetTimers request)
         {
             var result = _liveTvManager.GetTimers(new TimerQuery

+ 23 - 2
MediaBrowser.Api/TvShowsService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Dto;
+using MediaBrowser.Api.UserLibrary;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
@@ -89,6 +90,9 @@ namespace MediaBrowser.Api
 
         [ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         public bool? IsVirtualUnaired { get; set; }
+
+        [ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string AdjacentTo { get; set; }
     }
 
     [Route("/Shows/{Id}/Seasons", "GET")]
@@ -120,6 +124,9 @@ namespace MediaBrowser.Api
 
         [ApiMember(Name = "IsVirtualUnaired", Description = "Optional filter by items that are virtual unaired episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         public bool? IsVirtualUnaired { get; set; }
+
+        [ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string AdjacentTo { get; set; }
     }
 
     /// <summary>
@@ -394,6 +401,13 @@ namespace MediaBrowser.Api
             seasons = _libraryManager.Sort(seasons, user, new[] { sortOrder }, SortOrder.Ascending)
                 .Cast<Season>();
 
+            // This must be the last filter
+            if (!string.IsNullOrEmpty(request.AdjacentTo))
+            {
+                seasons = ItemsService.FilterForAdjacency(seasons, request.AdjacentTo)
+                    .Cast<Season>();
+            }
+
             var returnItems = seasons.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
                 .ToArray();
 
@@ -447,7 +461,7 @@ namespace MediaBrowser.Api
 
             if (!string.IsNullOrEmpty(request.SeasonId))
             {
-                var season = _libraryManager.GetItemById(request.Id) as Season;
+                var season = _libraryManager.GetItemById(new Guid(request.SeasonId)) as Season;
 
                 if (season.IndexNumber.HasValue)
                 {
@@ -496,6 +510,13 @@ namespace MediaBrowser.Api
             episodes = _libraryManager.Sort(episodes, user, new[] { sortOrder }, SortOrder.Ascending)
                 .Cast<Episode>();
 
+            // This must be the last filter
+            if (!string.IsNullOrEmpty(request.AdjacentTo))
+            {
+                episodes = ItemsService.FilterForAdjacency(episodes, request.AdjacentTo)
+                    .Cast<Episode>();
+            }
+
             var returnItems = episodes.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
                 .ToArray();
 

+ 31 - 24
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -310,6 +310,12 @@ namespace MediaBrowser.Api.UserLibrary
 
             items = ApplySortOrder(request, items, user, _libraryManager);
 
+            // This must be the last filter
+            if (!string.IsNullOrEmpty(request.AdjacentTo))
+            {
+                items = FilterForAdjacency(items, request.AdjacentTo);
+            }
+
             var itemsArray = items.ToList();
 
             var pagedItems = ApplyPaging(request, itemsArray);
@@ -666,30 +672,6 @@ namespace MediaBrowser.Api.UserLibrary
                 });
             }
 
-            if (!string.IsNullOrEmpty(request.AdjacentTo))
-            {
-                var item = _dtoService.GetItemByDtoId(request.AdjacentTo);
-
-                var allSiblings = item.Parent.GetChildren(user, true).OrderBy(i => i.SortName).ToList();
-
-                var index = allSiblings.IndexOf(item);
-
-                var previousId = Guid.Empty;
-                var nextId = Guid.Empty;
-
-                if (index > 0)
-                {
-                    previousId = allSiblings[index - 1].Id;
-                }
-
-                if (index < allSiblings.Count - 1)
-                {
-                    nextId = allSiblings[index + 1].Id;
-                }
-
-                items = items.Where(i => i.Id == previousId || i.Id == nextId);
-            }
-
             // Min index number
             if (request.MinIndexNumber.HasValue)
             {
@@ -1144,6 +1126,31 @@ namespace MediaBrowser.Api.UserLibrary
             return false;
         }
 
+        internal static IEnumerable<BaseItem> FilterForAdjacency(IEnumerable<BaseItem> items, string adjacentToId)
+        {
+            var list = items.ToList();
+
+            var adjacentToIdGuid = new Guid(adjacentToId);
+            var adjacentToItem = list.FirstOrDefault(i => i.Id == adjacentToIdGuid);
+
+            var index = list.IndexOf(adjacentToItem);
+
+            var previousId = Guid.Empty;
+            var nextId = Guid.Empty;
+
+            if (index > 0)
+            {
+                previousId = list[index - 1].Id;
+            }
+
+            if (index < list.Count - 1)
+            {
+                nextId = list[index + 1].Id;
+            }
+
+            return list.Where(i => i.Id == previousId || i.Id == nextId);
+        }
+
         /// <summary>
         /// Determines whether the specified item has image.
         /// </summary>

+ 36 - 0
MediaBrowser.Controller/Entities/TV/Episode.cs

@@ -235,6 +235,42 @@ namespace MediaBrowser.Controller.Entities.TV
             get { return LocationType == Model.Entities.LocationType.Virtual && IsUnaired; }
         }
 
+        [IgnoreDataMember]
+        public Guid? SeasonId
+        {
+            get
+            {
+                // First see if the parent is a Season
+                var season = Parent as Season;
+
+                if (season != null)
+                {
+                    return season.Id;
+                }
+
+                var seasonNumber = ParentIndexNumber;
+
+                // Parent is a Series
+                if (seasonNumber.HasValue)
+                {
+                    var series = Parent as Series;
+
+                    if (series != null)
+                    {
+                        season = series.Children.OfType<Season>()
+                            .FirstOrDefault(i => i.IndexNumber.HasValue && i.IndexNumber.Value == seasonNumber.Value);
+
+                        if (season != null)
+                        {
+                            return season.Id;
+                        }
+                    }
+                }
+
+                return null;
+            }
+        }
+
         public override IEnumerable<string> GetDeletePaths()
         {
             return new[] { Path };

+ 16 - 0
MediaBrowser.Controller/LiveTv/ILiveTvManager.cs

@@ -51,6 +51,22 @@ namespace MediaBrowser.Controller.LiveTv
         /// <returns>IEnumerable{Channel}.</returns>
         QueryResult<ChannelInfoDto> GetChannels(ChannelQuery query);
 
+        /// <summary>
+        /// Gets the recording.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{RecordingInfoDto}.</returns>
+        Task<RecordingInfoDto> GetRecording(string id, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Gets the timer.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{TimerInfoDto}.</returns>
+        Task<TimerInfoDto> GetTimer(string id, CancellationToken cancellationToken);
+
         /// <summary>
         /// Gets the recordings.
         /// </summary>

+ 19 - 1
MediaBrowser.Controller/LiveTv/RecordingInfo.cs

@@ -20,7 +20,13 @@ namespace MediaBrowser.Controller.LiveTv
         /// ChannelName of the recording.
         /// </summary>
         public string ChannelName { get; set; }
-        
+
+        /// <summary>
+        /// Gets or sets the type of the channel.
+        /// </summary>
+        /// <value>The type of the channel.</value>
+        public ChannelType ChannelType { get; set; }
+     
         /// <summary>
         /// Name of the recording.
         /// </summary>
@@ -76,6 +82,18 @@ namespace MediaBrowser.Controller.LiveTv
         /// <value>The episode title.</value>
         public string EpisodeTitle { get; set; }
 
+        /// <summary>
+        /// Gets or sets the official rating.
+        /// </summary>
+        /// <value>The official rating.</value>
+        public string OfficialRating { get; set; }
+
+        /// <summary>
+        /// Gets or sets the community rating.
+        /// </summary>
+        /// <value>The community rating.</value>
+        public float? CommunityRating { get; set; }
+
         public RecordingInfo()
         {
             Genres = new List<string>();

+ 6 - 0
MediaBrowser.Model/Dto/BaseItemDto.cs

@@ -312,6 +312,12 @@ namespace MediaBrowser.Model.Dto
         /// <value>The series id.</value>
         public string SeriesId { get; set; }
 
+        /// <summary>
+        /// Gets or sets the season identifier.
+        /// </summary>
+        /// <value>The season identifier.</value>
+        public string SeasonId { get; set; }
+        
         /// <summary>
         /// Gets or sets the special feature count.
         /// </summary>

+ 30 - 0
MediaBrowser.Model/LiveTv/RecordingInfoDto.cs

@@ -81,6 +81,36 @@ namespace MediaBrowser.Model.LiveTv
         /// <value>The episode title.</value>
         public string EpisodeTitle { get; set; }
 
+        /// <summary>
+        /// Gets or sets the duration ms.
+        /// </summary>
+        /// <value>The duration ms.</value>
+        public int DurationMs { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type of the media.
+        /// </summary>
+        /// <value>The type of the media.</value>
+        public string MediaType { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type of the channel.
+        /// </summary>
+        /// <value>The type of the channel.</value>
+        public ChannelType ChannelType { get; set; }
+
+        /// <summary>
+        /// Gets or sets the official rating.
+        /// </summary>
+        /// <value>The official rating.</value>
+        public string OfficialRating { get; set; }
+
+        /// <summary>
+        /// Gets or sets the community rating.
+        /// </summary>
+        /// <value>The community rating.</value>
+        public float? CommunityRating { get; set; }
+
         public RecordingInfoDto()
         {
             Genres = new List<string>();

+ 6 - 0
MediaBrowser.Model/LiveTv/TimerInfoDto.cs

@@ -74,5 +74,11 @@ namespace MediaBrowser.Model.LiveTv
         /// </summary>
         /// <value>The post padding seconds.</value>
         public int PostPaddingSeconds { get; set; }
+
+        /// <summary>
+        /// Gets or sets the duration ms.
+        /// </summary>
+        /// <value>The duration ms.</value>
+        public int DurationMs { get; set; }
     }
 }

+ 0 - 1
MediaBrowser.Providers/TV/SeriesPostScanTask.cs

@@ -1,6 +1,5 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Entities;

+ 6 - 0
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -1029,6 +1029,12 @@ namespace MediaBrowser.Server.Implementations.Dto
             {
                 dto.IndexNumberEnd = episode.IndexNumberEnd;
                 dto.SpecialSeasonNumber = episode.AirsAfterSeasonNumber ?? episode.AirsBeforeSeasonNumber;
+
+                var seasonId = episode.SeasonId;
+                if (seasonId.HasValue)
+                {
+                    dto.SeasonId = seasonId.Value.ToString("N");
+                }
             }
 
             // Add SeriesInfo

+ 25 - 1
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -391,9 +391,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 Path = info.Path,
                 Genres = info.Genres,
                 IsRepeat = info.IsRepeat,
-                EpisodeTitle = info.EpisodeTitle
+                EpisodeTitle = info.EpisodeTitle,
+                ChannelType = info.ChannelType,
+                MediaType = info.ChannelType == ChannelType.Radio ? MediaType.Audio : MediaType.Video,
+                CommunityRating = info.CommunityRating,
+                OfficialRating = info.OfficialRating
             };
 
+            var duration = info.EndDate - info.StartDate;
+            dto.DurationMs = Convert.ToInt32(duration.TotalMilliseconds);
+
             if (!string.IsNullOrEmpty(info.ProgramId))
             {
                 dto.ProgramId = GetInternalProgramIdId(service.Name, info.ProgramId).ToString("N");
@@ -510,6 +517,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 PostPaddingSeconds = info.PostPaddingSeconds
             };
 
+            var duration = info.EndDate - info.StartDate;
+            dto.DurationMs = Convert.ToInt32(duration.TotalMilliseconds);
+
             if (!string.IsNullOrEmpty(info.ProgramId))
             {
                 dto.ProgramId = GetInternalProgramIdId(service.Name, info.ProgramId).ToString("N");
@@ -563,5 +573,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
         }
+
+        public async Task<RecordingInfoDto> GetRecording(string id, CancellationToken cancellationToken)
+        {
+            var results = await GetRecordings(new RecordingQuery(), cancellationToken).ConfigureAwait(false);
+
+            return results.Items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.CurrentCulture));
+        }
+
+        public async Task<TimerInfoDto> GetTimer(string id, CancellationToken cancellationToken)
+        {
+            var results = await GetTimers(new TimerQuery(), cancellationToken).ConfigureAwait(false);
+
+            return results.Items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.CurrentCulture));
+        }
     }
 }