diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 5e0bfca97..d06941bb8 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -172,6 +172,9 @@ namespace MediaBrowser.Api.UserLibrary
[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; }
+ [ApiMember(Name = "MinIndexNumber", Description = "Optional filter index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int? MinIndexNumber { get; set; }
+
///
/// Gets the order by.
///
@@ -511,6 +514,12 @@ namespace MediaBrowser.Api.UserLibrary
items = items.Where(i => i.Id == previousId || i.Id == nextId);
}
+ // Min index number
+ if (request.MinIndexNumber.HasValue)
+ {
+ items = items.Where(i => i.IndexNumber.HasValue && i.IndexNumber.Value >= request.MinIndexNumber.Value);
+ }
+
// Min official rating
if (!string.IsNullOrEmpty(request.MinOfficialRating))
{
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index a6c53b4a4..de25651ed 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -1,6 +1,7 @@
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Session;
@@ -325,7 +326,7 @@ namespace MediaBrowser.Api.UserLibrary
/// Class GetSpecialFeatures
///
[Route("/Users/{UserId}/Items/{Id}/SpecialFeatures", "GET")]
- [Api(Description = "Gets special features for a movie")]
+ [Api(Description = "Gets special features for an item")]
public class GetSpecialFeatures : IReturn>
{
///
@@ -404,16 +405,40 @@ namespace MediaBrowser.Api.UserLibrary
// Get everything
var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
- var movie = (Movie)item;
-
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
- var tasks = movie.SpecialFeatureIds
- .Select(_itemRepo.RetrieveItem)
- .OrderBy(i => i.SortName)
- .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user, movie));
+ var movie = item as Movie;
- return Task.WhenAll(tasks);
+ // Get them from the db
+ if (movie != null)
+ {
+ // Avoid implicitly captured closure
+ var movie1 = movie;
+
+ var tasks = movie.SpecialFeatureIds
+ .Select(_itemRepo.RetrieveItem)
+ .OrderBy(i => i.SortName)
+ .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user, movie1));
+
+ return Task.WhenAll(tasks);
+ }
+
+ var series = item as Series;
+
+ // Get them from the child tree
+ if (series != null)
+ {
+ var tasks = series
+ .RecursiveChildren
+ .OfType()
+ .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
+ .OrderBy(i => i.SortName)
+ .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user));
+
+ return Task.WhenAll(tasks);
+ }
+
+ throw new ArgumentException("The item does not support special features");
}
///
@@ -589,7 +614,7 @@ namespace MediaBrowser.Api.UserLibrary
return DtoBuilder.GetUserItemDataDto(data);
}
-
+
///
/// Posts the specified request.
///
diff --git a/MediaBrowser.Controller/Dto/DtoBuilder.cs b/MediaBrowser.Controller/Dto/DtoBuilder.cs
index ea994e103..f762c7cc6 100644
--- a/MediaBrowser.Controller/Dto/DtoBuilder.cs
+++ b/MediaBrowser.Controller/Dto/DtoBuilder.cs
@@ -108,7 +108,7 @@ namespace MediaBrowser.Controller.Dto
.Select(i => i.ToString("N"))
.ToArray();
}
-
+
// Make sure all the tasks we kicked off have completed.
if (tasks.Count > 0)
{
@@ -532,6 +532,10 @@ namespace MediaBrowser.Controller.Dto
dto.AirDays = series.AirDays;
dto.AirTime = series.AirTime;
dto.Status = series.Status;
+
+ dto.SpecialFeatureCount = series.SpecialFeatureIds.Count;
+
+ dto.SeasonCount = series.SeasonCount;
}
if (episode != null)
@@ -579,7 +583,7 @@ namespace MediaBrowser.Controller.Dto
{
dto.SeriesName = item.SeriesName;
}
-
+
private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item)
{
if (!string.IsNullOrEmpty(item.Album))
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 2458e5619..1e4d56e1a 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -13,9 +13,15 @@ namespace MediaBrowser.Controller.Entities.TV
///
public class Series : Folder
{
+ public List SpecialFeatureIds { get; set; }
+
+ public int SeasonCount { get; set; }
+
public Series()
{
AirDays = new List();
+
+ SpecialFeatureIds = new List();
}
///
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index fa9ed2536..b843465df 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -138,6 +138,8 @@ namespace MediaBrowser.Model.Dto
/// The production year.
public int? ProductionYear { get; set; }
+ public int? SeasonCount { get; set; }
+
///
/// Gets or sets the players supported by a game.
///
diff --git a/MediaBrowser.Model/Querying/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs
index 18b263960..fe9848513 100644
--- a/MediaBrowser.Model/Querying/ItemQuery.cs
+++ b/MediaBrowser.Model/Querying/ItemQuery.cs
@@ -176,6 +176,8 @@ namespace MediaBrowser.Model.Querying
/// The max official rating.
public string MaxOfficialRating { get; set; }
+ public int? MinIndexNumber { get; set; }
+
///
/// Initializes a new instance of the class.
///
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 761cdccbe..9d0739494 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -107,6 +107,7 @@
+
diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
new file mode 100644
index 000000000..a781551de
--- /dev/null
+++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs
@@ -0,0 +1,64 @@
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Providers.TV
+{
+ class SeriesPostScanTask : ILibraryPostScanTask
+ {
+ ///
+ /// The _library manager
+ ///
+ private readonly ILibraryManager _libraryManager;
+
+ public SeriesPostScanTask(ILibraryManager libraryManager)
+ {
+ _libraryManager = libraryManager;
+ }
+
+ public Task Run(IProgress progress, CancellationToken cancellationToken)
+ {
+ return Task.Run(() => RunInternal(progress, cancellationToken));
+ }
+
+ private void RunInternal(IProgress progress, CancellationToken cancellationToken)
+ {
+ var seriesList = _libraryManager.RootFolder
+ .RecursiveChildren
+ .OfType()
+ .ToList();
+
+ var numComplete = 0;
+
+ foreach (var series in seriesList)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var episodes = series.RecursiveChildren
+ .OfType()
+ .ToList();
+
+ series.SpecialFeatureIds = episodes
+ .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == 0)
+ .Select(i => i.Id)
+ .ToList();
+
+ series.SeasonCount = episodes
+ .Select(i => i.ParentIndexNumber ?? 0)
+ .Where(i => i != 0)
+ .Distinct()
+ .Count();
+
+ numComplete++;
+ double percent = numComplete;
+ percent /= seriesList.Count;
+ percent *= 100;
+
+ progress.Report(percent);
+ }
+ }
+ }
+}