aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/Channels/Channel.cs30
-rw-r--r--MediaBrowser.Controller/Channels/ChannelFolderItem.cs30
-rw-r--r--MediaBrowser.Controller/Channels/ChannelVideoItem.cs2
-rw-r--r--MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs4
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs30
-rw-r--r--MediaBrowser.Controller/Entities/UserItemsQuery.cs35
-rw-r--r--MediaBrowser.Controller/Entities/UserRootFolder.cs13
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs80
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs614
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs9
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj5
-rw-r--r--MediaBrowser.Controller/TV/ITVSeriesManager.cs24
13 files changed, 812 insertions, 66 deletions
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index df38259b4..602918b19 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -1,6 +1,10 @@
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Channels;
+using MediaBrowser.Model.Querying;
using System;
using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
namespace MediaBrowser.Controller.Channels
{
@@ -17,5 +21,31 @@ namespace MediaBrowser.Controller.Channels
return base.IsVisible(user);
}
+
+ public override async Task<QueryResult<BaseItem>> GetUserItems(UserItemsQuery query)
+ {
+ try
+ {
+ // Don't blow up here because it could cause parent screens with other content to fail
+ return await ChannelManager.GetChannelItemsInternal(new ChannelItemQuery
+ {
+ ChannelId = Id.ToString("N"),
+ Limit = query.Limit,
+ StartIndex = query.StartIndex,
+ UserId = query.User.Id.ToString("N"),
+ SortBy = query.SortBy,
+ SortOrder = query.SortOrder
+
+ }, CancellationToken.None);
+ }
+ catch
+ {
+ // Already logged at lower levels
+ return new QueryResult<BaseItem>
+ {
+
+ };
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
index 077138f3c..a7cc80104 100644
--- a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs
@@ -1,6 +1,9 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Querying;
+using System.Threading;
+using System.Threading.Tasks;
namespace MediaBrowser.Controller.Channels
{
@@ -33,5 +36,32 @@ namespace MediaBrowser.Controller.Channels
{
return ExternalId;
}
+
+ public override async Task<QueryResult<BaseItem>> GetUserItems(UserItemsQuery query)
+ {
+ try
+ {
+ // Don't blow up here because it could cause parent screens with other content to fail
+ return await ChannelManager.GetChannelItemsInternal(new ChannelItemQuery
+ {
+ ChannelId = ChannelId,
+ FolderId = Id.ToString("N"),
+ Limit = query.Limit,
+ StartIndex = query.StartIndex,
+ UserId = query.User.Id.ToString("N"),
+ SortBy = query.SortBy,
+ SortOrder = query.SortOrder
+
+ }, CancellationToken.None);
+ }
+ catch
+ {
+ // Already logged at lower levels
+ return new QueryResult<BaseItem>
+ {
+
+ };
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
index 7a261bc58..10e486e71 100644
--- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
@@ -11,8 +11,6 @@ namespace MediaBrowser.Controller.Channels
{
public class ChannelVideoItem : Video, IChannelMediaItem
{
- public static IChannelManager ChannelManager { get; set; }
-
public string ExternalId { get; set; }
public string ChannelId { get; set; }
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index f4a76be00..fbbf21797 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Drawing
public int? UnplayedCount { get; set; }
- public double? PercentPlayed { get; set; }
+ public double PercentPlayed { get; set; }
public string BackgroundColor { get; set; }
@@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.Drawing
return (!Quality.HasValue || Quality.Value == 100) &&
IsOutputFormatDefault(originalImagePath) &&
!AddPlayedIndicator &&
- !PercentPlayed.HasValue &&
+ PercentPlayed.Equals(0) &&
!UnplayedCount.HasValue &&
string.IsNullOrEmpty(BackgroundColor);
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 26b28ec72..3830fa1c1 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
@@ -240,6 +241,7 @@ namespace MediaBrowser.Controller.Entities
public static IFileSystem FileSystem { get; set; }
public static IUserDataManager UserDataManager { get; set; }
public static ILiveTvManager LiveTvManager { get; set; }
+ public static IChannelManager ChannelManager { get; set; }
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 356f2b603..3907217be 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -6,6 +6,8 @@ using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
+using MoreLinq;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -14,7 +16,6 @@ using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
-using MoreLinq;
namespace MediaBrowser.Controller.Entities
{
@@ -24,6 +25,7 @@ namespace MediaBrowser.Controller.Entities
public class Folder : BaseItem, IHasThemeMedia, IHasTags
{
public static IUserManager UserManager { get; set; }
+ public static IUserViewManager UserViewManager { get; set; }
public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { get; set; }
@@ -770,6 +772,24 @@ namespace MediaBrowser.Controller.Entities
return item;
}
+ public virtual Task<QueryResult<BaseItem>> GetUserItems(UserItemsQuery query)
+ {
+ var user = query.User;
+
+ var items = query.Recursive
+ ? GetRecursiveChildren(user)
+ : GetChildren(user, true);
+
+ var result = SortAndFilter(items, query);
+
+ return Task.FromResult(result);
+ }
+
+ protected QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items, UserItemsQuery query)
+ {
+ return UserViewBuilder.SortAndFilter(items, null, query, LibraryManager, UserDataManager);
+ }
+
/// <summary>
/// Gets allowed children of an item
/// </summary>
@@ -944,7 +964,7 @@ namespace MediaBrowser.Controller.Entities
.OfType<CollectionFolder>()
.SelectMany(i => i.PhysicalLocations)
.ToList();
-
+
return LinkedChildren
.Select(i =>
{
@@ -985,10 +1005,10 @@ namespace MediaBrowser.Controller.Entities
/// Gets the linked children.
/// </summary>
/// <returns>IEnumerable{BaseItem}.</returns>
- public IEnumerable<Tuple<LinkedChild,BaseItem>> GetLinkedChildrenInfos()
+ public IEnumerable<Tuple<LinkedChild, BaseItem>> GetLinkedChildrenInfos()
{
return LinkedChildren
- .Select(i => new Tuple<LinkedChild,BaseItem>(i, GetLinkedChild(i)))
+ .Select(i => new Tuple<LinkedChild, BaseItem>(i, GetLinkedChild(i)))
.Where(i => i.Item2 != null);
}
@@ -1183,7 +1203,7 @@ namespace MediaBrowser.Controller.Entities
var isUnplayed = true;
var itemUserData = UserDataManager.GetUserData(user.Id, child.GetUserDataKey());
-
+
// Incrememt totalPercentPlayed
if (itemUserData != null)
{
diff --git a/MediaBrowser.Controller/Entities/UserItemsQuery.cs b/MediaBrowser.Controller/Entities/UserItemsQuery.cs
new file mode 100644
index 000000000..ca1c0115d
--- /dev/null
+++ b/MediaBrowser.Controller/Entities/UserItemsQuery.cs
@@ -0,0 +1,35 @@
+using MediaBrowser.Model.Entities;
+using System;
+
+namespace MediaBrowser.Controller.Entities
+{
+ public class UserItemsQuery
+ {
+ public bool Recursive { get; set; }
+
+ public int? StartIndex { get; set; }
+
+ public int? Limit { get; set; }
+
+ public string[] SortBy { get; set; }
+
+ public SortOrder SortOrder { get; set; }
+
+ public User User { get; set; }
+
+ public Func<BaseItem, User, bool> Filter { get; set; }
+
+ public bool? IsFolder { get; set; }
+ public bool? IsFavorite { get; set; }
+ public bool? IsPlayed { get; set; }
+ public bool? IsResumable { get; set; }
+
+ public string[] MediaTypes { get; set; }
+
+ public UserItemsQuery()
+ {
+ SortBy = new string[] { };
+ MediaTypes = new string[] { };
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs
index 6404e71ec..5c7cb7e23 100644
--- a/MediaBrowser.Controller/Entities/UserRootFolder.cs
+++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs
@@ -1,5 +1,7 @@
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Library;
+using MediaBrowser.Model.Querying;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -14,6 +16,17 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class UserRootFolder : Folder
{
+ public override async Task<QueryResult<BaseItem>> GetUserItems(UserItemsQuery query)
+ {
+ var result = await UserViewManager.GetUserViews(new UserViewQuery
+ {
+ UserId = query.User.Id.ToString("N")
+
+ }, CancellationToken.None).ConfigureAwait(false);
+
+ return SortAndFilter(result, query);
+ }
+
/// <summary>
/// Get the children of this folder from the actual file system
/// </summary>
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index 2abc71752..9b26ce23c 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -1,12 +1,9 @@
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.LiveTv;
+using MediaBrowser.Model.Querying;
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Entities
@@ -14,56 +11,37 @@ namespace MediaBrowser.Controller.Entities
public class UserView : Folder
{
public string ViewType { get; set; }
- public static IUserViewManager UserViewManager { get; set; }
+ public Guid ParentId { get; set; }
- public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
+ public static ITVSeriesManager TVSeriesManager;
+
+ public override Task<QueryResult<BaseItem>> GetUserItems(UserItemsQuery query)
{
- var mediaFolders = GetMediaFolders(user);
+ return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager)
+ .GetUserItems(this, ViewType, query);
+ }
- switch (ViewType)
+ public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
+ {
+ var result = GetUserItems(new UserItemsQuery
{
- case CollectionType.LiveTvChannels:
- return LiveTvManager.GetInternalChannels(new LiveTvChannelQuery
- {
- UserId = user.Id.ToString("N")
-
- }, CancellationToken.None).Result.Items;
- case CollectionType.LiveTvRecordingGroups:
- return LiveTvManager.GetInternalRecordings(new RecordingQuery
- {
- UserId = user.Id.ToString("N"),
- Status = RecordingStatus.Completed
-
- }, CancellationToken.None).Result.Items;
- case CollectionType.LiveTv:
- return GetLiveTvFolders(user).Result;
- case CollectionType.Folders:
- return user.RootFolder.GetChildren(user, includeLinkedChildren);
- case CollectionType.Games:
- return mediaFolders.SelectMany(i => i.GetRecursiveChildren(user, includeLinkedChildren))
- .OfType<GameSystem>();
- case CollectionType.BoxSets:
- return mediaFolders.SelectMany(i => i.GetRecursiveChildren(user, includeLinkedChildren))
- .OfType<BoxSet>();
- case CollectionType.TvShows:
- return mediaFolders.SelectMany(i => i.GetRecursiveChildren(user, includeLinkedChildren))
- .OfType<Series>();
- case CollectionType.Trailers:
- return mediaFolders.SelectMany(i => i.GetRecursiveChildren(user, includeLinkedChildren))
- .OfType<Trailer>();
- default:
- return mediaFolders.SelectMany(i => i.GetChildren(user, includeLinkedChildren));
- }
+ User = user
+
+ }).Result;
+
+ return result.Items;
}
- private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user)
+ public override IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true)
{
- var list = new List<BaseItem>();
+ var result = GetUserItems(new UserItemsQuery
+ {
+ User = user,
+ Recursive = true
- list.Add(await UserViewManager.GetUserView(CollectionType.LiveTvChannels, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
- list.Add(await UserViewManager.GetUserView(CollectionType.LiveTvRecordingGroups, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
+ }).Result;
- return list;
+ return result.Items;
}
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
@@ -71,16 +49,6 @@ namespace MediaBrowser.Controller.Entities
return GetChildren(user, false);
}
- private IEnumerable<Folder> GetMediaFolders(User user)
- {
- var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
-
- return user.RootFolder
- .GetChildren(user, true, true)
- .OfType<Folder>()
- .Where(i => !excludeFolderIds.Contains(i.Id) && !IsExcludedFromGrouping(i));
- }
-
public static bool IsExcludedFromGrouping(Folder folder)
{
var standaloneTypes = new List<string>
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
new file mode 100644
index 000000000..f11ac70ca
--- /dev/null
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -0,0 +1,614 @@
+using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.TV;
+using MediaBrowser.Model.Channels;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.LiveTv;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Querying;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Entities
+{
+ public class UserViewBuilder
+ {
+ private readonly IChannelManager _channelManager;
+ private readonly ILiveTvManager _liveTvManager;
+ private readonly IUserViewManager _userViewManager;
+ private readonly ILibraryManager _libraryManager;
+ private readonly ILogger _logger;
+ private readonly IUserDataManager _userDataManager;
+ private readonly ITVSeriesManager _tvSeriesManager;
+
+ public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager)
+ {
+ _userViewManager = userViewManager;
+ _liveTvManager = liveTvManager;
+ _channelManager = channelManager;
+ _libraryManager = libraryManager;
+ _logger = logger;
+ _userDataManager = userDataManager;
+ _tvSeriesManager = tvSeriesManager;
+ }
+
+ public async Task<QueryResult<BaseItem>> GetUserItems(Folder parent, string viewType, UserItemsQuery query)
+ {
+ var user = query.User;
+
+ switch (viewType)
+ {
+ case CollectionType.Channels:
+ {
+ var result = await _channelManager.GetChannelsInternal(new ChannelQuery
+ {
+ UserId = user.Id.ToString("N"),
+ Limit = query.Limit,
+ StartIndex = query.StartIndex
+
+ }, CancellationToken.None).ConfigureAwait(false);
+
+ return GetResult(result);
+ }
+
+ case CollectionType.LiveTvChannels:
+ {
+ var result = await _liveTvManager.GetInternalChannels(new LiveTvChannelQuery
+ {
+ UserId = query.User.Id.ToString("N"),
+ Limit = query.Limit,
+ StartIndex = query.StartIndex
+
+ }, CancellationToken.None).ConfigureAwait(false);
+
+ return GetResult(result);
+ }
+
+ case CollectionType.LiveTvNowPlaying:
+ {
+ var result = await _liveTvManager.GetRecommendedProgramsInternal(new RecommendedProgramQuery
+ {
+ UserId = query.User.Id.ToString("N"),
+ Limit = query.Limit,
+ IsAiring = true
+
+ }, CancellationToken.None).ConfigureAwait(false);
+
+ return GetResult(result);
+ }
+
+ case CollectionType.LiveTvRecordingGroups:
+ {
+ var result = await _liveTvManager.GetInternalRecordings(new RecordingQuery
+ {
+ UserId = query.User.Id.ToString("N"),
+ Status = RecordingStatus.Completed,
+ Limit = query.Limit,
+ StartIndex = query.StartIndex
+
+ }, CancellationToken.None).ConfigureAwait(false);
+
+ return GetResult(result);
+ }
+
+ case CollectionType.LiveTv:
+ {
+ var result = await GetLiveTvFolders(user).ConfigureAwait(false);
+
+ return GetResult(result, query);
+ }
+
+ case CollectionType.Folders:
+ return GetResult(user.RootFolder.GetChildren(user, true), query);
+
+ case CollectionType.Games:
+ return await GetGameView(user, parent, query).ConfigureAwait(false);
+
+ case CollectionType.BoxSets:
+ return GetResult(GetMediaFolders(user).SelectMany(i => i.GetRecursiveChildren(user)).OfType<BoxSet>(), query);
+
+ case CollectionType.TvShows:
+ return await GetTvView(parent, user, query).ConfigureAwait(false);
+
+ case CollectionType.Music:
+ return await GetMusicFolders(parent, user, query).ConfigureAwait(false);
+
+ case CollectionType.Movies:
+ return await GetMovieFolders(parent, user, query).ConfigureAwait(false);
+
+ case CollectionType.GameGenres:
+ return GetGameGenres(parent, user, query);
+
+ case CollectionType.GameSystems:
+ return GetGameSystems(parent, user, query);
+
+ case CollectionType.LatestGames:
+ return GetLatestGames(parent, user, query);
+
+ case CollectionType.RecentlyPlayedGames:
+ return GetRecentlyPlayedGames(parent, user, query);
+
+ case CollectionType.GameFavorites:
+ return GetFavoriteGames(parent, user, query);
+
+ case CollectionType.TvSeries:
+ return GetTvSeries(parent, user, query);
+
+ case CollectionType.TvGenres:
+ return GetTvGenres(parent, user, query);
+
+ case CollectionType.TvResume:
+ return GetTvResume(parent, user, query);
+
+ case CollectionType.TvNextUp:
+ return GetTvNextUp(parent, query);
+
+ case CollectionType.TvLatest:
+ return GetTvLatest(parent, user, query);
+
+ case CollectionType.MovieFavorites:
+ return GetFavoriteMovies(parent, user, query);
+
+ case CollectionType.MovieLatest:
+ return GetMovieLatest(parent, user, query);
+
+ case CollectionType.MovieGenres:
+ return GetMovieGenres(parent, user, query);
+
+ case CollectionType.MovieResume:
+ return GetMovieResume(parent, user, query);
+
+ case CollectionType.MovieMovies:
+ return GetMovieMovies(parent, user, query);
+
+ case CollectionType.MovieCollections:
+ return GetMovieCollections(parent, user, query);
+
+ default:
+ return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), query);
+ }
+ }
+
+ private int GetSpecialItemsLimit()
+ {
+ return 50;
+ }
+
+ private async Task<QueryResult<BaseItem>> GetMusicFolders(Folder parent, User user, UserItemsQuery query)
+ {
+ if (query.Recursive)
+ {
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }), query);
+ }
+
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).OfType<MusicArtist>(), query);
+ }
+
+ private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, UserItemsQuery query)
+ {
+ if (query.Recursive)
+ {
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie || i is BoxSet), query);
+ }
+
+ var list = new List<BaseItem>();
+
+ list.Add(await GetUserView(CollectionType.MovieResume, user, "0", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.MovieLatest, user, "1", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.MovieMovies, user, "2", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.MovieCollections, user, "3", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.MovieFavorites, user, "4", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.MovieGenres, user, "5", parent).ConfigureAwait(false));
+
+ return GetResult(list, query);
+ }
+
+ private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, UserItemsQuery query)
+ {
+ query.IsFavorite = true;
+
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query);
+ }
+
+ private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, UserItemsQuery query)
+ {
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query);
+ }
+
+ private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, UserItemsQuery query)
+ {
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is BoxSet), query);
+ }
+
+ private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, UserItemsQuery query)
+ {
+ query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
+ query.SortOrder = SortOrder.Descending;
+
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query);
+ }
+
+ private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, UserItemsQuery query)
+ {
+ query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
+ query.SortOrder = SortOrder.Descending;
+ query.IsResumable = true;
+
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query);
+ }
+
+ private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, UserItemsQuery query)
+ {
+ var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty })
+ .Where(i => i is Movie)
+ .SelectMany(i => i.Genres)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .Select(i =>
+ {
+ try
+ {
+ return _libraryManager.GetGenre(i);
+ }
+ catch
+ {
+ // Full exception logged at lower levels
+ _logger.Error("Error getting genre");
+ return null;
+ }
+
+ })
+ .Where(i => i != null);
+
+ return GetResult(genres, query);
+ }
+
+ private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, UserItemsQuery query)
+ {
+ if (query.Recursive)
+ {
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series || i is Season || i is Episode), query);
+ }
+
+ var list = new List<BaseItem>();
+
+ list.Add(await GetUserView(CollectionType.TvResume, user, "0", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.TvNextUp, user, "1", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.TvLatest, user, "2", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.TvSeries, user, "3", parent).ConfigureAwait(false));
+ //list.Add(await GetUserView(CollectionType.TvFavorites, user, "4", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.TvGenres, user, "5", parent).ConfigureAwait(false));
+
+ return GetResult(list, query);
+ }
+
+ private async Task<QueryResult<BaseItem>> GetGameView(User user, Folder parent, UserItemsQuery query)
+ {
+ if (query.Recursive)
+ {
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }), query);
+ }
+
+ var list = new List<BaseItem>();
+
+ list.Add(await GetUserView(CollectionType.LatestGames, user, "0", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.RecentlyPlayedGames, user, "1", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.GameFavorites, user, "2", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.GameSystems, user, "3", parent).ConfigureAwait(false));
+ list.Add(await GetUserView(CollectionType.GameGenres, user, "4", parent).ConfigureAwait(false));
+
+ return GetResult(list, query);
+ }
+
+ private QueryResult<BaseItem> GetLatestGames(Folder parent, User user, UserItemsQuery query)
+ {
+ query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
+ query.SortOrder = SortOrder.Descending;
+
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query);
+ }
+
+ private QueryResult<BaseItem> GetRecentlyPlayedGames(Folder parent, User user, UserItemsQuery query)
+ {
+ query.IsPlayed = true;
+ query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
+ query.SortOrder = SortOrder.Descending;
+
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query);
+ }
+
+ private QueryResult<BaseItem> GetFavoriteGames(Folder parent, User user, UserItemsQuery query)
+ {
+ query.IsFavorite = true;
+
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), query);
+ }
+
+ private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, UserItemsQuery query)
+ {
+ query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
+ query.SortOrder = SortOrder.Descending;
+
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query);
+ }
+
+ private QueryResult<BaseItem> GetTvNextUp(Folder parent, UserItemsQuery query)
+ {
+ var parentFolders = GetMediaFolders(parent, query.User, new[] { CollectionType.TvShows, string.Empty });
+
+ var result = _tvSeriesManager.GetNextUp(new NextUpQuery
+ {
+ Limit = query.Limit,
+ StartIndex = query.StartIndex,
+ UserId = query.User.Id.ToString("N")
+
+ }, parentFolders);
+
+ return result;
+ }
+
+ private QueryResult<BaseItem> GetTvResume(Folder parent, User user, UserItemsQuery query)
+ {
+ query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
+ query.SortOrder = SortOrder.Descending;
+ query.IsResumable = true;
+
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query);
+ }
+
+ private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, UserItemsQuery query)
+ {
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Series>(), query);
+ }
+
+ private QueryResult<BaseItem> GetTvGenres(Folder parent, User user, UserItemsQuery query)
+ {
+ var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty })
+ .OfType<Series>()
+ .SelectMany(i => i.Genres)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .Select(i =>
+ {
+ try
+ {
+ return _libraryManager.GetGenre(i);
+ }
+ catch
+ {
+ // Full exception logged at lower levels
+ _logger.Error("Error getting genre");
+ return null;
+ }
+
+ })
+ .Where(i => i != null);
+
+ return GetResult(genres, query);
+ }
+
+ private QueryResult<BaseItem> GetGameSystems(Folder parent, User user, UserItemsQuery query)
+ {
+ return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<GameSystem>(), query);
+ }
+
+ private QueryResult<BaseItem> GetGameGenres(Folder parent, User user, UserItemsQuery query)
+ {
+ var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Games })
+ .OfType<Game>()
+ .SelectMany(i => i.Genres)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .Select(i =>
+ {
+ try
+ {
+ return _libraryManager.GetGameGenre(i);
+ }
+ catch
+ {
+ // Full exception logged at lower levels
+ _logger.Error("Error getting game genre");
+ return null;
+ }
+
+ })
+ .Where(i => i != null);
+
+ return GetResult(genres, query);
+ }
+
+ private QueryResult<BaseItem> GetResult<T>(QueryResult<T> result)
+ where T : BaseItem
+ {
+ return new QueryResult<BaseItem>
+ {
+ Items = result.Items,
+ TotalRecordCount = result.TotalRecordCount
+ };
+ }
+
+ private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
+ UserItemsQuery query)
+ where T : BaseItem
+ {
+ return GetResult(items, null, query);
+ }
+
+ private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
+ int? totalRecordLimit,
+ UserItemsQuery query)
+ where T : BaseItem
+ {
+ return SortAndFilter(items, totalRecordLimit, query, _libraryManager, _userDataManager);
+ }
+
+ public static QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items,
+ int? totalRecordLimit,
+ UserItemsQuery query,
+ ILibraryManager libraryManager,
+ IUserDataManager userDataManager)
+ {
+ var user = query.User;
+
+ items = items.Where(i => Filter(i, user, query, userDataManager));
+
+ return Sort(items, totalRecordLimit, query, libraryManager);
+ }
+
+ public static QueryResult<BaseItem> Sort(IEnumerable<BaseItem> items,
+ int? totalRecordLimit,
+ UserItemsQuery query,
+ ILibraryManager libraryManager)
+ {
+ var user = query.User;
+
+ items = libraryManager.ReplaceVideosWithPrimaryVersions(items);
+
+ if (query.SortBy.Length > 0)
+ {
+ items = libraryManager.Sort(items, user, query.SortBy, query.SortOrder);
+ }
+
+ var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
+ var totalCount = itemsArray.Length;
+
+ if (query.Limit.HasValue)
+ {
+ itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
+ }
+ else if (query.StartIndex.HasValue)
+ {
+ itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
+ }
+
+ return new QueryResult<BaseItem>
+ {
+ TotalRecordCount = totalCount,
+ Items = itemsArray
+ };
+ }
+
+ private static bool Filter(BaseItem item, User user, UserItemsQuery query, IUserDataManager userDataManager)
+ {
+ if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
+ {
+ return false;
+ }
+
+ if (query.Filter != null && !query.Filter(item, user))
+ {
+ return false;
+ }
+
+ UserItemData userData = null;
+
+ if (query.IsFavorite.HasValue)
+ {
+ userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+
+ if (userData.IsFavorite != query.IsFavorite.Value)
+ {
+ return false;
+ }
+ }
+
+ if (query.IsResumable.HasValue)
+ {
+ userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
+ var isResumable = userData.PlaybackPositionTicks > 0;
+
+ if (isResumable != query.IsResumable.Value)
+ {
+ return false;
+ }
+ }
+
+ if (query.IsPlayed.HasValue)
+ {
+ if (item.IsPlayed(user) != query.IsPlayed.Value)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private IEnumerable<Folder> GetMediaFolders(User user)
+ {
+ var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
+
+ return user.RootFolder
+ .GetChildren(user, true, true)
+ .OfType<Folder>()
+ .Where(i => !excludeFolderIds.Contains(i.Id) && !UserView.IsExcludedFromGrouping(i));
+ }
+
+ private IEnumerable<Folder> GetMediaFolders(User user, string[] viewTypes)
+ {
+ return GetMediaFolders(user)
+ .Where(i =>
+ {
+ var folder = i as ICollectionFolder;
+
+ return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ });
+ }
+
+ private IEnumerable<Folder> GetMediaFolders(Folder parent, User user, string[] viewTypes)
+ {
+ if (parent == null || parent is UserView)
+ {
+ return GetMediaFolders(user, viewTypes);
+ }
+
+ return new[] { parent };
+ }
+
+ private IEnumerable<BaseItem> GetRecursiveChildren(Folder parent, User user, string[] viewTypes)
+ {
+ if (parent == null || parent is UserView)
+ {
+ return GetMediaFolders(user, viewTypes).SelectMany(i => i.GetRecursiveChildren(user));
+ }
+
+ return parent.GetRecursiveChildren(user);
+ }
+
+ private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user)
+ {
+ var list = new List<BaseItem>();
+
+ list.Add(await _userViewManager.GetUserView(CollectionType.LiveTvNowPlaying, user, "0", CancellationToken.None).ConfigureAwait(false));
+ list.Add(await _userViewManager.GetUserView(CollectionType.LiveTvChannels, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
+ list.Add(await _userViewManager.GetUserView(CollectionType.LiveTvRecordingGroups, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
+
+ return list;
+ }
+
+ private async Task<UserView> GetUserView(string type, User user, string sortName, Folder parent)
+ {
+ var view = await _userViewManager.GetUserView(type, user, sortName, CancellationToken.None)
+ .ConfigureAwait(false);
+
+ if (parent.Id != view.ParentId)
+ {
+ view.ParentId = parent.Id;
+ await view.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None)
+ .ConfigureAwait(false);
+ }
+
+ return view;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index b1c6ebffc..370ac2e75 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -245,6 +245,15 @@ namespace MediaBrowser.Controller.LiveTv
CancellationToken cancellationToken);
/// <summary>
+ /// Gets the recommended programs internal.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;QueryResult&lt;LiveTvProgram&gt;&gt;.</returns>
+ Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query,
+ CancellationToken cancellationToken);
+
+ /// <summary>
/// Gets the live tv information.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 6a78fa5d9..2ad950a4f 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -157,7 +157,9 @@
<Compile Include="Entities\IHasAwards.cs" />
<Compile Include="Entities\Photo.cs" />
<Compile Include="Entities\PhotoAlbum.cs" />
+ <Compile Include="Entities\UserItemsQuery.cs" />
<Compile Include="Entities\UserView.cs" />
+ <Compile Include="Entities\UserViewBuilder.cs" />
<Compile Include="FileOrganization\IFileOrganizationService.cs" />
<Compile Include="Library\DeleteOptions.cs" />
<Compile Include="Library\ILibraryPostScanTask.cs" />
@@ -336,6 +338,7 @@
<Compile Include="Sync\ISyncRepository.cs" />
<Compile Include="Themes\IAppThemeManager.cs" />
<Compile Include="Themes\InternalThemeImage.cs" />
+ <Compile Include="TV\ITVSeriesManager.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
@@ -360,7 +363,7 @@ xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
- <Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
+ <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition=" '$(ConfigurationName)' != 'Release Mono' " />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
diff --git a/MediaBrowser.Controller/TV/ITVSeriesManager.cs b/MediaBrowser.Controller/TV/ITVSeriesManager.cs
new file mode 100644
index 000000000..3d6e87474
--- /dev/null
+++ b/MediaBrowser.Controller/TV/ITVSeriesManager.cs
@@ -0,0 +1,24 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Querying;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.TV
+{
+ public interface ITVSeriesManager
+ {
+ /// <summary>
+ /// Gets the next up.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
+ QueryResult<BaseItem> GetNextUp(NextUpQuery query);
+
+ /// <summary>
+ /// Gets the next up.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <param name="parentsFolders">The parents folders.</param>
+ /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
+ QueryResult<BaseItem> GetNextUp(NextUpQuery request, IEnumerable<Folder> parentsFolders);
+ }
+}