diff options
Diffstat (limited to 'MediaBrowser.Controller')
| -rw-r--r-- | MediaBrowser.Controller/Channels/Channel.cs | 30 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Channels/ChannelFolderItem.cs | 30 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Channels/ChannelVideoItem.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/BaseItem.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Folder.cs | 30 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/UserItemsQuery.cs | 35 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/UserRootFolder.cs | 13 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/UserView.cs | 80 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/UserViewBuilder.cs | 614 | ||||
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 9 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaBrowser.Controller.csproj | 5 | ||||
| -rw-r--r-- | MediaBrowser.Controller/TV/ITVSeriesManager.cs | 24 |
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<QueryResult<LiveTvProgram>>.</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<BaseItem>.</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<BaseItem>.</returns> + QueryResult<BaseItem> GetNextUp(NextUpQuery request, IEnumerable<Folder> parentsFolders); + } +} |
