From 1f9d32afc52e9bd133ddf22d12bdc468adaf9ebe Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 30 Apr 2016 18:05:13 -0400 Subject: limit use of GetUserDataKey --- MediaBrowser.Controller/Entities/Folder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index f4cdc8fa1b..41f0c02bdc 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1635,7 +1635,7 @@ namespace MediaBrowser.Controller.Entities var isUnplayed = true; - var itemUserData = UserDataManager.GetUserData(user.Id, child.GetUserDataKey()); + var itemUserData = UserDataManager.GetUserData(user, child); // Incrememt totalPercentPlayed if (itemUserData != null) -- cgit v1.2.3 From 311dd50eb7ec777a055755c3791b115fa2c0d762 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 1 May 2016 21:46:08 -0400 Subject: support more filters at db level --- MediaBrowser.Controller/Entities/Folder.cs | 29 ---------------------- .../Persistence/SqliteItemRepository.cs | 24 ++++++++++++++++++ 2 files changed, 24 insertions(+), 29 deletions(-) (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 41f0c02bdc..fca2c6e439 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -839,11 +839,6 @@ namespace MediaBrowser.Controller.Entities Logger.Debug("Query requires post-filtering due to ItemSortBy.SeriesSortName"); return true; } - if (query.SortBy.Contains(ItemSortBy.StartDate, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.StartDate"); - return true; - } if (query.SortBy.Contains(ItemSortBy.Studio, StringComparer.OrdinalIgnoreCase)) { Logger.Debug("Query requires post-filtering due to ItemSortBy.Studio"); @@ -1059,30 +1054,6 @@ namespace MediaBrowser.Controller.Entities return true; } - if (!string.IsNullOrWhiteSpace(query.NameContains)) - { - Logger.Debug("Query requires post-filtering due to NameContains"); - return true; - } - - if (!string.IsNullOrWhiteSpace(query.NameLessThan)) - { - Logger.Debug("Query requires post-filtering due to NameLessThan"); - return true; - } - - if (!string.IsNullOrWhiteSpace(query.NameStartsWith)) - { - Logger.Debug("Query requires post-filtering due to NameStartsWith"); - return true; - } - - if (!string.IsNullOrWhiteSpace(query.NameStartsWithOrGreater)) - { - Logger.Debug("Query requires post-filtering due to NameStartsWithOrGreater"); - return true; - } - if (query.AirDays.Length > 0) { Logger.Debug("Query requires post-filtering due to AirDays"); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 6afdb8d9fa..87b3bffe45 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -2071,6 +2071,30 @@ namespace MediaBrowser.Server.Implementations.Persistence } cmd.Parameters.Add(cmd, "@NameContains", DbType.String).Value = "%" + query.NameContains + "%"; } + if (!string.IsNullOrWhiteSpace(query.NameStartsWith)) + { + if (_config.Configuration.SchemaVersion >= 66) + { + whereClauses.Add("CleanName like @NameStartsWith"); + } + else + { + whereClauses.Add("Name like @NameStartsWith"); + } + cmd.Parameters.Add(cmd, "@NameStartsWith", DbType.String).Value = query.NameStartsWith + "%"; + } + if (!string.IsNullOrWhiteSpace(query.NameStartsWithOrGreater)) + { + whereClauses.Add("SortName >= @NameStartsWithOrGreater"); + // lowercase this because SortName is stored as lowercase + cmd.Parameters.Add(cmd, "@NameStartsWithOrGreater", DbType.String).Value = query.NameStartsWithOrGreater.ToLower(); + } + if (!string.IsNullOrWhiteSpace(query.NameLessThan)) + { + whereClauses.Add("SortName < @NameLessThan"); + // lowercase this because SortName is stored as lowercase + cmd.Parameters.Add(cmd, "@NameLessThan", DbType.String).Value = query.NameLessThan.ToLower(); + } if (query.Genres.Length > 0) { -- cgit v1.2.3 From 568e339ae890414f45d8ecb332f5a6bf68ec7baa Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 2 May 2016 13:11:45 -0400 Subject: update series pooling --- MediaBrowser.Controller/Entities/Folder.cs | 28 ++++++++++++++++++++++ MediaBrowser.Controller/Entities/TV/Season.cs | 7 +++++- .../Dto/DtoService.cs | 3 +-- .../Persistence/SqliteItemRepository.cs | 2 +- 4 files changed, 36 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index fca2c6e439..f57e2fa17a 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1578,8 +1578,36 @@ namespace MediaBrowser.Controller.Entities return !IsPlayed(user); } + [IgnoreDataMember] + public virtual bool SupportsUserDataFromChildren + { + get + { + // These are just far too slow. + if (this is ICollectionFolder) + { + return false; + } + if (this is UserView) + { + return false; + } + if (this is UserRootFolder) + { + return false; + } + + return true; + } + } + public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user) { + if (!SupportsUserDataFromChildren) + { + return; + } + var recursiveItemCount = 0; var unplayed = 0; diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 1f443071c7..29db5fd550 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -125,10 +125,15 @@ namespace MediaBrowser.Controller.Entities.TV get { return LocationType == LocationType.Virtual && GetEpisodes().All(i => i.IsMissingEpisode); } } + private bool GetIsUnaired() + { + return GetEpisodes().All(i => i.IsUnaired); + } + [IgnoreDataMember] public bool IsUnaired { - get { return GetEpisodes().All(i => i.IsUnaired); } + get { return GetIsUnaired(); } } [IgnoreDataMember] diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index e8af0c3cb6..af4c8675c9 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -499,8 +499,7 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.ChildCount = GetChildCount(folder, user); - // These are just far too slow. - if (!(folder is UserRootFolder) && !(folder is UserView) && !(folder is ICollectionFolder)) + if (!folder.SupportsUserDataFromChildren) { SetSpecialCounts(folder, user, dto, fields, syncProgress); } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 6959de8e6b..e26a56ec04 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _updateInheritedRatingCommand; private IDbCommand _updateInheritedTagsCommand; - public const int LatestSchemaVersion = 68; + public const int LatestSchemaVersion = 69; /// /// Initializes a new instance of the class. -- cgit v1.2.3 From 5a496a1fc8d9ee2e728d6f712ae6bdf4862183f1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 6 May 2016 00:50:39 -0400 Subject: reduce recursive querying --- MediaBrowser.Api/BaseApiService.cs | 189 +++++++++------------ MediaBrowser.Api/VideosService.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 20 +++ MediaBrowser.Controller/Entities/Folder.cs | 4 +- .../Entities/InternalItemsQuery.cs | 7 +- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 3 +- MediaBrowser.Controller/Entities/Video.cs | 147 ++++++++-------- .../Dto/DtoService.cs | 45 ----- .../Library/Validators/StudiosValidator.cs | 44 +---- .../Persistence/SqliteItemRepository.cs | 59 ++++++- 10 files changed, 247 insertions(+), 273 deletions(-) (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 30750b3741..44d459a01e 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -79,7 +79,7 @@ namespace MediaBrowser.Api } } } - + /// /// To the optimized serialized result using cache. /// @@ -118,9 +118,6 @@ namespace MediaBrowser.Api return ResultFactory.GetStaticFileResult(Request, path); } - private readonly char[] _dashReplaceChars = { '?', '/', '&' }; - private const char SlugChar = '-'; - protected DtoOptions GetDtoOptions(object request) { var options = new DtoOptions(); @@ -154,152 +151,122 @@ namespace MediaBrowser.Api protected MusicArtist GetArtist(string name, ILibraryManager libraryManager) { - return libraryManager.GetArtist(DeSlugArtistName(name, libraryManager)); - } - - protected Studio GetStudio(string name, ILibraryManager libraryManager) - { - return libraryManager.GetStudio(DeSlugStudioName(name, libraryManager)); - } - - protected Genre GetGenre(string name, ILibraryManager libraryManager) - { - return libraryManager.GetGenre(DeSlugGenreName(name, libraryManager)); - } + if (name.IndexOf(BaseItem.SlugChar) != -1) + { + var result = libraryManager.GetItemList(new InternalItemsQuery + { + SlugName = name, + IncludeItemTypes = new[] { typeof(MusicArtist).Name } - protected MusicGenre GetMusicGenre(string name, ILibraryManager libraryManager) - { - return libraryManager.GetMusicGenre(DeSlugGenreName(name, libraryManager)); - } + }).OfType().FirstOrDefault(); - protected GameGenre GetGameGenre(string name, ILibraryManager libraryManager) - { - return libraryManager.GetGameGenre(DeSlugGameGenreName(name, libraryManager)); - } + if (result != null) + { + return result; + } + } - protected Person GetPerson(string name, ILibraryManager libraryManager) - { - return libraryManager.GetPerson(DeSlugPersonName(name, libraryManager)); + return libraryManager.GetArtist(name); } - /// - /// Deslugs an artist name by finding the correct entry in the library - /// - /// - /// - /// - protected string DeSlugArtistName(string name, ILibraryManager libraryManager) + protected Studio GetStudio(string name, ILibraryManager libraryManager) { - if (name.IndexOf(SlugChar) == -1) - { - return name; - } - - var items = libraryManager.GetItemList(new InternalItemsQuery + if (name.IndexOf(BaseItem.SlugChar) != -1) { - IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicVideo).Name, typeof(MusicAlbum).Name } - }); - - return items - .OfType() - .SelectMany(i => i.AllArtists) - .DistinctNames() - .FirstOrDefault(i => + var result = libraryManager.GetItemList(new InternalItemsQuery { - i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar)); + SlugName = name, + IncludeItemTypes = new[] { typeof(Studio).Name } - return string.Equals(i, name, StringComparison.OrdinalIgnoreCase); + }).OfType().FirstOrDefault(); + + if (result != null) + { + return result; + } + } - }) ?? name; + return libraryManager.GetStudio(name); } - /// - /// Deslugs a genre name by finding the correct entry in the library - /// - protected string DeSlugGenreName(string name, ILibraryManager libraryManager) + protected Genre GetGenre(string name, ILibraryManager libraryManager) { - if (name.IndexOf(SlugChar) == -1) + if (name.IndexOf(BaseItem.SlugChar) != -1) { - return name; - } - - return libraryManager.RootFolder.GetRecursiveChildren() - .SelectMany(i => i.Genres) - .DistinctNames() - .FirstOrDefault(i => + var result = libraryManager.GetItemList(new InternalItemsQuery { - i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar)); + SlugName = name, + IncludeItemTypes = new[] { typeof(Genre).Name } - return string.Equals(i, name, StringComparison.OrdinalIgnoreCase); + }).OfType().FirstOrDefault(); + + if (result != null) + { + return result; + } + } - }) ?? name; + return libraryManager.GetGenre(name); } - protected string DeSlugGameGenreName(string name, ILibraryManager libraryManager) + protected MusicGenre GetMusicGenre(string name, ILibraryManager libraryManager) { - if (name.IndexOf(SlugChar) == -1) + if (name.IndexOf(BaseItem.SlugChar) != -1) { - return name; - } + var result = libraryManager.GetItemList(new InternalItemsQuery + { + SlugName = name, + IncludeItemTypes = new[] { typeof(MusicGenre).Name } - var items = libraryManager.GetItemList(new InternalItemsQuery - { - IncludeItemTypes = new[] { typeof(Game).Name } - }); + }).OfType().FirstOrDefault(); - return items - .SelectMany(i => i.Genres) - .DistinctNames() - .FirstOrDefault(i => + if (result != null) { - i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar)); - - return string.Equals(i, name, StringComparison.OrdinalIgnoreCase); + return result; + } + } - }) ?? name; + return libraryManager.GetMusicGenre(name); } - /// - /// Deslugs a studio name by finding the correct entry in the library - /// - protected string DeSlugStudioName(string name, ILibraryManager libraryManager) + protected GameGenre GetGameGenre(string name, ILibraryManager libraryManager) { - if (name.IndexOf(SlugChar) == -1) + if (name.IndexOf(BaseItem.SlugChar) != -1) { - return name; - } - - return libraryManager.RootFolder - .GetRecursiveChildren() - .SelectMany(i => i.Studios) - .DistinctNames() - .FirstOrDefault(i => + var result = libraryManager.GetItemList(new InternalItemsQuery { - i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar)); + SlugName = name, + IncludeItemTypes = new[] { typeof(GameGenre).Name } - return string.Equals(i, name, StringComparison.OrdinalIgnoreCase); + }).OfType().FirstOrDefault(); - }) ?? name; + if (result != null) + { + return result; + } + } + + return libraryManager.GetGameGenre(name); } - /// - /// Deslugs a person name by finding the correct entry in the library - /// - protected string DeSlugPersonName(string name, ILibraryManager libraryManager) + protected Person GetPerson(string name, ILibraryManager libraryManager) { - if (name.IndexOf(SlugChar) == -1) + if (name.IndexOf(BaseItem.SlugChar) != -1) { - return name; - } - - return libraryManager.GetPeopleNames(new InternalPeopleQuery()) - .FirstOrDefault(i => + var result = libraryManager.GetItemList(new InternalItemsQuery { - i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar)); + SlugName = name, + IncludeItemTypes = new[] { typeof(Person).Name } - return string.Equals(i, name, StringComparison.OrdinalIgnoreCase); + }).OfType().FirstOrDefault(); + + if (result != null) + { + return result; + } + } - }) ?? name; + return libraryManager.GetPerson(name); } protected string GetPathValue(int index) diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs index 6cefda3a35..c8dbb7bb26 100644 --- a/MediaBrowser.Api/VideosService.cs +++ b/MediaBrowser.Api/VideosService.cs @@ -175,7 +175,7 @@ namespace MediaBrowser.Api foreach (var item in items.Where(i => i.Id != primaryVersion.Id)) { - item.PrimaryVersionId = primaryVersion.Id; + item.PrimaryVersionId = primaryVersion.Id.ToString("N"); await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 6bf55e108c..2e968c8803 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -44,6 +44,9 @@ namespace MediaBrowser.Controller.Entities ImageInfos = new List(); } + public static readonly char[] SlugReplaceChars = { '?', '/', '&' }; + public static char SlugChar = '-'; + /// /// The supported image extensions /// @@ -125,6 +128,21 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public string SlugName + { + get + { + var name = Name; + if (string.IsNullOrWhiteSpace(name)) + { + return string.Empty; + } + + return SlugReplaceChars.Aggregate(name, (current, c) => current.Replace(c, SlugChar)); + } + } + public string OriginalTitle { get; set; } /// @@ -728,12 +746,14 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the critic rating. /// /// The critic rating. + [IgnoreDataMember] public float? CriticRating { get; set; } /// /// Gets or sets the critic rating summary. /// /// The critic rating summary. + [IgnoreDataMember] public string CriticRatingSummary { get; set; } /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index f57e2fa17a..d9c0b7bfe3 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -707,8 +707,8 @@ namespace MediaBrowser.Controller.Entities { return ItemRepository.GetItemIdsList(new InternalItemsQuery { - ParentId = Id - + ParentId = Id, + GroupByPresentationUniqueKey = false }); } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 6838fde714..2615f351ad 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -49,6 +49,7 @@ namespace MediaBrowser.Controller.Entities public string PresentationUniqueKey { get; set; } public string Path { get; set; } public string Name { get; set; } + public string SlugName { get; set; } public string Person { get; set; } public string[] PersonIds { get; set; } @@ -133,9 +134,13 @@ namespace MediaBrowser.Controller.Entities public string[] AlbumNames { get; set; } public string[] ArtistNames { get; set; } - + + public bool GroupByPresentationUniqueKey { get; set; } + public InternalItemsQuery() { + GroupByPresentationUniqueKey = true; + AlbumNames = new string[] { }; ArtistNames = new string[] { }; diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index cd3e07ea38..09a9d97bcf 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Controller.Entities.Audio; namespace MediaBrowser.Controller.Entities.Movies { @@ -118,7 +119,7 @@ namespace MediaBrowser.Controller.Entities.Movies // Gather all possible ratings var ratings = GetRecursiveChildren() .Concat(GetLinkedChildren()) - .Where(i => i is Movie || i is Series) + .Where(i => i is Movie || i is Series || i is MusicAlbum || i is Game) .Select(i => i.OfficialRating) .Where(i => !string.IsNullOrEmpty(i)) .Distinct(StringComparer.OrdinalIgnoreCase) diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 67b710534c..6a9d7cb511 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -28,7 +28,8 @@ namespace MediaBrowser.Controller.Entities IThemeMedia, IArchivable { - public Guid? PrimaryVersionId { get; set; } + [IgnoreDataMember] + public string PrimaryVersionId { get; set; } public List AdditionalParts { get; set; } public List LocalAlternateVersions { get; set; } @@ -49,9 +50,9 @@ namespace MediaBrowser.Controller.Entities { get { - if (PrimaryVersionId.HasValue) + if (!string.IsNullOrWhiteSpace(PrimaryVersionId)) { - return PrimaryVersionId.Value.ToString("N"); + return PrimaryVersionId; } return base.PresentationUniqueKey; @@ -70,6 +71,72 @@ namespace MediaBrowser.Controller.Entities /// The timestamp. public TransportStreamTimestamp? Timestamp { get; set; } + /// + /// Gets or sets the subtitle paths. + /// + /// The subtitle paths. + public List SubtitleFiles { get; set; } + + /// + /// Gets or sets a value indicating whether this instance has subtitles. + /// + /// true if this instance has subtitles; otherwise, false. + public bool HasSubtitles { get; set; } + + public bool IsPlaceHolder { get; set; } + public bool IsShortcut { get; set; } + public string ShortcutPath { get; set; } + + /// + /// Gets or sets the video bit rate. + /// + /// The video bit rate. + public int? VideoBitRate { get; set; } + + /// + /// Gets or sets the default index of the video stream. + /// + /// The default index of the video stream. + public int? DefaultVideoStreamIndex { get; set; } + + /// + /// Gets or sets the type of the video. + /// + /// The type of the video. + public VideoType VideoType { get; set; } + + /// + /// Gets or sets the type of the iso. + /// + /// The type of the iso. + public IsoType? IsoType { get; set; } + + /// + /// Gets or sets the video3 D format. + /// + /// The video3 D format. + public Video3DFormat? Video3DFormat { get; set; } + + /// + /// If the video is a folder-rip, this will hold the file list for the largest playlist + /// + public List PlayableStreamFileNames { get; set; } + + /// + /// Gets the playable stream files. + /// + /// List{System.String}. + public List GetPlayableStreamFiles() + { + return GetPlayableStreamFiles(Path); + } + + /// + /// Gets or sets the aspect ratio. + /// + /// The aspect ratio. + public string AspectRatio { get; set; } + public Video() { PlayableStreamFileNames = new List(); @@ -104,9 +171,9 @@ namespace MediaBrowser.Controller.Entities { get { - if (PrimaryVersionId.HasValue) + if (!string.IsNullOrWhiteSpace(PrimaryVersionId)) { - var item = LibraryManager.GetItemById(PrimaryVersionId.Value) as Video; + var item = LibraryManager.GetItemById(PrimaryVersionId) as Video; if (item != null) { return item.MediaSourceCount; @@ -238,72 +305,6 @@ namespace MediaBrowser.Controller.Entities .OrderBy(i => i.SortName); } - /// - /// Gets or sets the subtitle paths. - /// - /// The subtitle paths. - public List SubtitleFiles { get; set; } - - /// - /// Gets or sets a value indicating whether this instance has subtitles. - /// - /// true if this instance has subtitles; otherwise, false. - public bool HasSubtitles { get; set; } - - public bool IsPlaceHolder { get; set; } - public bool IsShortcut { get; set; } - public string ShortcutPath { get; set; } - - /// - /// Gets or sets the video bit rate. - /// - /// The video bit rate. - public int? VideoBitRate { get; set; } - - /// - /// Gets or sets the default index of the video stream. - /// - /// The default index of the video stream. - public int? DefaultVideoStreamIndex { get; set; } - - /// - /// Gets or sets the type of the video. - /// - /// The type of the video. - public VideoType VideoType { get; set; } - - /// - /// Gets or sets the type of the iso. - /// - /// The type of the iso. - public IsoType? IsoType { get; set; } - - /// - /// Gets or sets the video3 D format. - /// - /// The video3 D format. - public Video3DFormat? Video3DFormat { get; set; } - - /// - /// If the video is a folder-rip, this will hold the file list for the largest playlist - /// - public List PlayableStreamFileNames { get; set; } - - /// - /// Gets the playable stream files. - /// - /// List{System.String}. - public List GetPlayableStreamFiles() - { - return GetPlayableStreamFiles(Path); - } - - /// - /// Gets or sets the aspect ratio. - /// - /// The aspect ratio. - public string AspectRatio { get; set; } - [IgnoreDataMember] public override string ContainingFolderPath { @@ -520,9 +521,9 @@ namespace MediaBrowser.Controller.Entities list.Add(new Tuple(this, MediaSourceType.Default)); list.AddRange(GetLinkedAlternateVersions().Select(i => new Tuple(i, MediaSourceType.Grouping))); - if (PrimaryVersionId.HasValue) + if (!string.IsNullOrWhiteSpace(PrimaryVersionId)) { - var primary = LibraryManager.GetItemById(PrimaryVersionId.Value) as Video; + var primary = LibraryManager.GetItemById(PrimaryVersionId) as Video; if (primary != null) { var existingIds = list.Select(i => i.Item1.Id).ToList(); diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index ff94552dad..0aec3230da 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -397,12 +397,6 @@ namespace MediaBrowser.Server.Implementations.Dto collectionFolder.GetViewType(user); } - var playlist = item as Playlist; - if (playlist != null) - { - AttachLinkedChildImages(dto, playlist, user, options); - } - if (fields.Contains(ItemFields.CanDelete)) { dto.CanDelete = user == null @@ -1564,45 +1558,6 @@ namespace MediaBrowser.Server.Implementations.Dto } } - private void AttachLinkedChildImages(BaseItemDto dto, Folder folder, User user, DtoOptions options) - { - List linkedChildren = null; - - var backdropLimit = options.GetImageLimit(ImageType.Backdrop); - - if (backdropLimit > 0 && dto.BackdropImageTags.Count == 0) - { - linkedChildren = user == null - ? folder.GetRecursiveChildren().ToList() - : folder.GetRecursiveChildren(user).ToList(); - - var parentWithBackdrop = linkedChildren.FirstOrDefault(i => i.GetImages(ImageType.Backdrop).Any()); - - if (parentWithBackdrop != null) - { - dto.ParentBackdropItemId = GetDtoId(parentWithBackdrop); - dto.ParentBackdropImageTags = GetBackdropImageTags(parentWithBackdrop, backdropLimit); - } - } - - if (!dto.ImageTags.ContainsKey(ImageType.Primary) && options.GetImageLimit(ImageType.Primary) > 0) - { - if (linkedChildren == null) - { - linkedChildren = user == null - ? folder.GetRecursiveChildren().ToList() - : folder.GetRecursiveChildren(user).ToList(); - } - var parentWithImage = linkedChildren.FirstOrDefault(i => i.GetImages(ImageType.Primary).Any()); - - if (parentWithImage != null) - { - dto.ParentPrimaryImageItemId = GetDtoId(parentWithImage); - dto.ParentPrimaryImageTag = GetImageCacheTag(parentWithImage, ImageType.Primary); - } - } - } - private string GetMappedPath(IHasMetadata item) { var path = item.Path; diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs index c122d64d30..00dc8e6a10 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs @@ -2,7 +2,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using System; -using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -35,25 +34,20 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var items = _libraryManager.RootFolder.GetRecursiveChildren() - .SelectMany(i => i.Studios) - .DistinctNames() - .ToList(); + var items = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Studio).Name } + + }).ToList(); var numComplete = 0; var count = items.Count; - var validIds = new List(); - - foreach (var name in items) + foreach (var item in items) { try { - var itemByName = _libraryManager.GetStudio(name); - - validIds.Add(itemByName.Id); - - await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -62,7 +56,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators } catch (Exception ex) { - _logger.ErrorException("Error refreshing {0}", ex, name); + _logger.ErrorException("Error refreshing {0}", ex, item.Name); } numComplete++; @@ -73,28 +67,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators progress.Report(percent); } - var allIds = _libraryManager.GetItemIds(new InternalItemsQuery - { - IncludeItemTypes = new[] { typeof(Studio).Name } - }); - - var invalidIds = allIds - .Except(validIds) - .ToList(); - - foreach (var id in invalidIds) - { - cancellationToken.ThrowIfCancellationRequested(); - - var item = _libraryManager.GetItemById(id); - - await _libraryManager.DeleteItem(item, new DeleteOptions - { - DeleteFileLocation = false - - }).ConfigureAwait(false); - } - progress.Report(100); } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index d825a8de96..7199301af5 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _updateInheritedRatingCommand; private IDbCommand _updateInheritedTagsCommand; - public const int LatestSchemaVersion = 69; + public const int LatestSchemaVersion = 71; /// /// Initializes a new instance of the class. @@ -226,6 +226,9 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(Logger, "TypedBaseItems", "InheritedTags", "Text"); _connection.AddColumn(Logger, "TypedBaseItems", "CleanName", "Text"); _connection.AddColumn(Logger, "TypedBaseItems", "PresentationUniqueKey", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "SlugName", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "OriginalTitle", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "PrimaryVersionId", "Text"); string[] postQueries = { @@ -367,7 +370,9 @@ namespace MediaBrowser.Server.Implementations.Persistence "Tags", "SourceType", "TrailerTypes", - "DateModifiedDuringLastRefresh" + "DateModifiedDuringLastRefresh", + "OriginalTitle", + "PrimaryVersionId" }; private readonly string[] _mediaStreamSaveColumns = @@ -476,7 +481,10 @@ namespace MediaBrowser.Server.Implementations.Persistence "DateModifiedDuringLastRefresh", "InheritedTags", "CleanName", - "PresentationUniqueKey" + "PresentationUniqueKey", + "SlugName", + "OriginalTitle", + "PrimaryVersionId" }; _saveItemCommand = _connection.CreateCommand(); _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; @@ -810,7 +818,20 @@ namespace MediaBrowser.Server.Implementations.Persistence { _saveItemCommand.GetParameter(index++).Value = item.Name.RemoveDiacritics(); } + _saveItemCommand.GetParameter(index++).Value = item.PresentationUniqueKey; + _saveItemCommand.GetParameter(index++).Value = item.SlugName; + _saveItemCommand.GetParameter(index++).Value = item.OriginalTitle; + + var video = item as Video; + if (video != null) + { + _saveItemCommand.GetParameter(index++).Value = video.PrimaryVersionId; + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } _saveItemCommand.Transaction = transaction; @@ -1189,6 +1210,20 @@ namespace MediaBrowser.Server.Implementations.Persistence item.DateModifiedDuringLastRefresh = reader.GetDateTime(51).ToUniversalTime(); } + if (!reader.IsDBNull(52)) + { + item.OriginalTitle = reader.GetString(52); + } + + var video = item as Video; + if (video != null) + { + if (!reader.IsDBNull(53)) + { + video.PrimaryVersionId = reader.GetString(53); + } + } + return item; } @@ -2070,6 +2105,19 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@PersonName", DbType.String).Value = query.Person; } + if (!string.IsNullOrWhiteSpace(query.SlugName)) + { + if (_config.Configuration.SchemaVersion >= 70) + { + whereClauses.Add("SlugName=@SlugName"); + } + else + { + whereClauses.Add("Name=@SlugName"); + } + cmd.Parameters.Add(cmd, "@SlugName", DbType.String).Value = query.SlugName; + } + if (!string.IsNullOrWhiteSpace(query.Name)) { if (_config.Configuration.SchemaVersion >= 66) @@ -2340,6 +2388,11 @@ namespace MediaBrowser.Server.Implementations.Persistence private bool EnableGroupByPresentationUniqueKey(InternalItemsQuery query) { + if (!query.GroupByPresentationUniqueKey) + { + return false; + } + if (!string.IsNullOrWhiteSpace(query.PresentationUniqueKey)) { return false; -- cgit v1.2.3 From d04b39421e54952241f9a3460a87413923cceb3a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 6 May 2016 22:11:22 -0400 Subject: fix episode query --- MediaBrowser.Controller/Entities/Folder.cs | 32 +++++++++-------- MediaBrowser.Controller/Entities/TV/Season.cs | 25 ++++--------- MediaBrowser.Controller/Playlists/Playlist.cs | 41 ++++++++++++++-------- .../Persistence/SqliteItemRepository.cs | 2 +- .../Playlists/PlaylistManager.cs | 4 +-- 5 files changed, 53 insertions(+), 51 deletions(-) (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index d9c0b7bfe3..4606a5dc72 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -199,8 +199,8 @@ namespace MediaBrowser.Controller.Entities /// Dictionary{System.StringFunc{UserIEnumerable{BaseItem}}}. protected virtual IEnumerable GetIndexByOptions() { - return new List { - {"None"}, + return new List { + {"None"}, {"Performer"}, {"Genre"}, {"Director"}, @@ -1569,7 +1569,15 @@ namespace MediaBrowser.Controller.Entities public override bool IsPlayed(User user) { - return GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual) + var itemsResult = GetItems(new InternalItemsQuery(user) + { + Recursive = true, + IsFolder = false, + ExcludeLocationTypes = new[] { LocationType.Virtual } + + }).Result; + + return itemsResult.Items .All(i => i.IsPlayed(user)); } @@ -1613,19 +1621,15 @@ namespace MediaBrowser.Controller.Entities double totalPercentPlayed = 0; - IEnumerable children; - var folder = this; + var itemsResult = GetItems(new InternalItemsQuery(user) + { + Recursive = true, + IsFolder = false, + ExcludeLocationTypes = new[] { LocationType.Virtual } - var season = folder as Season; + }).Result; - if (season != null) - { - children = season.GetEpisodes(user).Where(i => i.LocationType != LocationType.Virtual); - } - else - { - children = folder.GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual); - } + var children = itemsResult.Items; // Loop through each recursive child foreach (var child in children) diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index a6894f5150..4e6128527c 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -156,24 +156,16 @@ namespace MediaBrowser.Controller.Entities.TV protected override Task> GetItemsInternal(InternalItemsQuery query) { + if (query.User == null) + { + return base.GetItemsInternal(query); + } + var user = query.User; Func filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); - IEnumerable items; - - if (query.User == null) - { - items = query.Recursive - ? GetRecursiveChildren(filter) - : Children.Where(filter); - } - else - { - items = query.Recursive - ? GetRecursiveChildren(user, filter) - : GetChildren(user, true).Where(filter); - } + var items = GetEpisodes(user).Where(filter); var result = PostFilterAndSort(items, query); @@ -269,11 +261,6 @@ namespace MediaBrowser.Controller.Entities.TV return GetEpisodes(user); } - public override IEnumerable GetRecursiveChildren(User user, Func filter) - { - return GetEpisodes(user).Where(filter); - } - protected override bool GetBlockUnratedValue(UserPolicy config) { // Don't block. Let either the entire series rating or episode rating determine it diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 0f9af6550b..750dea3618 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using System.Threading.Tasks; namespace MediaBrowser.Controller.Playlists { @@ -50,12 +51,12 @@ namespace MediaBrowser.Controller.Playlists public override IEnumerable GetChildren(User user, bool includeLinkedChildren) { - return GetPlayableItems(user); + return GetPlayableItems(user).Result; } public override IEnumerable GetRecursiveChildren(User user, Func filter) { - var items = GetPlayableItems(user); + var items = GetPlayableItems(user).Result; if (filter != null) { @@ -70,23 +71,30 @@ namespace MediaBrowser.Controller.Playlists return GetLinkedChildrenInfos(); } - private IEnumerable GetPlayableItems(User user) + private Task> GetPlayableItems(User user) { return GetPlaylistItems(MediaType, base.GetChildren(user, true), user); } - public static IEnumerable GetPlaylistItems(string playlistMediaType, IEnumerable inputItems, User user) + public static async Task> GetPlaylistItems(string playlistMediaType, IEnumerable inputItems, User user) { if (user != null) { inputItems = inputItems.Where(i => i.IsVisible(user)); } - return inputItems.SelectMany(i => GetPlaylistItems(i, user)) - .Where(m => string.Equals(m.MediaType, playlistMediaType, StringComparison.OrdinalIgnoreCase)); + var list = new List(); + + foreach (var item in inputItems) + { + var playlistItems = await GetPlaylistItems(item, user, playlistMediaType).ConfigureAwait(false); + list.AddRange(playlistItems); + } + + return list; } - private static IEnumerable GetPlaylistItems(BaseItem item, User user) + private static async Task> GetPlaylistItems(BaseItem item, User user, string mediaType) { var musicGenre = item as MusicGenre; if (musicGenre != null) @@ -119,15 +127,18 @@ namespace MediaBrowser.Controller.Playlists var folder = item as Folder; if (folder != null) { - var items = user == null - ? folder.GetRecursiveChildren(m => !m.IsFolder) - : folder.GetRecursiveChildren(user, m => !m.IsFolder); - - if (folder.IsPreSorted) + var query = new InternalItemsQuery(user) { - return items; - } - return LibraryManager.Sort(items, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending); + Recursive = true, + IsFolder = false, + SortBy = new[] { ItemSortBy.SortName }, + MediaTypes = new[] { mediaType } + }; + + var itemsResult = await folder.GetItems(query).ConfigureAwait(false); + var items = itemsResult.Items; + + return items; } return new[] { item }; diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 3422a32127..2de458d6e6 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _updateInheritedRatingCommand; private IDbCommand _updateInheritedTagsCommand; - public const int LatestSchemaVersion = 71; + public const int LatestSchemaVersion = 72; /// /// Initializes a new instance of the class. diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs index 06ef05951a..53c03b91c1 100644 --- a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs +++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs @@ -158,7 +158,7 @@ namespace MediaBrowser.Server.Implementations.Playlists return path; } - private IEnumerable GetPlaylistItems(IEnumerable itemIds, string playlistMediaType, User user) + private Task> GetPlaylistItems(IEnumerable itemIds, string playlistMediaType, User user) { var items = itemIds.Select(i => _libraryManager.GetItemById(i)).Where(i => i != null); @@ -183,7 +183,7 @@ namespace MediaBrowser.Server.Implementations.Playlists var list = new List(); - var items = GetPlaylistItems(itemIds, playlist.MediaType, user) + var items = (await GetPlaylistItems(itemIds, playlist.MediaType, user).ConfigureAwait(false)) .Where(i => i.SupportsAddingToPlaylist) .ToList(); -- cgit v1.2.3 From fb25ac7c087be0808677f431023f0769a69c76d2 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 8 May 2016 02:31:08 -0400 Subject: update user data queries --- MediaBrowser.Controller/Entities/Folder.cs | 100 ++--- MediaBrowser.Controller/Entities/TV/Series.cs | 4 +- MediaBrowser.Controller/Entities/UserItemData.cs | 4 +- .../Library/LibraryManager.cs | 2 +- .../Library/UserDataManager.cs | 2 +- .../Persistence/SqliteItemRepository.cs | 443 +++++++++++++++------ .../Persistence/SqliteUserDataRepository.cs | 1 + .../ApplicationHost.cs | 2 +- 8 files changed, 393 insertions(+), 165 deletions(-) (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 4606a5dc72..978fd7fedf 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -751,28 +751,38 @@ namespace MediaBrowser.Controller.Entities return true; } } + + var supportsUserDataQueries = ConfigurationManager.Configuration.SchemaVersion >= 76; if (query.SortBy != null && query.SortBy.Length > 0) { - if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase)) + if (!supportsUserDataQueries) { - Logger.Debug("Query requires post-filtering due to ItemSortBy.DatePlayed"); - return true; - } - if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked"); - return true; - } - if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.IsPlayed"); - return true; - } - if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.IsUnplayed"); - return true; + if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase)) + { + Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked"); + return true; + } + if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase)) + { + Logger.Debug("Query requires post-filtering due to ItemSortBy.PlayCount"); + return true; + } + if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase)) + { + Logger.Debug("Query requires post-filtering due to ItemSortBy.IsFavoriteOrLiked"); + return true; + } + if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase)) + { + Logger.Debug("Query requires post-filtering due to ItemSortBy.IsPlayed"); + return true; + } + if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase)) + { + Logger.Debug("Query requires post-filtering due to ItemSortBy.IsUnplayed"); + return true; + } } if (query.SortBy.Contains(ItemSortBy.AiredEpisodeOrder, StringComparer.OrdinalIgnoreCase)) { @@ -819,11 +829,6 @@ namespace MediaBrowser.Controller.Entities Logger.Debug("Query requires post-filtering due to ItemSortBy.OfficialRating"); return true; } - if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.PlayCount"); - return true; - } if (query.SortBy.Contains(ItemSortBy.Players, StringComparer.OrdinalIgnoreCase)) { Logger.Debug("Query requires post-filtering due to ItemSortBy.Players"); @@ -863,34 +868,37 @@ namespace MediaBrowser.Controller.Entities return true; } - if (query.IsLiked.HasValue) + if (!supportsUserDataQueries) { - Logger.Debug("Query requires post-filtering due to IsLiked"); - return true; - } + if (query.IsLiked.HasValue) + { + Logger.Debug("Query requires post-filtering due to IsLiked"); + return true; + } - if (query.IsFavoriteOrLiked.HasValue) - { - Logger.Debug("Query requires post-filtering due to IsFavoriteOrLiked"); - return true; - } + if (query.IsFavoriteOrLiked.HasValue) + { + Logger.Debug("Query requires post-filtering due to IsFavoriteOrLiked"); + return true; + } - if (query.IsFavorite.HasValue) - { - Logger.Debug("Query requires post-filtering due to IsFavorite"); - return true; - } + if (query.IsFavorite.HasValue) + { + Logger.Debug("Query requires post-filtering due to IsFavorite"); + return true; + } - if (query.IsResumable.HasValue) - { - Logger.Debug("Query requires post-filtering due to IsResumable"); - return true; - } + if (query.IsResumable.HasValue) + { + Logger.Debug("Query requires post-filtering due to IsResumable"); + return true; + } - if (query.IsPlayed.HasValue) - { - Logger.Debug("Query requires post-filtering due to IsPlayed"); - return true; + if (query.IsPlayed.HasValue) + { + Logger.Debug("Query requires post-filtering due to IsPlayed"); + return true; + } } if (query.IsInBoxSet.HasValue) diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index a70bac6db4..680af1843c 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -208,7 +208,7 @@ namespace MediaBrowser.Controller.Entities.TV IncludeItemTypes = new[] { typeof(Season).Name }, SortBy = new[] { ItemSortBy.SortName } - }).OfType(); + }).Cast(); } else { @@ -347,7 +347,7 @@ namespace MediaBrowser.Controller.Entities.TV IncludeItemTypes = new[] { typeof(Episode).Name }, SortBy = new[] { ItemSortBy.SortName } - }).OfType(); + }).Cast(); } else { diff --git a/MediaBrowser.Controller/Entities/UserItemData.cs b/MediaBrowser.Controller/Entities/UserItemData.cs index 16c37e7d33..f95fd70364 100644 --- a/MediaBrowser.Controller/Entities/UserItemData.cs +++ b/MediaBrowser.Controller/Entities/UserItemData.cs @@ -88,6 +88,8 @@ namespace MediaBrowser.Controller.Entities /// /// The index of the subtitle stream. public int? SubtitleStreamIndex { get; set; } + + public const double MinLikeValue = 6.5; /// /// This is an interpreted property to indicate likes or dislikes @@ -101,7 +103,7 @@ namespace MediaBrowser.Controller.Entities { if (Rating != null) { - return Rating >= 6.5; + return Rating >= MinLikeValue; } return null; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index b6a33afe4d..f9bf3446f4 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1398,7 +1398,7 @@ namespace MediaBrowser.Server.Implementations.Library private void AddUserToQuery(InternalItemsQuery query, User user) { - if (query.AncestorIds.Length == 0 && !query.ParentId.HasValue && query.ChannelIds.Length == 0 && query.TopParentIds.Length == 0) + if (query.AncestorIds.Length == 0 && !query.ParentId.HasValue && query.ChannelIds.Length == 0 && query.TopParentIds.Length == 0 && string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey)) { var userViews = _userviewManager().GetUserViews(new UserViewQuery { diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs index 98f8abd405..d3aad20f5f 100644 --- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs @@ -157,7 +157,7 @@ namespace MediaBrowser.Server.Implementations.Library return _userData.GetOrAdd(GetCacheKey(userId, key), keyName => GetUserDataFromRepository(userId, key)); } - public UserItemData GetUserDataFromRepository(Guid userId, string key) + private UserItemData GetUserDataFromRepository(Guid userId, string key) { var data = Repository.GetUserData(userId, key); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 30314b7cc4..09739f8a9d 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -79,10 +79,13 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _deleteAncestorsCommand; private IDbCommand _saveAncestorCommand; + private IDbCommand _deleteUserDataKeysCommand; + private IDbCommand _saveUserDataKeysCommand; + private IDbCommand _updateInheritedRatingCommand; private IDbCommand _updateInheritedTagsCommand; - public const int LatestSchemaVersion = 73; + public const int LatestSchemaVersion = 76; /// /// Initializes a new instance of the class. @@ -135,15 +138,18 @@ namespace MediaBrowser.Server.Implementations.Persistence "create index if not exists idx_AncestorIds1 on AncestorIds(AncestorId)", "create index if not exists idx_AncestorIds2 on AncestorIds(AncestorIdText)", + "create table if not exists UserDataKeys (ItemId GUID, UserDataKey TEXT, PRIMARY KEY (ItemId, UserDataKey))", + "create index if not exists idx_UserDataKeys1 on UserDataKeys(ItemId)", + "create table if not exists People (ItemId GUID, Name TEXT NOT NULL, Role TEXT, PersonType TEXT, SortOrder int, ListOrder int)", "create index if not exists idxPeopleItemId on People(ItemId)", "create index if not exists idxPeopleName on People(Name)", "create table if not exists "+ChaptersTableName+" (ItemId GUID, ChapterIndex INT, StartPositionTicks BIGINT, Name TEXT, ImagePath TEXT, PRIMARY KEY (ItemId, ChapterIndex))", - "create index if not exists idx_"+ChaptersTableName+" on "+ChaptersTableName+"(ItemId, ChapterIndex)", + "create index if not exists idx_"+ChaptersTableName+"1 on "+ChaptersTableName+"(ItemId)", createMediaStreamsTableCommand, - "create index if not exists idx_mediastreams on mediastreams(ItemId, StreamIndex)", + "create index if not exists idx_mediastreams1 on mediastreams(ItemId)", //pragmas "pragma temp_store = memory", @@ -229,6 +235,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(Logger, "TypedBaseItems", "SlugName", "Text"); _connection.AddColumn(Logger, "TypedBaseItems", "OriginalTitle", "Text"); _connection.AddColumn(Logger, "TypedBaseItems", "PrimaryVersionId", "Text"); + _connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT"); string[] postQueries = { @@ -242,17 +249,13 @@ namespace MediaBrowser.Server.Implementations.Persistence new MediaStreamColumns(_connection, Logger).AddColumns(); - var chapterDbFile = Path.Combine(_config.ApplicationPaths.DataPath, "chapters.db"); - if (File.Exists(chapterDbFile)) - { - MigrateChapters(chapterDbFile); - } - var mediaStreamsDbFile = Path.Combine(_config.ApplicationPaths.DataPath, "mediainfo.db"); if (File.Exists(mediaStreamsDbFile)) { MigrateMediaStreams(mediaStreamsDbFile); } + + DataExtensions.Attach(_connection, Path.Combine(_config.ApplicationPaths.DataPath, "userdata_v2.db"), "UserDataDb"); } private void MigrateMediaStreams(string file) @@ -281,30 +284,6 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - private void MigrateChapters(string file) - { - try - { - var backupFile = file + ".bak"; - File.Copy(file, backupFile, true); - DataExtensions.Attach(_connection, backupFile, "ChaptersOld"); - - string[] queries = { - "REPLACE INTO "+ChaptersTableName+"(ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath) SELECT ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath FROM ChaptersOld.Chapters;" - }; - - _connection.RunQueries(queries, Logger); - } - catch (Exception ex) - { - Logger.ErrorException("Error migrating chapter database", ex); - } - finally - { - TryDeleteFile(file); - } - } - private void TryDeleteFile(string file) { try @@ -569,6 +548,18 @@ namespace MediaBrowser.Server.Implementations.Persistence _updateInheritedTagsCommand.CommandText = "Update TypedBaseItems set InheritedTags=@InheritedTags where Guid=@Guid"; _updateInheritedTagsCommand.Parameters.Add(_updateInheritedTagsCommand, "@Guid"); _updateInheritedTagsCommand.Parameters.Add(_updateInheritedTagsCommand, "@InheritedTags"); + + // user data + _deleteUserDataKeysCommand = _connection.CreateCommand(); + _deleteUserDataKeysCommand.CommandText = "delete from UserDataKeys where ItemId=@Id"; + _deleteUserDataKeysCommand.Parameters.Add(_deleteUserDataKeysCommand, "@Id"); + + _saveUserDataKeysCommand = _connection.CreateCommand(); + _saveUserDataKeysCommand.CommandText = "insert into UserDataKeys (ItemId, UserDataKey, Priority) values (@ItemId, @UserDataKey, @Priority)"; + _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@ItemId"); + _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@UserDataKey"); + _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@Priority"); + } /// @@ -841,6 +832,8 @@ namespace MediaBrowser.Server.Implementations.Persistence { UpdateAncestors(item.Id, item.GetAncestorIds().Distinct().ToList(), transaction); } + + UpdateUserDataKeys(item.Id, item.GetUserDataKeys(), transaction); } transaction.Commit(); @@ -1467,34 +1460,96 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - public IEnumerable GetItemsOfType(Type type) + private bool EnableJoinUserData(InternalItemsQuery query) { - if (type == null) + if (_config.Configuration.SchemaVersion < 76) { - throw new ArgumentNullException("type"); + return false; } - CheckDisposed(); + if (query.User == null) + { + return false; + } - using (var cmd = _connection.CreateCommand()) + if (query.SortBy != null && query.SortBy.Length > 0) + { + if (query.SortBy.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase)) + { + return true; + } + if (query.SortBy.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase)) + { + return true; + } + if (query.SortBy.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase)) + { + return true; + } + if (query.SortBy.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase)) + { + return true; + } + if (query.SortBy.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase)) + { + return true; + } + } + + if (query.IsFavoriteOrLiked.HasValue) + { + return true; + } + + if (query.IsFavorite.HasValue) { - cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where type = @type"; + return true; + } - cmd.Parameters.Add(cmd, "@type", DbType.String).Value = type.FullName; + if (query.IsResumable.HasValue) + { + return true; + } - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) - { - var item = GetItem(reader); + if (query.IsPlayed.HasValue) + { + return true; + } - if (item != null) - { - yield return item; - } - } - } + if (query.IsLiked.HasValue) + { + return true; + } + + return false; + } + + private string[] GetFinalColumnsToSelect(InternalItemsQuery query, string[] startColumns) + { + var list = startColumns.ToList(); + + if (EnableJoinUserData(query)) + { + list.Add("UserDataDb.UserData.UserId"); + list.Add("UserDataDb.UserData.lastPlayedDate"); + list.Add("UserDataDb.UserData.playbackPositionTicks"); + list.Add("UserDataDb.UserData.playcount"); + list.Add("UserDataDb.UserData.isFavorite"); + list.Add("UserDataDb.UserData.played"); + list.Add("UserDataDb.UserData.rating"); + } + + return list.ToArray(); + } + + private string GetJoinUserDataText(InternalItemsQuery query) + { + if (!EnableJoinUserData(query)) + { + return string.Empty; } + + return " left join UserDataDb.UserData on (select UserDataKey from UserDataKeys where ItemId=Guid order by Priority LIMIT 1)=UserDataDb.UserData.Key"; } public IEnumerable GetItemList(InternalItemsQuery query) @@ -1510,9 +1565,15 @@ namespace MediaBrowser.Server.Implementations.Persistence using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems"; + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns)) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); + + if (EnableJoinUserData(query)) + { + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + } - var whereClauses = GetWhereClauses(query, cmd, true); + var whereClauses = GetWhereClauses(query, cmd); var whereText = whereClauses.Count == 0 ? string.Empty : @@ -1527,14 +1588,21 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += GetOrderByText(query); - if (query.Limit.HasValue) + if (query.Limit.HasValue || query.StartIndex.HasValue) { - cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } } using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - Logger.Debug("GetItemList query time: {0}ms. Query: {1}", + Logger.Debug("GetItemList query time: {0}ms. Query: {1}", Convert.ToInt32((DateTime.UtcNow - now).TotalMilliseconds), cmd.CommandText); @@ -1563,16 +1631,20 @@ namespace MediaBrowser.Server.Implementations.Persistence using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems"; + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns)) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); + + if (EnableJoinUserData(query)) + { + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + } - var whereClauses = GetWhereClauses(query, cmd, false); + var whereClauses = GetWhereClauses(query, cmd); var whereTextWithoutPaging = whereClauses.Count == 0 ? string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray()); - whereClauses = GetWhereClauses(query, cmd, true); - var whereText = whereClauses.Count == 0 ? string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray()); @@ -1586,20 +1658,30 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += GetOrderByText(query); - if (query.Limit.HasValue) + if (query.Limit.HasValue || query.StartIndex.HasValue) { - cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } } - if (_config.Configuration.SchemaVersion >= 66) + if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66) { - cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems" + whereTextWithoutPaging; + cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; } else { - cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; + cmd.CommandText += "; select count (guid) from TypedBaseItems"; } + cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += whereTextWithoutPaging; + var list = new List(); var count = 0; @@ -1639,32 +1721,64 @@ namespace MediaBrowser.Server.Implementations.Persistence return string.Empty; } - var sortOrder = query.SortOrder == SortOrder.Descending ? "DESC" : "ASC"; + var isAscending = query.SortOrder != SortOrder.Descending; - return " ORDER BY " + string.Join(",", query.SortBy.Select(i => MapOrderByField(i) + " " + sortOrder).ToArray()); + return " ORDER BY " + string.Join(",", query.SortBy.Select(i => + { + var columnMap = MapOrderByField(i); + var columnAscending = isAscending; + if (columnMap.Item2) + { + columnAscending = !columnAscending; + } + + var sortOrder = columnAscending ? "ASC" : "DESC"; + + return columnMap.Item1 + " " + sortOrder; + }).ToArray()); } - private string MapOrderByField(string name) + private Tuple MapOrderByField(string name) { if (string.Equals(name, ItemSortBy.AirTime, StringComparison.OrdinalIgnoreCase)) { // TODO - return "SortName"; + return new Tuple("SortName", false); } if (string.Equals(name, ItemSortBy.Runtime, StringComparison.OrdinalIgnoreCase)) { - return "RuntimeTicks"; + return new Tuple("RuntimeTicks", false); + } + if (string.Equals(name, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase)) + { + return new Tuple("RANDOM()", false); + } + if (string.Equals(name, ItemSortBy.DatePlayed, StringComparison.OrdinalIgnoreCase)) + { + return new Tuple("LastPlayedDate", false); + } + if (string.Equals(name, ItemSortBy.PlayCount, StringComparison.OrdinalIgnoreCase)) + { + return new Tuple("PlayCount", false); + } + if (string.Equals(name, ItemSortBy.IsFavoriteOrLiked, StringComparison.OrdinalIgnoreCase)) + { + return new Tuple("IsFavorite", true); } if (string.Equals(name, ItemSortBy.IsFolder, StringComparison.OrdinalIgnoreCase)) { - return "IsFolder"; + return new Tuple("IsFolder", true); } - if (string.Equals(name, ItemSortBy.Random, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(name, ItemSortBy.IsPlayed, StringComparison.OrdinalIgnoreCase)) + { + return new Tuple("played", true); + } + if (string.Equals(name, ItemSortBy.IsUnplayed, StringComparison.OrdinalIgnoreCase)) { - return "RANDOM()"; + return new Tuple("played", false); } - return name; + return new Tuple(name, false); } public List GetItemIdsList(InternalItemsQuery query) @@ -1680,9 +1794,15 @@ namespace MediaBrowser.Server.Implementations.Persistence using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "select guid from TypedBaseItems"; + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" })) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); + + if (EnableJoinUserData(query)) + { + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + } - var whereClauses = GetWhereClauses(query, cmd, true); + var whereClauses = GetWhereClauses(query, cmd); var whereText = whereClauses.Count == 0 ? string.Empty : @@ -1697,9 +1817,16 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += GetOrderByText(query); - if (query.Limit.HasValue) + if (query.Limit.HasValue || query.StartIndex.HasValue) { - cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } } var list = new List(); @@ -1733,14 +1860,12 @@ namespace MediaBrowser.Server.Implementations.Persistence { cmd.CommandText = "select guid,path from TypedBaseItems"; - var whereClauses = GetWhereClauses(query, cmd, false); + var whereClauses = GetWhereClauses(query, cmd); var whereTextWithoutPaging = whereClauses.Count == 0 ? string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray()); - whereClauses = GetWhereClauses(query, cmd, true, false); - var whereText = whereClauses.Count == 0 ? string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray()); @@ -1754,9 +1879,16 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += GetOrderByText(query); - if (query.Limit.HasValue) + if (query.Limit.HasValue || query.StartIndex.HasValue) { - cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } } cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; @@ -1807,16 +1939,20 @@ namespace MediaBrowser.Server.Implementations.Persistence using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "select guid from TypedBaseItems"; + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" })) + " from TypedBaseItems"; + + var whereClauses = GetWhereClauses(query, cmd); + cmd.CommandText += GetJoinUserDataText(query); - var whereClauses = GetWhereClauses(query, cmd, false); + if (EnableJoinUserData(query)) + { + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + } var whereTextWithoutPaging = whereClauses.Count == 0 ? string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray()); - whereClauses = GetWhereClauses(query, cmd, true); - var whereText = whereClauses.Count == 0 ? string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray()); @@ -1830,20 +1966,30 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += GetOrderByText(query); - if (query.Limit.HasValue) + if (query.Limit.HasValue || query.StartIndex.HasValue) { - cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } } if (EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66) { - cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems" + whereTextWithoutPaging; + cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; } else { - cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; + cmd.CommandText += "; select count (guid) from TypedBaseItems"; } + cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += whereTextWithoutPaging; + var list = new List(); var count = 0; @@ -1872,7 +2018,7 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - private List GetWhereClauses(InternalItemsQuery query, IDbCommand cmd, bool addPaging, bool enablePresentationUniqueKey = true) + private List GetWhereClauses(InternalItemsQuery query, IDbCommand cmd) { var whereClauses = new List(); @@ -2161,6 +2307,60 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@NameLessThan", DbType.String).Value = query.NameLessThan.ToLower(); } + if (query.IsLiked.HasValue) + { + if (query.IsLiked.Value) + { + whereClauses.Add("rating>=@UserRating"); + cmd.Parameters.Add(cmd, "@UserRating", DbType.Double).Value = UserItemData.MinLikeValue; + } + else + { + whereClauses.Add("(rating is null or rating<@UserRating)"); + cmd.Parameters.Add(cmd, "@UserRating", DbType.Double).Value = UserItemData.MinLikeValue; + } + } + + if (query.IsFavoriteOrLiked.HasValue) + { + if (query.IsFavoriteOrLiked.Value) + { + whereClauses.Add("(IsFavorite=@IsFavoriteOrLiked or rating>=@UserRatingIsFavoriteOrLiked)"); + cmd.Parameters.Add(cmd, "@IsFavoriteOrLiked", DbType.Boolean).Value = true; + cmd.Parameters.Add(cmd, "@UserRatingIsFavoriteOrLiked", DbType.Double).Value = UserItemData.MinLikeValue; + } + else + { + whereClauses.Add("(IsFavorite=@IsFavoriteOrLiked or rating is null or rating<@UserRatingIsFavoriteOrLiked)"); + cmd.Parameters.Add(cmd, "@IsFavoriteOrLiked", DbType.Boolean).Value = false; + cmd.Parameters.Add(cmd, "@UserRatingIsFavoriteOrLiked", DbType.Double).Value = UserItemData.MinLikeValue; + } + } + + if (query.IsFavorite.HasValue) + { + whereClauses.Add("IsFavorite=@IsFavorite"); + cmd.Parameters.Add(cmd, "@IsFavorite", DbType.Boolean).Value = query.IsFavorite.Value; + } + + if (query.IsPlayed.HasValue) + { + whereClauses.Add("played=@IsPlayed"); + cmd.Parameters.Add(cmd, "@IsPlayed", DbType.Boolean).Value = query.IsPlayed.Value; + } + + if (query.IsResumable.HasValue) + { + if (query.IsResumable.Value) + { + whereClauses.Add("playbackPositionTicks > 0"); + } + else + { + whereClauses.Add("(playbackPositionTicks is null or playbackPositionTicks = 0)"); + } + } + if (query.Genres.Length > 0) { var clauses = new List(); @@ -2368,27 +2568,6 @@ namespace MediaBrowser.Server.Implementations.Persistence excludeTagIndex++; } - if (addPaging) - { - if (query.StartIndex.HasValue && query.StartIndex.Value > 0) - { - var pagingWhereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - if (enablePresentationUniqueKey && EnableGroupByPresentationUniqueKey(query) && _config.Configuration.SchemaVersion >= 66) - { - pagingWhereText += " Group by PresentationUniqueKey"; - } - - var orderBy = GetOrderByText(query); - - whereClauses.Add(string.Format("guid NOT IN (SELECT guid FROM TypedBaseItems {0}" + orderBy + " LIMIT {1})", - pagingWhereText, - query.StartIndex.Value.ToString(CultureInfo.InvariantCulture))); - } - } - return whereClauses; } @@ -2694,6 +2873,11 @@ namespace MediaBrowser.Server.Implementations.Persistence _deleteAncestorsCommand.Transaction = transaction; _deleteAncestorsCommand.ExecuteNonQuery(); + // Delete user data keys + _deleteUserDataKeysCommand.GetParameter(0).Value = id; + _deleteUserDataKeysCommand.Transaction = transaction; + _deleteUserDataKeysCommand.ExecuteNonQuery(); + // Delete the item _deleteItemCommand.GetParameter(0).Value = id; _deleteItemCommand.Transaction = transaction; @@ -2886,6 +3070,39 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + private void UpdateUserDataKeys(Guid itemId, List keys, IDbTransaction transaction) + { + if (itemId == Guid.Empty) + { + throw new ArgumentNullException("itemId"); + } + + if (keys == null) + { + throw new ArgumentNullException("keys"); + } + + CheckDisposed(); + + // First delete + _deleteUserDataKeysCommand.GetParameter(0).Value = itemId; + _deleteUserDataKeysCommand.Transaction = transaction; + + _deleteUserDataKeysCommand.ExecuteNonQuery(); + var index = 0; + + foreach (var key in keys) + { + _saveUserDataKeysCommand.GetParameter(0).Value = itemId; + _saveUserDataKeysCommand.GetParameter(1).Value = key; + _saveUserDataKeysCommand.GetParameter(2).Value = index; + index++; + _saveUserDataKeysCommand.Transaction = transaction; + + _saveUserDataKeysCommand.ExecuteNonQuery(); + } + } + public async Task UpdatePeople(Guid itemId, List people) { if (itemId == Guid.Empty) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index 33a2b11877..8c521d88a6 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -47,6 +47,7 @@ namespace MediaBrowser.Server.Implementations.Persistence "create table if not exists userdata (key nvarchar, userId GUID, rating float null, played bit, playCount int, isFavorite bit, playbackPositionTicks bigint, lastPlayedDate datetime null)", + "create index if not exists idx_userdata on userdata(key)", "create unique index if not exists userdataindex on userdata (key, userId)", //pragmas diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 2d56a15753..ae839e6ee0 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -562,10 +562,10 @@ namespace MediaBrowser.Server.Startup.Common RegisterSingleInstance(SubtitleEncoder); await displayPreferencesRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false); + await ConfigureUserDataRepositories().ConfigureAwait(false); await itemRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false); await providerRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false); ((LibraryManager)LibraryManager).ItemRepository = ItemRepository; - await ConfigureUserDataRepositories().ConfigureAwait(false); await ConfigureNotificationsRepository().ConfigureAwait(false); progress.Report(100); -- cgit v1.2.3 From 99084edabeb1787f28496dffa55fbb260e34ae81 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 8 May 2016 23:13:38 -0400 Subject: update windows ffmpeg --- MediaBrowser.Api/ApiEntryPoint.cs | 8 ++- MediaBrowser.Api/LiveTv/LiveTvService.cs | 20 ++++++- MediaBrowser.Api/Movies/MoviesService.cs | 1 - MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs | 5 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 3 +- MediaBrowser.Controller/Entities/Audio/Audio.cs | 6 --- .../Entities/Audio/MusicAlbum.cs | 9 ++++ .../Entities/Audio/MusicArtist.cs | 9 ++++ MediaBrowser.Controller/Entities/BaseItem.cs | 11 ++++ MediaBrowser.Controller/Entities/Folder.cs | 49 +++++++++++------ MediaBrowser.Controller/Entities/IHasMetadata.cs | 2 + .../Entities/InternalItemsQuery.cs | 2 + MediaBrowser.Controller/Entities/MusicVideo.cs | 6 --- MediaBrowser.Controller/Entities/TV/Season.cs | 9 ++++ MediaBrowser.Controller/Entities/TV/Series.cs | 9 ++++ MediaBrowser.Controller/Entities/UserRootFolder.cs | 5 -- MediaBrowser.Controller/Playlists/Playlist.cs | 9 ++++ MediaBrowser.Model/LiveTv/ProgramQuery.cs | 3 ++ .../LiveTv/RecommendedProgramQuery.cs | 9 +++- MediaBrowser.Providers/Manager/MetadataService.cs | 61 +++++++++++++++++++-- .../Music/MusicBrainzArtistProvider.cs | 29 +++++++--- .../Dto/DtoService.cs | 33 ++++-------- .../Library/LibraryManager.cs | 14 +++-- .../LiveTv/EmbyTV/EmbyTV.cs | 18 ++++++- .../LiveTv/LiveTvManager.cs | 10 ++-- .../Persistence/SqliteItemRepository.cs | 62 ++++++++++++++++++++-- .../Sorting/DateLastMediaAddedComparer.cs | 8 +-- .../MediaBrowser.ServerApplication.csproj | 2 - .../Native/WindowsApp.cs | 17 ++++-- .../ffmpeg/ffmpegx64.7z.REMOVED.git-id | 1 - .../ffmpeg/ffmpegx86.7z.REMOVED.git-id | 1 - 31 files changed, 330 insertions(+), 101 deletions(-) delete mode 100644 MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id delete mode 100644 MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 66ca8c25d4..a677bc6004 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -488,13 +488,17 @@ namespace MediaBrowser.Api { try { - Logger.Info("Killing ffmpeg process for {0}", job.Path); + Logger.Info("Stopping ffmpeg process with q command for {0}", job.Path); //process.Kill(); process.StandardInput.WriteLine("q"); // Need to wait because killing is asynchronous - process.WaitForExit(5000); + if (!process.WaitForExit(5000)) + { + Logger.Info("Killing ffmpeg process for {0}", job.Path); + process.Kill(); + } } catch (Exception ex) { diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index ebcf8fbeac..d3a4558c88 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -254,6 +254,8 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] public bool? EnableImages { get; set; } + public bool EnableTotalRecordCount { get; set; } + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? ImageTypeLimit { get; set; } @@ -266,12 +268,24 @@ namespace MediaBrowser.Api.LiveTv /// The fields. [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string Fields { get; set; } + + public GetPrograms() + { + EnableTotalRecordCount = true; + } } [Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")] [Authenticated] public class GetRecommendedPrograms : IReturn>, IHasDtoOptions { + public bool EnableTotalRecordCount { get; set; } + + public GetRecommendedPrograms() + { + EnableTotalRecordCount = true; + } + [ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] public string UserId { get; set; } @@ -662,7 +676,8 @@ namespace MediaBrowser.Api.LiveTv { ChannelIds = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(), UserId = request.UserId, - HasAired = request.HasAired + HasAired = request.HasAired, + EnableTotalRecordCount = request.EnableTotalRecordCount }; if (!string.IsNullOrEmpty(request.MinStartDate)) @@ -709,7 +724,8 @@ namespace MediaBrowser.Api.LiveTv HasAired = request.HasAired, IsMovie = request.IsMovie, IsKids = request.IsKids, - IsSports = request.IsSports + IsSports = request.IsSports, + EnableTotalRecordCount = request.EnableTotalRecordCount }; var result = await _liveTvManager.GetRecommendedPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 9590971d06..786615cc3e 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -196,7 +196,6 @@ namespace MediaBrowser.Api.Movies var parentIds = new string[] { }; var list = _libraryManager.GetItemList(query, parentIds) - .DistinctBy(i => i.PresentationUniqueKey, StringComparer.OrdinalIgnoreCase) .DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) .ToList(); diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 6867f6308c..aee1a8d545 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -12,6 +12,7 @@ namespace MediaBrowser.Api.UserLibrary protected BaseItemsRequest() { EnableImages = true; + EnableTotalRecordCount = true; } /// @@ -104,7 +105,9 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "IsInBoxSet", Description = "Optional filter by items that are in boxsets, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsInBoxSet { get; set; } - + + public bool EnableTotalRecordCount { get; set; } + /// /// Skips over a given number of items within the results. Use for paging. /// diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 7d2029cabe..ff937078e6 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -230,7 +230,8 @@ namespace MediaBrowser.Api.UserLibrary ParentId = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId), ParentIndexNumber = request.ParentIndexNumber, AiredDuringSeason = request.AiredDuringSeason, - AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater + AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater, + EnableTotalRecordCount = request.EnableTotalRecordCount }; if (!string.IsNullOrWhiteSpace(request.Ids)) diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index fd56a6746a..c34a884ff5 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -40,12 +40,6 @@ namespace MediaBrowser.Controller.Entities.Audio public List AlbumArtists { get; set; } - /// - /// Gets or sets the album. - /// - /// The album. - public string Album { get; set; } - [IgnoreDataMember] public bool IsThemeMedia { diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 5cb4e8c9d1..615276e837 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -48,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.Audio } } + [IgnoreDataMember] + public override bool SupportsCumulativeRunTimeTicks + { + get + { + return true; + } + } + [IgnoreDataMember] public List AllArtists { diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 6f6f124dbb..6104976615 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -34,6 +34,15 @@ namespace MediaBrowser.Controller.Entities.Audio } } + [IgnoreDataMember] + public override bool SupportsCumulativeRunTimeTicks + { + get + { + return true; + } + } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 2e968c8803..cd021d2ab5 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -69,6 +69,12 @@ namespace MediaBrowser.Controller.Entities public List ImageInfos { get; set; } + /// + /// Gets or sets the album. + /// + /// The album. + public string Album { get; set; } + /// /// Gets or sets the channel identifier. /// @@ -1175,6 +1181,11 @@ namespace MediaBrowser.Controller.Entities get { return Id.ToString("N"); } } + public virtual bool RequiresRefresh() + { + return false; + } + private string _userDataKey; /// /// Gets the user data key. diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 978fd7fedf..457a0b3abd 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -28,6 +28,9 @@ namespace MediaBrowser.Controller.Entities public List ThemeSongIds { get; set; } public List ThemeVideoIds { get; set; } + [IgnoreDataMember] + public DateTime? DateLastMediaAdded { get; set; } + public Folder() { LinkedChildren = new List(); @@ -55,6 +58,36 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public virtual bool SupportsCumulativeRunTimeTicks + { + get + { + return false; + } + } + + [IgnoreDataMember] + public virtual bool SupportsDateLastMediaAdded + { + get + { + return false; + } + } + + public override bool RequiresRefresh() + { + var baseResult = base.RequiresRefresh(); + + if (SupportsCumulativeRunTimeTicks && !RunTimeTicks.HasValue) + { + baseResult = true; + } + + return baseResult; + } + [IgnoreDataMember] public override string FileNameWithoutExtension { @@ -789,11 +822,6 @@ namespace MediaBrowser.Controller.Entities Logger.Debug("Query requires post-filtering due to ItemSortBy.AiredEpisodeOrder"); return true; } - if (query.SortBy.Contains(ItemSortBy.Album, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.Album"); - return true; - } if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase)) { Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist"); @@ -809,11 +837,6 @@ namespace MediaBrowser.Controller.Entities Logger.Debug("Query requires post-filtering due to ItemSortBy.Budget"); return true; } - if (query.SortBy.Contains(ItemSortBy.DateLastContentAdded, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.DateLastContentAdded"); - return true; - } if (query.SortBy.Contains(ItemSortBy.GameSystem, StringComparer.OrdinalIgnoreCase)) { Logger.Debug("Query requires post-filtering due to ItemSortBy.GameSystem"); @@ -1086,12 +1109,6 @@ namespace MediaBrowser.Controller.Entities return true; } - if (query.AlbumNames.Length > 0) - { - Logger.Debug("Query requires post-filtering due to AlbumNames"); - return true; - } - if (query.ArtistNames.Length > 0) { Logger.Debug("Query requires post-filtering due to ArtistNames"); diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index 1f680b35f3..c7940c8a97 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -49,5 +49,7 @@ namespace MediaBrowser.Controller.Entities /// /// true if [supports people]; otherwise, false. bool SupportsPeople { get; } + + bool RequiresRefresh(); } } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 385ee81e9d..5236b0a278 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -137,10 +137,12 @@ namespace MediaBrowser.Controller.Entities public string AncestorWithPresentationUniqueKey { get; set; } public bool GroupByPresentationUniqueKey { get; set; } + public bool EnableTotalRecordCount { get; set; } public InternalItemsQuery() { GroupByPresentationUniqueKey = true; + EnableTotalRecordCount = true; AlbumNames = new string[] { }; ArtistNames = new string[] { }; diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index bf4c2559c5..7119828e26 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -9,12 +9,6 @@ namespace MediaBrowser.Controller.Entities { public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasProductionLocations, IHasBudget, IHasLookupInfo { - /// - /// Gets or sets the album. - /// - /// The album. - public string Album { get; set; } - /// /// Gets or sets the budget. /// diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 4e6128527c..ac8cc0ee26 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -32,6 +32,15 @@ namespace MediaBrowser.Controller.Entities.TV } } + [IgnoreDataMember] + public override bool SupportsDateLastMediaAdded + { + get + { + return true; + } + } + [IgnoreDataMember] public override Guid? DisplayParentId { diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 680af1843c..f8cdab8ce6 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -48,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.TV } } + [IgnoreDataMember] + public override bool SupportsDateLastMediaAdded + { + get + { + return true; + } + } + public bool DisplaySpecialsWithSeasons { get; set; } public List LocalTrailerIds { get; set; } diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 8ce39c6979..b9e997d175 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -102,10 +102,5 @@ namespace MediaBrowser.Controller.Entities LibraryManager.RegisterItem(item); } } - - public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user) - { - // Nothing meaninful here and will only waste resources - } } } diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index cd0c5dc1c7..003cbcfcda 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -39,6 +39,15 @@ namespace MediaBrowser.Controller.Playlists } } + [IgnoreDataMember] + public override bool SupportsCumulativeRunTimeTicks + { + get + { + return true; + } + } + public override bool IsAuthorizedToDelete(User user) { return true; diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index 7a877e3561..0141191c18 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -14,8 +14,11 @@ namespace MediaBrowser.Model.LiveTv ChannelIds = new string[] { }; SortBy = new string[] { }; Genres = new string[] { }; + EnableTotalRecordCount = true; } + public bool EnableTotalRecordCount { get; set; } + /// /// Fields to return within the items, in addition to basic information /// diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs index e83a8fda65..0e6d081a1d 100644 --- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs @@ -13,7 +13,14 @@ namespace MediaBrowser.Model.LiveTv public bool? EnableImages { get; set; } public int? ImageTypeLimit { get; set; } public ImageType[] EnableImageTypes { get; set; } - + + public bool EnableTotalRecordCount { get; set; } + + public RecommendedProgramQuery() + { + EnableTotalRecordCount = true; + } + /// /// Gets or sets the user identifier. /// diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index ae48c996a0..218127ab9e 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -310,6 +310,11 @@ namespace MediaBrowser.Providers.Manager return true; } + if (item is MusicVideo) + { + return true; + } + return false; } @@ -390,7 +395,6 @@ namespace MediaBrowser.Providers.Manager return _cachedTask; } - private readonly Task _cachedResult = Task.FromResult(ItemUpdateType.None); /// /// Befores the save. /// @@ -398,9 +402,58 @@ namespace MediaBrowser.Providers.Manager /// if set to true [is full refresh]. /// Type of the current update. /// ItemUpdateType. - protected virtual Task BeforeSave(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType) + protected virtual async Task BeforeSave(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType) + { + var updateType = ItemUpdateType.None; + + updateType |= SaveCumulativeRunTimeTicks(item, isFullRefresh, currentUpdateType); + updateType |= SaveDateLastMediaAdded(item, isFullRefresh, currentUpdateType); + + return updateType; + } + + private ItemUpdateType SaveCumulativeRunTimeTicks(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType) + { + var updateType = ItemUpdateType.None; + + if (isFullRefresh || currentUpdateType > ItemUpdateType.None) + { + var folder = item as Folder; + if (folder != null && folder.SupportsCumulativeRunTimeTicks) + { + var ticks = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.RunTimeTicks ?? 0).Sum(); + + if (!folder.RunTimeTicks.HasValue || folder.RunTimeTicks.Value != ticks) + { + folder.RunTimeTicks = ticks; + updateType = ItemUpdateType.MetadataEdit; + } + } + } + + return updateType; + } + + private ItemUpdateType SaveDateLastMediaAdded(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType) { - return _cachedResult; + var updateType = ItemUpdateType.None; + + if (isFullRefresh || currentUpdateType > ItemUpdateType.None) + { + var folder = item as Folder; + if (folder != null && folder.SupportsDateLastMediaAdded) + { + var date = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.DateCreated).Max(); + + if (!folder.DateLastMediaAdded.HasValue || folder.DateLastMediaAdded.Value != date) + { + folder.DateLastMediaAdded = date; + updateType = ItemUpdateType.MetadataEdit; + } + } + } + + return updateType; } /// @@ -420,7 +473,7 @@ namespace MediaBrowser.Providers.Manager : status.DateLastMetadataRefresh ?? default(DateTime); // Run all if either of these flags are true - var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime); + var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime) || item.RequiresRefresh(); if (!runAllProviders) { diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs index ad900123ed..2eb65f4e57 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs @@ -62,12 +62,25 @@ namespace MediaBrowser.Providers.Music private IEnumerable GetResultsFromResponse(XmlDocument doc) { - var ns = new XmlNamespaceManager(doc.NameTable); - ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#"); + //var ns = new XmlNamespaceManager(doc.NameTable); + //ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#"); var list = new List(); - var nodes = doc.SelectNodes("//mb:artist-list/mb:artist", ns); + var docElem = doc.DocumentElement; + + if (docElem == null) + { + return list; + } + + var artistList = docElem.FirstChild; + if (artistList == null) + { + return list; + } + + var nodes = artistList.ChildNodes; if (nodes != null) { @@ -79,11 +92,13 @@ namespace MediaBrowser.Providers.Music string mbzId = node.Attributes["id"].Value; - var nameNode = node.SelectSingleNode("//mb:name", ns); - - if (nameNode != null) + foreach (var child in node.ChildNodes.Cast()) { - name = nameNode.InnerText; + if (string.Equals(child.Name, "name", StringComparison.OrdinalIgnoreCase)) + { + name = node.InnerText; + break; + } } if (!string.IsNullOrWhiteSpace(mbzId) && !string.IsNullOrWhiteSpace(name)) diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 0aec3230da..32610a6ad9 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -499,6 +499,16 @@ namespace MediaBrowser.Server.Implementations.Dto } } + if (fields.Contains(ItemFields.CumulativeRunTimeTicks)) + { + dto.CumulativeRunTimeTicks = dto.RunTimeTicks; + } + + if (fields.Contains(ItemFields.DateLastMediaAdded)) + { + dto.DateLastMediaAdded = folder.DateLastMediaAdded; + } + dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue && dto.UserData.PlayedPercentage.Value >= 100; } @@ -1613,9 +1623,7 @@ namespace MediaBrowser.Server.Implementations.Dto { var recursiveItemCount = 0; var unplayed = 0; - long runtime = 0; - DateTime? dateLastMediaAdded = null; double totalPercentPlayed = 0; double totalSyncPercent = 0; var addSyncInfo = fields.Contains(ItemFields.SyncInfo); @@ -1632,15 +1640,6 @@ namespace MediaBrowser.Server.Implementations.Dto // Loop through each recursive child foreach (var child in children) { - if (!dateLastMediaAdded.HasValue) - { - dateLastMediaAdded = child.DateCreated; - } - else - { - dateLastMediaAdded = new[] { dateLastMediaAdded.Value, child.DateCreated }.Max(); - } - var userdata = _userDataRepository.GetUserData(user, child); recursiveItemCount++; @@ -1669,8 +1668,6 @@ namespace MediaBrowser.Server.Implementations.Dto unplayed++; } - runtime += child.RunTimeTicks ?? 0; - if (addSyncInfo) { double percent = 0; @@ -1709,16 +1706,6 @@ namespace MediaBrowser.Server.Implementations.Dto } } } - - if (runtime > 0 && fields.Contains(ItemFields.CumulativeRunTimeTicks)) - { - dto.CumulativeRunTimeTicks = runtime; - } - - if (fields.Contains(ItemFields.DateLastMediaAdded)) - { - dto.DateLastMediaAdded = dateLastMediaAdded; - } } /// diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index f9bf3446f4..c95b301722 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1354,12 +1354,20 @@ namespace MediaBrowser.Server.Implementations.Library AddUserToQuery(query, query.User); } - var initialResult = ItemRepository.GetItemIds(query); + if (query.EnableTotalRecordCount) + { + var initialResult = ItemRepository.GetItemIds(query); + + return new QueryResult + { + TotalRecordCount = initialResult.TotalRecordCount, + Items = initialResult.Items.Select(GetItemById).Where(i => i != null).ToArray() + }; + } return new QueryResult { - TotalRecordCount = initialResult.TotalRecordCount, - Items = initialResult.Items.Select(GetItemById).Where(i => i != null).ToArray() + Items = ItemRepository.GetItemIdsList(query).Select(GetItemById).Where(i => i != null).ToArray() }; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index c5920d3d6a..b5e8ad79a5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -760,7 +760,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (info.IsMovie) { var customRecordingPath = config.MovieRecordingPath; - if ((string.IsNullOrWhiteSpace(customRecordingPath) || string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase)) && config.EnableRecordingSubfolders) + var allowSubfolder = true; + if (!string.IsNullOrWhiteSpace(customRecordingPath)) + { + allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase); + recordPath = customRecordingPath; + } + + if (allowSubfolder && config.EnableRecordingSubfolders) { recordPath = Path.Combine(recordPath, "Movies"); } @@ -775,7 +782,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV else if (info.IsSeries) { var customRecordingPath = config.SeriesRecordingPath; - if ((string.IsNullOrWhiteSpace(customRecordingPath) || string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase)) && config.EnableRecordingSubfolders) + var allowSubfolder = true; + if (!string.IsNullOrWhiteSpace(customRecordingPath)) + { + allowSubfolder = string.Equals(customRecordingPath, recordPath, StringComparison.OrdinalIgnoreCase); + recordPath = customRecordingPath; + } + + if (allowSubfolder && config.EnableRecordingSubfolders) { recordPath = Path.Combine(recordPath, "Series"); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index eec8328f89..175eed66c0 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -886,7 +886,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv StartIndex = query.StartIndex, Limit = query.Limit, SortBy = query.SortBy, - SortOrder = query.SortOrder ?? SortOrder.Ascending + SortOrder = query.SortOrder ?? SortOrder.Ascending, + EnableTotalRecordCount = query.EnableTotalRecordCount }; if (query.HasAired.HasValue) @@ -924,7 +925,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv IsAiring = query.IsAiring, IsMovie = query.IsMovie, IsSports = query.IsSports, - IsKids = query.IsKids + IsKids = query.IsKids, + EnableTotalRecordCount = query.EnableTotalRecordCount }; if (query.HasAired.HasValue) @@ -1263,11 +1265,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv private async Task CleanDatabaseInternal(List currentIdList, string[] validTypes, IProgress progress, CancellationToken cancellationToken) { - var list = _itemRepo.GetItemIds(new InternalItemsQuery + var list = _itemRepo.GetItemIdsList(new InternalItemsQuery { IncludeItemTypes = validTypes - }).Items.ToList(); + }).ToList(); var numComplete = 0; diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 09739f8a9d..180bd35479 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -85,7 +85,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _updateInheritedRatingCommand; private IDbCommand _updateInheritedTagsCommand; - public const int LatestSchemaVersion = 76; + public const int LatestSchemaVersion = 77; /// /// Initializes a new instance of the class. @@ -235,6 +235,9 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(Logger, "TypedBaseItems", "SlugName", "Text"); _connection.AddColumn(Logger, "TypedBaseItems", "OriginalTitle", "Text"); _connection.AddColumn(Logger, "TypedBaseItems", "PrimaryVersionId", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "DateLastMediaAdded", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "Album", "Text"); + _connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT"); string[] postQueries = @@ -351,7 +354,9 @@ namespace MediaBrowser.Server.Implementations.Persistence "TrailerTypes", "DateModifiedDuringLastRefresh", "OriginalTitle", - "PrimaryVersionId" + "PrimaryVersionId", + "DateLastMediaAdded", + "Album" }; private readonly string[] _mediaStreamSaveColumns = @@ -463,7 +468,9 @@ namespace MediaBrowser.Server.Implementations.Persistence "PresentationUniqueKey", "SlugName", "OriginalTitle", - "PrimaryVersionId" + "PrimaryVersionId", + "DateLastMediaAdded", + "Album" }; _saveItemCommand = _connection.CreateCommand(); _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; @@ -824,6 +831,18 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = null; } + var folder = item as Folder; + if (folder != null && folder.DateLastMediaAdded.HasValue) + { + _saveItemCommand.GetParameter(index++).Value = folder.DateLastMediaAdded.Value; + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + + _saveItemCommand.GetParameter(index++).Value = item.Album; + _saveItemCommand.Transaction = transaction; _saveItemCommand.ExecuteNonQuery(); @@ -1217,6 +1236,17 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + var folder = item as Folder; + if (folder != null && !reader.IsDBNull(54)) + { + folder.DateLastMediaAdded = reader.GetDateTime(54).ToUniversalTime(); + } + + if (!reader.IsDBNull(55)) + { + item.Album = reader.GetString(55); + } + return item; } @@ -1777,6 +1807,10 @@ namespace MediaBrowser.Server.Implementations.Persistence { return new Tuple("played", false); } + if (string.Equals(name, ItemSortBy.DateLastContentAdded, StringComparison.OrdinalIgnoreCase)) + { + return new Tuple("DateLastMediaAdded", false); + } return new Tuple(name, false); } @@ -2484,7 +2518,7 @@ namespace MediaBrowser.Server.Implementations.Persistence if (query.MediaTypes.Length == 1) { whereClauses.Add("MediaType=@MediaTypes"); - cmd.Parameters.Add(cmd, "@MediaTypes", DbType.String).Value = query.MediaTypes[0].ToString(); + cmd.Parameters.Add(cmd, "@MediaTypes", DbType.String).Value = query.MediaTypes[0]; } if (query.MediaTypes.Length > 1) { @@ -2493,6 +2527,26 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add("MediaType in (" + val + ")"); } + if (query.AlbumNames.Length > 0) + { + var clause = "("; + + var index = 0; + foreach (var name in query.AlbumNames) + { + if (index > 0) + { + clause += " OR "; + } + clause += "Album=@AlbumName" + index; + index++; + cmd.Parameters.Add(cmd, "@AlbumName" + index, DbType.String).Value = name; + } + + clause += ")"; + whereClauses.Add(clause); + } + //var enableItemsByName = query.IncludeItemsByName ?? query.IncludeItemTypes.Length > 0; var enableItemsByName = query.IncludeItemsByName ?? false; diff --git a/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs index 68cd44ec94..5c51f5e0fc 100644 --- a/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs @@ -49,10 +49,10 @@ namespace MediaBrowser.Server.Implementations.Sorting if (folder != null) { - return folder.GetRecursiveChildren(User, i => !i.IsFolder) - .Select(i => i.DateCreated) - .OrderByDescending(i => i) - .FirstOrDefault(); + if (folder.DateLastMediaAdded.HasValue) + { + return folder.DateLastMediaAdded.Value; + } } return x.DateCreated; diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index f544a149d8..366d4b6083 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -142,8 +142,6 @@ - - diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs index 808c7558ec..271b02d9a7 100644 --- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs +++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs @@ -158,9 +158,9 @@ namespace MediaBrowser.ServerApplication.Native info.FFMpegFilename = "ffmpeg.exe"; info.FFProbeFilename = "ffprobe.exe"; - info.Version = "20160401"; + info.Version = "20160508"; info.ArchiveType = "7z"; - info.IsEmbedded = true; + info.IsEmbedded = false; info.DownloadUrls = GetDownloadUrls(); return info; @@ -212,11 +212,18 @@ namespace MediaBrowser.ServerApplication.Native switch (Environment.SystemArchitecture) { case Architecture.X86_X64: - return new[] { "MediaBrowser.ServerApplication.ffmpeg.ffmpegx64.7z" }; + return new[] + { + "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20160508-win64.7z", + "https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20160508-git-caee88d-win64-static.7z" + }; case Architecture.X86: - return new[] { "MediaBrowser.ServerApplication.ffmpeg.ffmpegx86.7z" }; + return new[] + { + "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20160508-win32.7z", + "https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20160508-git-caee88d-win32-static.7z" + }; } - return new string[] { }; } } diff --git a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id b/MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id deleted file mode 100644 index b0542b75f3..0000000000 --- a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx64.7z.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -9dc10b022537738edce7eb71aa8dd4adbfee2c7b \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id b/MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id deleted file mode 100644 index 3939ec44d6..0000000000 --- a/MediaBrowser.ServerApplication/ffmpeg/ffmpegx86.7z.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -00fa1afa35fbd0a7e97ad7956e42ae17f6882f64 \ No newline at end of file -- cgit v1.2.3 From f80c1d93c0f20d9d905ffd4170297959a942ad6d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 9 May 2016 00:56:41 -0400 Subject: update user queries --- MediaBrowser.Controller/Entities/Folder.cs | 26 ++++++++++++------- MediaBrowser.Providers/Manager/MetadataService.cs | 3 ++- .../Movies/MovieUpdatesPrescanTask.cs | 10 +++++--- .../FileOrganization/EpisodeFileOrganizer.cs | 26 +++++++++++-------- .../Library/UserDataManager.cs | 30 +++++++++++++++++++--- .../Persistence/SqliteItemRepository.cs | 4 +++ .../Persistence/SqliteUserDataRepository.cs | 6 +---- .../ScheduledTasks/ChapterImagesTask.cs | 12 ++++++--- 8 files changed, 82 insertions(+), 35 deletions(-) (limited to 'MediaBrowser.Controller/Entities/Folder.cs') diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 457a0b3abd..949b333d4a 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1293,33 +1293,41 @@ namespace MediaBrowser.Controller.Entities public IList GetRecursiveChildren(Func filter) { - var list = new List(); + var result = new Dictionary(); - AddChildrenToList(list, true, filter); + AddChildrenToList(result, true, true, filter); - return list; + return result.Values.ToList(); } /// /// Adds the children to list. /// - /// The list. - /// if set to true [recursive]. - /// The filter. - private void AddChildrenToList(List list, bool recursive, Func filter) + private void AddChildrenToList(Dictionary result, bool includeLinkedChildren, bool recursive, Func filter) { foreach (var child in Children) { if (filter == null || filter(child)) { - list.Add(child); + result[child.Id] = child; } if (recursive && child.IsFolder) { var folder = (Folder)child; - folder.AddChildrenToList(list, true, filter); + folder.AddChildrenToList(result, includeLinkedChildren, true, filter); + } + } + + if (includeLinkedChildren) + { + foreach (var child in GetLinkedChildren()) + { + if (filter == null || filter(child)) + { + result[child.Id] = child; + } } } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 218127ab9e..330b813749 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -421,7 +421,8 @@ namespace MediaBrowser.Providers.Manager var folder = item as Folder; if (folder != null && folder.SupportsCumulativeRunTimeTicks) { - var ticks = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.RunTimeTicks ?? 0).Sum(); + var items = folder.GetRecursiveChildren(i => !i.IsFolder).ToList(); + var ticks = items.Select(i => i.RunTimeTicks ?? 0).Sum(); if (!folder.RunTimeTicks.HasValue || folder.RunTimeTicks.Value != ticks) { diff --git a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs index f7f0fd6cc5..70c155ad5d 100644 --- a/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs +++ b/MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs @@ -176,9 +176,13 @@ namespace MediaBrowser.Providers.Movies var numComplete = 0; // Gather all movies into a lookup by tmdb id - var allMovies = _libraryManager.RootFolder - .GetRecursiveChildren(i => i is Movie && !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb))) - .ToLookup(i => i.GetProviderId(MetadataProviders.Tmdb)); + var allMovies = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery + { + IncludeItemTypes = new[] {typeof (Movie).Name}, + Recursive = true + + }).Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb))) + .ToLookup(i => i.GetProviderId(MetadataProviders.Tmdb)); foreach (var id in list) { diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index 270f01b2b4..f402a0a33b 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -116,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization premiereDate, options, overwriteExisting, - false, + false, result, cancellationToken).ConfigureAwait(false); } @@ -202,7 +202,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization null, options, true, - request.RememberCorrection, + request.RememberCorrection, result, cancellationToken).ConfigureAwait(false); @@ -219,7 +219,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization DateTime? premiereDate, AutoOrganizeOptions options, bool overwriteExisting, - bool rememberCorrection, + bool rememberCorrection, FileOrganizationResult result, CancellationToken cancellationToken) { @@ -242,7 +242,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization premiereDate, options, overwriteExisting, - rememberCorrection, + rememberCorrection, result, cancellationToken); } @@ -255,7 +255,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization DateTime? premiereDate, AutoOrganizeOptions options, bool overwriteExisting, - bool rememberCorrection, + bool rememberCorrection, FileOrganizationResult result, CancellationToken cancellationToken) { @@ -536,7 +536,11 @@ namespace MediaBrowser.Server.Implementations.FileOrganization result.ExtractedName = nameWithoutYear; result.ExtractedYear = yearInName; - var series = _libraryManager.RootFolder.GetRecursiveChildren(i => i is Series) + var series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Recursive = true + }) .Cast() .Select(i => NameUtils.GetMatchScore(nameWithoutYear, yearInName, i)) .Where(i => i.Item2 > 0) @@ -550,10 +554,12 @@ namespace MediaBrowser.Server.Implementations.FileOrganization if (info != null) { - series = _libraryManager.RootFolder - .GetRecursiveChildren(i => i is Series) - .Cast() - .FirstOrDefault(i => string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)); + series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Recursive = true + }).Cast() + .FirstOrDefault(i => string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)); } } diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs index d3aad20f5f..0fabbf54aa 100644 --- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Server.Implementations.Library { public event EventHandler UserDataSaved; - private readonly ConcurrentDictionary _userData = new ConcurrentDictionary(); + private readonly Dictionary _userData = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly ILogger _logger; private readonly IServerConfigurationManager _config; @@ -66,8 +66,10 @@ namespace MediaBrowser.Server.Implementations.Library var newValue = userData; - // Once it succeeds, put it into the dictionary to make it available to everyone else - _userData.AddOrUpdate(GetCacheKey(userId, key), newValue, delegate { return newValue; }); + lock (_userData) + { + _userData[GetCacheKey(userId, key)] = newValue; + } } catch (Exception ex) { @@ -154,13 +156,33 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("key"); } - return _userData.GetOrAdd(GetCacheKey(userId, key), keyName => GetUserDataFromRepository(userId, key)); + lock (_userData) + { + var cacheKey = GetCacheKey(userId, key); + UserItemData value; + if (_userData.TryGetValue(cacheKey, out value)) + { + return value; + } + + value = GetUserDataFromRepository(userId, key); + _userData[cacheKey] = value; + return value; + } } private UserItemData GetUserDataFromRepository(Guid userId, string key) { var data = Repository.GetUserData(userId, key); + if (data == null) + { + data = new UserItemData + { + UserId = userId, + Key = key + }; + } return data; } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 180bd35479..20cc7f82a9 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -2056,6 +2056,10 @@ namespace MediaBrowser.Server.Implementations.Persistence { var whereClauses = new List(); + if (EnableJoinUserData(query)) + { + whereClauses.Add("UserId=@UserId"); + } if (query.IsCurrentSchema.HasValue) { if (query.IsCurrentSchema.Value) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index 8c521d88a6..7f3b32e062 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -296,11 +296,7 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - return new UserItemData - { - UserId = userId, - Key = key - }; + return null; } } diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs index e50de7baca..607a043a64 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.Entities; namespace MediaBrowser.Server.Implementations.ScheduledTasks { @@ -85,8 +86,13 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks /// Task. public async Task Execute(CancellationToken cancellationToken, IProgress progress) { - var videos = _libraryManager.RootFolder.GetRecursiveChildren(i => i is Video) - .Cast