more support for episodes directly in a series folder

This commit is contained in:
Luke Pulverenti 2013-12-03 23:18:50 -05:00
parent 61a78e2be9
commit 40959a816f
12 changed files with 231 additions and 32 deletions

View File

@ -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

View File

@ -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();

View File

@ -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>

View File

@ -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 };

View File

@ -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>

View File

@ -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>();

View File

@ -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>

View File

@ -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>();

View File

@ -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; }
}
}

View File

@ -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;

View File

@ -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

View File

@ -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));
}
}
}