diff options
| author | Luke <luke.pulverenti@gmail.com> | 2015-02-09 16:58:30 -0500 |
|---|---|---|
| committer | Luke <luke.pulverenti@gmail.com> | 2015-02-09 16:58:30 -0500 |
| commit | 4cc3b2f0ccd7c092a4acf72db4903415e175037a (patch) | |
| tree | f9f90f8665b726253b8b357674f2f141aa43abc9 /MediaBrowser.Controller/Entities | |
| parent | e7037a9b80843c127712f11430239f8fa3cb4aed (diff) | |
| parent | 3d7089a7dbabb652730c892206ca050f52f832b1 (diff) | |
Merge pull request #1005 from MediaBrowser/dev
3.0.5518.0
Diffstat (limited to 'MediaBrowser.Controller/Entities')
34 files changed, 823 insertions, 421 deletions
diff --git a/MediaBrowser.Controller/Entities/AdultVideo.cs b/MediaBrowser.Controller/Entities/AdultVideo.cs deleted file mode 100644 index 6c3f7851e..000000000 --- a/MediaBrowser.Controller/Entities/AdultVideo.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace MediaBrowser.Controller.Entities -{ - [Obsolete] - public class AdultVideo : Video, IHasProductionLocations, IHasTaglines - { - public List<string> ProductionLocations { get; set; } - - public List<string> Taglines { get; set; } - - public AdultVideo() - { - Taglines = new List<string>(); - ProductionLocations = new List<string>(); - } - } -} diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 362096b5e..66a0d551b 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -32,6 +32,11 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// The _virtual children /// </summary> @@ -66,7 +71,7 @@ namespace MediaBrowser.Controller.Entities { var path = ContainingFolderPath; - var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager, directoryService) + var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths , directoryService) { FileInfo = new DirectoryInfo(path), Path = path, diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index c5ed09016..902447999 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -4,11 +4,11 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -81,6 +81,15 @@ namespace MediaBrowser.Controller.Entities.Audio } [IgnoreDataMember] + protected override bool SupportsOwnedItems + { + get + { + return false; + } + } + + [IgnoreDataMember] public override Folder LatestItemsIndexContainer { get @@ -104,6 +113,13 @@ namespace MediaBrowser.Controller.Entities.Audio } } + public override bool CanDownload() + { + var locationType = LocationType; + return locationType != LocationType.Remote && + locationType != LocationType.Virtual; + } + /// <summary> /// Gets or sets the artist. /// </summary> @@ -169,7 +185,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var parent = FindParent<MusicAlbum>(); @@ -186,7 +202,7 @@ namespace MediaBrowser.Controller.Entities.Audio } } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } protected override bool GetBlockUnratedValue(UserPolicy config) @@ -223,7 +239,7 @@ namespace MediaBrowser.Controller.Entities.Audio { Id = i.Id.ToString("N"), Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File, - MediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(), + MediaStreams = MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(), Name = i.Name, Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path, RunTimeTicks = i.RunTimeTicks, diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 90edfcce7..e3f523b5a 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -1,11 +1,11 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -52,14 +52,14 @@ namespace MediaBrowser.Controller.Entities.Audio } } - public List<string> AlbumArtists { get; set; } - [IgnoreDataMember] public string AlbumArtist { get { return AlbumArtists.FirstOrDefault(); } } + public List<string> AlbumArtists { get; set; } + /// <summary> /// Gets the tracks. /// </summary> @@ -68,7 +68,7 @@ namespace MediaBrowser.Controller.Entities.Audio { get { - return RecursiveChildren.OfType<Audio>(); + return GetRecursiveChildren(i => i is Audio).Cast<Audio>(); } } @@ -136,7 +136,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var id = this.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup); @@ -152,7 +152,7 @@ namespace MediaBrowser.Controller.Entities.Audio return "MusicAlbum-Musicbrainz-" + id; } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } protected override bool GetBlockUnratedValue(UserPolicy config) @@ -173,17 +173,12 @@ namespace MediaBrowser.Controller.Entities.Audio id.ArtistProviderIds = artist.ProviderIds; } - id.SongInfos = RecursiveChildren.OfType<Audio>() + id.SongInfos = GetRecursiveChildren(i => i is Audio) + .Cast<Audio>() .Select(i => i.GetLookupInfo()) .ToList(); return id; } } - - [Obsolete] - public class MusicAlbumDisc : Folder - { - - } } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index a60258d1a..e65d3c0e7 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -1,14 +1,13 @@ -using System.Runtime.Serialization; -using MediaBrowser.Common.Progress; -using MediaBrowser.Controller.Providers; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -19,7 +18,8 @@ namespace MediaBrowser.Controller.Entities.Audio { public bool IsAccessedByName { get; set; } public List<string> ProductionLocations { get; set; } - + + [IgnoreDataMember] public override bool IsFolder { get @@ -34,6 +34,11 @@ namespace MediaBrowser.Controller.Entities.Audio get { return true; } } + public override bool CanDelete() + { + return !IsAccessedByName; + } + protected override IEnumerable<BaseItem> ActualChildren { get @@ -68,7 +73,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return GetUserDataKey(this); } @@ -78,6 +83,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -90,6 +96,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -122,89 +129,53 @@ namespace MediaBrowser.Controller.Entities.Audio public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) { - var items = RecursiveChildren.ToList(); + var items = GetRecursiveChildren().ToList(); var songs = items.OfType<Audio>().ToList(); var others = items.Except(songs).ToList(); var totalItems = songs.Count + others.Count; - var percentages = new Dictionary<Guid, double>(totalItems); - - var tasks = new List<Task>(); + var numComplete = 0; // Refresh songs foreach (var item in songs) { - if (tasks.Count >= 2) - { - await Task.WhenAll(tasks).ConfigureAwait(false); - tasks.Clear(); - } - cancellationToken.ThrowIfCancellationRequested(); - var innerProgress = new ActionableProgress<double>(); - // Avoid implicitly captured closure - var currentChild = item; - innerProgress.RegisterAction(p => - { - lock (percentages) - { - percentages[currentChild.Id] = p / 100; - - var percent = percentages.Values.Sum(); - percent /= totalItems; - percent *= 100; - progress.Report(percent); - } - }); - - var taskChild = item; - tasks.Add(Task.Run(async () => await RefreshItem(taskChild, refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken)); - } + await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - await Task.WhenAll(tasks).ConfigureAwait(false); - tasks.Clear(); + numComplete++; + double percent = numComplete; + percent /= totalItems; + progress.Report(percent * 100); + } // Refresh current item await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - + // Refresh all non-songs foreach (var item in others) { cancellationToken.ThrowIfCancellationRequested(); - // Avoid implicitly captured closure - var currentChild = item; - await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - lock (percentages) - { - percentages[currentChild.Id] = 1; - var percent = percentages.Values.Sum(); - percent /= totalItems; - percent *= 100; - progress.Report(percent); - } + numComplete++; + double percent = numComplete; + percent /= totalItems; + progress.Report(percent * 100); } progress.Report(100); } - private async Task RefreshItem(BaseItem item, MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) - { - await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - - progress.Report(100); - } - public ArtistInfo GetLookupInfo() { var info = GetItemLookupInfo<ArtistInfo>(); - info.SongInfos = RecursiveChildren.OfType<Audio>() + info.SongInfos = GetRecursiveChildren(i => i is Audio) + .Cast<Audio>() .Select(i => i.GetLookupInfo()) .ToList(); @@ -213,9 +184,16 @@ namespace MediaBrowser.Controller.Entities.Audio public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.OfType<IHasArtist>() - .Where(i => i.HasArtist(Name)) - .Cast<BaseItem>(); + return inputItems.Where(GetItemFilter()); + } + + public Func<BaseItem, bool> GetItemFilter() + { + return i => + { + var hasArtist = i as IHasArtist; + return hasArtist != null && hasArtist.HasArtist(Name); + }; } } } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index 928eb6463..ed0956073 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "MusicGenre-" + Name; } @@ -30,6 +30,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -38,10 +39,16 @@ namespace MediaBrowser.Controller.Entities.Audio } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -52,7 +59,12 @@ namespace MediaBrowser.Controller.Entities.Audio public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.Where(i => (i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase)); + return inputItems.Where(GetItemFilter()); + } + + public Func<BaseItem, bool> GetItemFilter() + { + return i => (i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase); } } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index ee562d8b4..3ab02ea21 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -239,6 +239,38 @@ namespace MediaBrowser.Controller.Entities get { return this.GetImagePath(ImageType.Primary); } } + public virtual bool CanDelete() + { + var locationType = LocationType; + return locationType != LocationType.Remote && + locationType != LocationType.Virtual; + } + + public virtual bool IsAuthorizedToDelete(User user) + { + return user.Policy.EnableContentDeletion; + } + + public bool CanDelete(User user) + { + return CanDelete() && IsAuthorizedToDelete(user); + } + + public virtual bool CanDownload() + { + return false; + } + + public virtual bool IsAuthorizedToDownload(User user) + { + return user.Policy.EnableContentDownloading; + } + + public bool CanDownload(User user) + { + return CanDownload() && IsAuthorizedToDownload(user); + } + /// <summary> /// Gets or sets the date created. /// </summary> @@ -268,6 +300,7 @@ namespace MediaBrowser.Controller.Entities public static IChannelManager ChannelManager { get; set; } public static ICollectionManager CollectionManager { get; set; } public static IImageProcessor ImageProcessor { get; set; } + public static IMediaSourceManager MediaSourceManager { get; set; } /// <summary> /// Returns a <see cref="System.String" /> that represents this instance. @@ -359,7 +392,7 @@ namespace MediaBrowser.Controller.Entities { get { - if (!string.IsNullOrEmpty(ForcedSortName)) + if (!string.IsNullOrWhiteSpace(ForcedSortName)) { return ForcedSortName; } @@ -379,21 +412,19 @@ namespace MediaBrowser.Controller.Entities public string GetInternalMetadataPath() { - return GetInternalMetadataPath(ConfigurationManager.ApplicationPaths.InternalMetadataPath); + var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath; + + return GetInternalMetadataPath(basePath); } protected virtual string GetInternalMetadataPath(string basePath) { var idString = Id.ToString("N"); - return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString); - } - - public static string GetInternalMetadataPathForId(Guid id) - { - var idString = id.ToString("N"); - - var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath; + if (ConfigurationManager.Configuration.EnableLibraryMetadataSubFolder) + { + basePath = System.IO.Path.Combine(basePath, "library"); + } return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString); } @@ -692,7 +723,7 @@ namespace MediaBrowser.Controller.Entities var requiresSave = false; - if (IsFolder || Parent != null) + if (SupportsOwnedItems) { try { @@ -724,6 +755,12 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + protected virtual bool SupportsOwnedItems + { + get { return IsFolder || Parent != null; } + } + /// <summary> /// Refreshes owned items such as trailers, theme videos, special features, etc. /// Returns true or false indicating if changes were found. @@ -889,11 +926,24 @@ namespace MediaBrowser.Controller.Entities get { return null; } } + private string _userDataKey; /// <summary> /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public virtual string GetUserDataKey() + public string GetUserDataKey() + { + if (string.IsNullOrWhiteSpace(_userDataKey)) + { + var key = CreateUserDataKey(); + _userDataKey = key; + return key; + } + + return _userDataKey; + } + + protected virtual string CreateUserDataKey() { return Id.ToString(); } @@ -905,6 +955,12 @@ namespace MediaBrowser.Controller.Entities return current.IsInMixedFolder == newItem.IsInMixedFolder; } + public void AfterMetadataRefresh() + { + _sortName = null; + _userDataKey = null; + } + /// <summary> /// Gets the preferred metadata language. /// </summary> @@ -1024,7 +1080,8 @@ namespace MediaBrowser.Controller.Entities if (hasTags != null) { - if (user.Policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase))) + var policy = user.Policy; + if (policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase))) { return false; } @@ -1033,6 +1090,11 @@ namespace MediaBrowser.Controller.Entities return true; } + protected virtual bool IsAllowTagFilterEnforced() + { + return true; + } + /// <summary> /// Gets the block unrated value. /// </summary> @@ -1060,6 +1122,23 @@ namespace MediaBrowser.Controller.Entities return IsParentalAllowed(user); } + public virtual bool IsVisibleStandalone(User user) + { + if (!IsVisible(user)) + { + return false; + } + + if (Parents.Any(i => !i.IsVisible(user))) + { + return false; + } + + // TODO: Need some work here, e.g. is in user library, for channels, can user access channel, etc. + + return true; + } + /// <summary> /// Gets a value indicating whether this instance is folder. /// </summary> @@ -1146,7 +1225,7 @@ namespace MediaBrowser.Controller.Entities if (!string.IsNullOrWhiteSpace(info.ItemName) && !string.IsNullOrWhiteSpace(info.ItemType)) { - return LibraryManager.RootFolder.RecursiveChildren.FirstOrDefault(i => + return LibraryManager.RootFolder.GetRecursiveChildren(i => { if (string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)) { @@ -1164,7 +1243,8 @@ namespace MediaBrowser.Controller.Entities } return false; - }); + + }).FirstOrDefault(); } return null; @@ -1458,7 +1538,7 @@ namespace MediaBrowser.Controller.Entities currentFile.Attributes &= ~FileAttributes.Hidden; } - currentFile.Delete(); + FileSystem.DeleteFile(currentFile.FullName); } return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); @@ -1703,6 +1783,9 @@ namespace MediaBrowser.Controller.Entities /// </summary> public virtual bool BeforeMetadataRefresh() { + _userDataKey = null; + _sortName = null; + var hasChanges = false; if (string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(Path)) diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs index b30bd81b9..785c441d3 100644 --- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs +++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs @@ -11,5 +11,10 @@ namespace MediaBrowser.Controller.Entities { get { return null; } } + + public override bool CanDelete() + { + return false; + } } } diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index 381b2101d..e59db67a6 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -2,6 +2,7 @@ using MediaBrowser.Model.Configuration; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities @@ -37,6 +38,13 @@ namespace MediaBrowser.Controller.Entities Tags = new List<string>(); } + public override bool CanDownload() + { + var locationType = LocationType; + return locationType != LocationType.Remote && + locationType != LocationType.Virtual; + } + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Book); diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index f47a439a7..a39357f2b 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -35,6 +35,11 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + public string CollectionType { get; set; } /// <summary> @@ -86,7 +91,7 @@ namespace MediaBrowser.Controller.Entities { var path = ContainingFolderPath; - var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager, directoryService) + var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService) { FileInfo = new DirectoryInfo(path), Path = path, @@ -121,12 +126,6 @@ namespace MediaBrowser.Controller.Entities return args; } - // Cache this since it will be used a lot - /// <summary> - /// The null task result - /// </summary> - private static readonly Task NullTaskResult = Task.FromResult<object>(null); - /// <summary> /// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes /// ***Currently does not contain logic to maintain items that are unavailable in the file system*** @@ -138,7 +137,7 @@ namespace MediaBrowser.Controller.Entities /// <param name="refreshOptions">The refresh options.</param> /// <param name="directoryService">The directory service.</param> /// <returns>Task.</returns> - protected override async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { var list = PhysicalLocationsList.ToList(); @@ -146,8 +145,10 @@ namespace MediaBrowser.Controller.Entities if (!list.SequenceEqual(PhysicalLocationsList)) { - await UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + return UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken); } + + return Task.FromResult(true); } /// <summary> diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 2761aa5d7..0d9bb03ac 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -6,7 +6,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; -using MoreLinq; using System; using System.Collections; using System.Collections.Generic; @@ -15,13 +14,14 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { /// <summary> /// Class Folder /// </summary> - public class Folder : BaseItem, IHasThemeMedia, IHasTags + public class Folder : BaseItem, IHasThemeMedia, IHasTags, IHasPreferredMetadataLanguage { public static IUserManager UserManager { get; set; } public static IUserViewManager UserViewManager { get; set; } @@ -30,6 +30,14 @@ namespace MediaBrowser.Controller.Entities public List<Guid> ThemeVideoIds { get; set; } public List<string> Tags { get; set; } + public string PreferredMetadataLanguage { get; set; } + + /// <summary> + /// Gets or sets the preferred metadata country code. + /// </summary> + /// <value>The preferred metadata country code.</value> + public string PreferredMetadataCountryCode { get; set; } + public Folder() { LinkedChildren = new List<LinkedChild>(); @@ -72,6 +80,19 @@ namespace MediaBrowser.Controller.Entities } } + protected override bool IsAllowTagFilterEnforced() + { + if (this is ICollectionFolder) + { + return false; + } + if (this is UserView) + { + return false; + } + return true; + } + /// <summary> /// Gets or sets a value indicating whether this instance is physical root. /// </summary> @@ -98,6 +119,7 @@ namespace MediaBrowser.Controller.Entities public virtual List<LinkedChild> LinkedChildren { get; set; } + [IgnoreDataMember] protected virtual bool SupportsShortcutChildren { get { return true; } @@ -237,14 +259,13 @@ namespace MediaBrowser.Controller.Entities protected virtual IEnumerable<string> GetIndexByOptions() { return new List<string> { - {LocalizedStrings.Instance.GetString("NoneDispPref")}, - {LocalizedStrings.Instance.GetString("PerformerDispPref")}, - {LocalizedStrings.Instance.GetString("GenreDispPref")}, - {LocalizedStrings.Instance.GetString("DirectorDispPref")}, - {LocalizedStrings.Instance.GetString("YearDispPref")}, - {LocalizedStrings.Instance.GetString("StudioDispPref")} + {"None"}, + {"Performer"}, + {"Genre"}, + {"Director"}, + {"Year"}, + {"Studio"} }; - } /// <summary> @@ -275,7 +296,17 @@ namespace MediaBrowser.Controller.Entities { get { - return _children ?? (_children = LoadChildrenInternal()); + if (_children == null) + { + lock (_childrenSyncLock) + { + if (_children == null) + { + _children = LoadChildrenInternal(); + } + } + } + return _children; } } @@ -301,14 +332,24 @@ namespace MediaBrowser.Controller.Entities public override bool IsVisible(User user) { - if (this is ICollectionFolder) + if (this is ICollectionFolder && !(this is BasePluginFolder)) { - if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) || + if (user.Policy.BlockedMediaFolders != null) + { + if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) || - // Backwards compatibility - user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase)) + // Backwards compatibility + user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase)) + { + return false; + } + } + else { - return false; + if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) + { + return false; + } } } @@ -345,12 +386,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>Task.</returns> public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true) { - return ValidateChildrenWithCancellationSupport(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService); - } - - private Task ValidateChildrenWithCancellationSupport(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) - { - return ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService); + return ValidateChildrenInternal(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService); } private Dictionary<Guid, BaseItem> GetActualChildrenDictionary() @@ -540,50 +576,49 @@ namespace MediaBrowser.Controller.Entities var children = ActualChildren.ToList(); var percentages = new Dictionary<Guid, double>(children.Count); - - var tasks = new List<Task>(); + var numComplete = 0; + var count = children.Count; foreach (var child in children) { - if (tasks.Count >= 2) - { - await Task.WhenAll(tasks).ConfigureAwait(false); - tasks.Clear(); - } - cancellationToken.ThrowIfCancellationRequested(); - var innerProgress = new ActionableProgress<double>(); - // Avoid implicitly captured closure - var currentChild = child; - innerProgress.RegisterAction(p => + if (child.IsFolder) { - lock (percentages) + var innerProgress = new ActionableProgress<double>(); + + // Avoid implicitly captured closure + var currentChild = child; + innerProgress.RegisterAction(p => { - percentages[currentChild.Id] = p / 100; + lock (percentages) + { + percentages[currentChild.Id] = p / 100; - var percent = percentages.Values.Sum(); - percent /= children.Count; - percent *= 100; - progress.Report(percent); - } - }); + var innerPercent = percentages.Values.Sum(); + innerPercent /= count; + innerPercent *= 100; + progress.Report(innerPercent); + } + }); - if (child.IsFolder) - { await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken) .ConfigureAwait(false); } else { - // Avoid implicitly captured closure - var taskChild = child; - - tasks.Add(Task.Run(async () => await RefreshChildMetadata(taskChild, refreshOptions, false, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken)); + await RefreshChildMetadata(child, refreshOptions, false, new Progress<double>(), cancellationToken) + .ConfigureAwait(false); } + + numComplete++; + double percent = numComplete; + percent /= count; + percent *= 100; + + progress.Report(percent); } - await Task.WhenAll(tasks).ConfigureAwait(false); progress.Report(100); } @@ -648,7 +683,7 @@ namespace MediaBrowser.Controller.Entities } }); - await child.ValidateChildrenWithCancellationSupport(innerProgress, cancellationToken, true, false, null, directoryService) + await child.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService) .ConfigureAwait(false); } } @@ -678,12 +713,12 @@ namespace MediaBrowser.Controller.Entities path = System.IO.Path.GetDirectoryName(path); } - if (ContainsPath(LibraryManager.GetDefaultVirtualFolders(), originalPath)) + if (ContainsPath(LibraryManager.GetVirtualFolders(), originalPath)) { return true; } - return UserManager.Users.Any(user => ContainsPath(LibraryManager.GetVirtualFolders(user), originalPath)); + return ContainsPath(LibraryManager.GetVirtualFolders(), originalPath); } /// <summary> @@ -731,28 +766,6 @@ namespace MediaBrowser.Controller.Entities return childrenItems; } - /// <summary> - /// Retrieves the child. - /// </summary> - /// <param name="child">The child.</param> - /// <returns>BaseItem.</returns> - private BaseItem RetrieveChild(Guid child) - { - var item = LibraryManager.GetItemById(child); - - if (item != null) - { - if (item is IByReferenceItem) - { - return LibraryManager.GetOrAddByReferenceItem(item); - } - - item.Parent = this; - } - - return item; - } - private BaseItem RetrieveChild(BaseItem child) { if (child.Id == Guid.Empty) @@ -786,18 +799,31 @@ namespace MediaBrowser.Controller.Entities { var user = query.User; - var items = query.Recursive - ? GetRecursiveChildren(user) - : GetChildren(user, true); + Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); + + IEnumerable<BaseItem> 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 result = SortAndFilter(items, query); + var result = PostFilterAndSort(items, query); return Task.FromResult(result); } - protected QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items, InternalItemsQuery query) + protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query) { - return UserViewBuilder.SortAndFilter(items, this, null, query, LibraryManager, UserDataManager); + return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager); } /// <summary> @@ -822,11 +848,11 @@ namespace MediaBrowser.Controller.Entities //the true root should return our users root folder children if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, includeLinkedChildren); - var list = new List<BaseItem>(); + var result = new Dictionary<Guid, BaseItem>(); - var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, includeHidden, false); + AddChildren(user, includeLinkedChildren, result, includeHidden, false, null); - return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list; + return result.Values; } protected virtual IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user) @@ -839,31 +865,30 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="user">The user.</param> /// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param> - /// <param name="list">The list.</param> + /// <param name="result">The result.</param> /// <param name="includeHidden">if set to <c>true</c> [include hidden].</param> /// <param name="recursive">if set to <c>true</c> [recursive].</param> + /// <param name="filter">The filter.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - private bool AddChildrenToList(User user, bool includeLinkedChildren, List<BaseItem> list, bool includeHidden, bool recursive) + private void AddChildren(User user, bool includeLinkedChildren, Dictionary<Guid, BaseItem> result, bool includeHidden, bool recursive, Func<BaseItem, bool> filter) { - var hasLinkedChildren = false; - foreach (var child in GetEligibleChildrenForRecursiveChildren(user)) { if (child.IsVisible(user)) { if (includeHidden || !child.IsHiddenFromUser(user)) { - list.Add(child); + if (filter == null || filter(child)) + { + result[child.Id] = child; + } } if (recursive && child.IsFolder) { var folder = (Folder)child; - if (folder.AddChildrenToList(user, includeLinkedChildren, list, includeHidden, true)) - { - hasLinkedChildren = true; - } + folder.AddChildren(user, includeLinkedChildren, result, includeHidden, true, filter); } } } @@ -874,14 +899,13 @@ namespace MediaBrowser.Controller.Entities { if (child.IsVisible(user)) { - hasLinkedChildren = true; - - list.Add(child); + if (filter == null || filter(child)) + { + result[child.Id] = child; + } } } } - - return hasLinkedChildren; } /// <summary> @@ -891,18 +915,23 @@ namespace MediaBrowser.Controller.Entities /// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param> /// <returns>IEnumerable{BaseItem}.</returns> /// <exception cref="System.ArgumentNullException"></exception> - public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true) + public IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true) + { + return GetRecursiveChildren(user, i => true); + } + + public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter) { if (user == null) { throw new ArgumentNullException("user"); } - var list = new List<BaseItem>(); + var result = new Dictionary<Guid, BaseItem>(); - var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, false, true); + AddChildren(user, true, result, false, true, filter); - return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list; + return result.Values; } /// <summary> @@ -911,9 +940,14 @@ namespace MediaBrowser.Controller.Entities /// <returns>IList{BaseItem}.</returns> public IList<BaseItem> GetRecursiveChildren() { + return GetRecursiveChildren(i => true); + } + + public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter) + { var list = new List<BaseItem>(); - AddChildrenToList(list, true, null); + AddChildrenToList(list, true, filter); return list; } @@ -1022,6 +1056,15 @@ namespace MediaBrowser.Controller.Entities .Where(i => i.Item2 != null); } + [IgnoreDataMember] + protected override bool SupportsOwnedItems + { + get + { + return base.SupportsOwnedItems || SupportsShortcutChildren; + } + } + protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { var changesFound = false; @@ -1126,8 +1169,7 @@ namespace MediaBrowser.Controller.Entities bool resetPosition) { // Sweep through recursively and update status - var tasks = GetRecursiveChildren(user, true) - .Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual) + var tasks = GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual) .Select(c => c.MarkPlayed(user, datePlayed, resetPosition)); await Task.WhenAll(tasks).ConfigureAwait(false); @@ -1141,8 +1183,7 @@ namespace MediaBrowser.Controller.Entities public override async Task MarkUnplayed(User user) { // Sweep through recursively and update status - var tasks = GetRecursiveChildren(user, true) - .Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual) + var tasks = GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual) .Select(c => c.MarkUnplayed(user)); await Task.WhenAll(tasks).ConfigureAwait(false); @@ -1171,15 +1212,15 @@ namespace MediaBrowser.Controller.Entities return this; } - return RecursiveChildren.FirstOrDefault(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) || + return GetRecursiveChildren(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) || (!i.IsFolder && !i.IsInMixedFolder && string.Equals(i.ContainingFolderPath, path, StringComparison.OrdinalIgnoreCase)) || - i.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase)); + i.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase)) + .FirstOrDefault(); } public override bool IsPlayed(User user) { - return GetRecursiveChildren(user) - .Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual) + return GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual) .All(i => i.IsPlayed(user)); } @@ -1206,8 +1247,7 @@ namespace MediaBrowser.Controller.Entities } else { - children = folder.GetRecursiveChildren(user) - .Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual); + children = folder.GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual); } // Loop through each recursive child diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index bf32d3e63..899e5628f 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -1,10 +1,10 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -38,6 +38,13 @@ namespace MediaBrowser.Controller.Entities public List<Guid> LocalTrailerIds { get; set; } public List<Guid> RemoteTrailerIds { get; set; } + public override bool CanDownload() + { + var locationType = LocationType; + return locationType != LocationType.Remote && + locationType != LocationType.Virtual; + } + /// <summary> /// Gets or sets the tags. /// </summary> @@ -88,7 +95,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> public List<string> MultiPartGameFiles { get; set; } - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var id = this.GetProviderId(MetadataProviders.Gamesdb); @@ -96,7 +103,7 @@ namespace MediaBrowser.Controller.Entities { return "Game-Gamesdb-" + id; } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } public override IEnumerable<string> GetDeletePaths() diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs index 825468954..b246b9388 100644 --- a/MediaBrowser.Controller/Entities/GameGenre.cs +++ b/MediaBrowser.Controller/Entities/GameGenre.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities { @@ -10,7 +11,7 @@ namespace MediaBrowser.Controller.Entities /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "GameGenre-" + Name; } @@ -20,6 +21,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -32,6 +34,7 @@ namespace MediaBrowser.Controller.Entities /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -40,9 +43,19 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.Where(i => (i is Game) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase)); + return inputItems.Where(GetItemFilter()); + } + + public Func<BaseItem, bool> GetItemFilter() + { + return i => (i is Game) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase); } } } diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs index 758498977..cf6916763 100644 --- a/MediaBrowser.Controller/Entities/GameSystem.cs +++ b/MediaBrowser.Controller/Entities/GameSystem.cs @@ -35,13 +35,13 @@ namespace MediaBrowser.Controller.Entities /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { if (!string.IsNullOrEmpty(GameSystemName)) { return "GameSystem-" + GameSystemName; } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } protected override bool GetBlockUnratedValue(UserPolicy config) diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 05442f2b7..e17a5c1d8 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities.Audio; +using System.Runtime.Serialization; +using MediaBrowser.Controller.Entities.Audio; using System; using System.Collections.Generic; using System.Linq; @@ -14,7 +15,7 @@ namespace MediaBrowser.Controller.Entities /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "Genre-" + Name; } @@ -24,6 +25,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -32,10 +34,16 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -46,7 +54,12 @@ namespace MediaBrowser.Controller.Entities public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.Where(i => !(i is Game) && !(i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase)); + return inputItems.Where(GetItemFilter()); + } + + public Func<BaseItem, bool> GetItemFilter() + { + return i => !(i is Game) && !(i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase); } } } diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index 10ddaa474..3643c58b3 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -54,5 +54,10 @@ namespace MediaBrowser.Controller.Entities /// Gets the item identities. /// </summary> List<IItemIdentity> Identities { get; set; } + + /// <summary> + /// Afters the metadata refresh. + /// </summary> + void AfterMetadataRefresh(); } } diff --git a/MediaBrowser.Controller/Entities/IItemByName.cs b/MediaBrowser.Controller/Entities/IItemByName.cs index 70d5b840f..14b69b8fd 100644 --- a/MediaBrowser.Controller/Entities/IItemByName.cs +++ b/MediaBrowser.Controller/Entities/IItemByName.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { @@ -13,6 +14,12 @@ namespace MediaBrowser.Controller.Entities /// <param name="inputItems">The input items.</param> /// <returns>IEnumerable{BaseItem}.</returns> IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems); + + /// <summary> + /// Gets the item filter. + /// </summary> + /// <returns>Func<BaseItem, System.Boolean>.</returns> + Func<BaseItem, bool> GetItemFilter(); } public interface IHasDualAccess : IItemByName diff --git a/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs b/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs index 0fd463155..fbe5a06d0 100644 --- a/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs +++ b/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; - + namespace MediaBrowser.Controller.Entities { /// <summary> @@ -10,10 +8,5 @@ namespace MediaBrowser.Controller.Entities /// </summary> public interface ISupportsBoxSetGrouping { - /// <summary> - /// Gets or sets the box set identifier list. - /// </summary> - /// <value>The box set identifier list.</value> - List<Guid> BoxSetIdList { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 30043682d..e99c11e87 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Controller.Entities public User User { get; set; } - public Func<BaseItem, User, bool> Filter { get; set; } + public Func<BaseItem, bool> Filter { get; set; } public bool? IsFolder { get; set; } public bool? IsFavorite { get; set; } diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 4483c7b0f..d874046ef 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -1,22 +1,22 @@ -using MediaBrowser.Common.Progress; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Movies { /// <summary> /// Class BoxSet /// </summary> - public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IMetadataContainer, IHasShares + public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IMetadataContainer, IHasShares { public List<Share> Shares { get; set; } @@ -54,14 +54,6 @@ namespace MediaBrowser.Controller.Entities.Movies /// <value>The tags.</value> public List<string> Keywords { get; set; } - public string PreferredMetadataLanguage { get; set; } - - /// <summary> - /// Gets or sets the preferred metadata country code. - /// </summary> - /// <value>The preferred metadata country code.</value> - public string PreferredMetadataCountryCode { get; set; } - /// <summary> /// Gets or sets the display order. /// </summary> @@ -82,6 +74,11 @@ namespace MediaBrowser.Controller.Entities.Movies } } + public override bool IsAuthorizedToDelete(User user) + { + return true; + } + /// <summary> /// Gets the trailer ids. /// </summary> @@ -93,6 +90,31 @@ namespace MediaBrowser.Controller.Entities.Movies return list; } + /// <summary> + /// Updates the official rating based on content and returns true or false indicating if it changed. + /// </summary> + /// <returns></returns> + public bool UpdateRatingToContent() + { + var currentOfficialRating = OfficialRating; + + // Gather all possible ratings + var ratings = GetRecursiveChildren() + .Concat(GetLinkedChildren()) + .Where(i => i is Movie || i is Series) + .Select(i => i.OfficialRating) + .Where(i => !string.IsNullOrEmpty(i)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .Select(i => new Tuple<string, int?>(i, LocalizationManager.GetRatingLevel(i))) + .OrderBy(i => i.Item2 ?? 1000) + .Select(i => i.Item1); + + OfficialRating = ratings.FirstOrDefault() ?? currentOfficialRating; + + return !string.Equals(currentOfficialRating ?? string.Empty, OfficialRating ?? string.Empty, + StringComparison.OrdinalIgnoreCase); + } + public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren) { var children = base.GetChildren(user, includeLinkedChildren); @@ -122,34 +144,22 @@ namespace MediaBrowser.Controller.Entities.Movies { // Refresh bottom up, children first, then the boxset // By then hopefully the movies within will have Tmdb collection values - var items = RecursiveChildren.ToList(); + var items = GetRecursiveChildren().ToList(); var totalItems = items.Count; - var percentages = new Dictionary<Guid, double>(totalItems); + var numComplete = 0; // Refresh songs foreach (var item in items) { cancellationToken.ThrowIfCancellationRequested(); - var innerProgress = new ActionableProgress<double>(); - // Avoid implicitly captured closure - var currentChild = item; - innerProgress.RegisterAction(p => - { - lock (percentages) - { - percentages[currentChild.Id] = p / 100; - - var percent = percentages.Values.Sum(); - percent /= totalItems; - percent *= 100; - progress.Report(percent); - } - }); - - // Avoid implicitly captured closure - await RefreshItem(item, refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false); + await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); + + numComplete++; + double percent = numComplete; + percent /= totalItems; + progress.Report(percent * 100); } // Refresh current item @@ -158,13 +168,6 @@ namespace MediaBrowser.Controller.Entities.Movies progress.Report(100); } - private async Task RefreshItem(BaseItem item, MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) - { - await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - - progress.Report(100); - } - public override bool IsVisible(User user) { if (base.IsVisible(user)) diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index b3774cfe0..cfe008bd7 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -25,12 +25,6 @@ namespace MediaBrowser.Controller.Entities.Movies public List<Guid> ThemeVideoIds { get; set; } public List<string> ProductionLocations { get; set; } - /// <summary> - /// This is just a cache to enable quick access by Id - /// </summary> - [IgnoreDataMember] - public List<Guid> BoxSetIdList { get; set; } - public Movie() { SpecialFeatureIds = new List<Guid>(); @@ -40,7 +34,6 @@ namespace MediaBrowser.Controller.Entities.Movies RemoteTrailerIds = new List<Guid>(); ThemeSongIds = new List<Guid>(); ThemeVideoIds = new List<Guid>(); - BoxSetIdList = new List<Guid>(); Taglines = new List<string>(); Keywords = new List<string>(); ProductionLocations = new List<string>(); @@ -107,9 +100,9 @@ namespace MediaBrowser.Controller.Entities.Movies /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { - return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey(); + return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.CreateUserDataKey(); } protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index 4ca8cf1c5..771c62fd6 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -48,21 +48,6 @@ namespace MediaBrowser.Controller.Entities } /// <summary> - /// TODO: Remove - /// </summary> - public string Artist - { - get { return Artists.FirstOrDefault(); } - set - { - if (!string.IsNullOrEmpty(value) && !Artists.Contains(value, StringComparer.OrdinalIgnoreCase)) - { - Artists.Add(value); - } - } - } - - /// <summary> /// Determines whether the specified name has artist. /// </summary> /// <param name="name">The name.</param> @@ -76,9 +61,9 @@ namespace MediaBrowser.Controller.Entities /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { - return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey(); + return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.CreateUserDataKey(); } protected override bool GetBlockUnratedValue(UserPolicy config) diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index fe8d61836..d8cb69ca1 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Providers; +using System.Runtime.Serialization; +using MediaBrowser.Controller.Providers; using System; using System.Collections.Generic; using System.Linq; @@ -15,12 +16,12 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The place of birth.</value> public string PlaceOfBirth { get; set; } - + /// <summary> /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "Person-" + Name; } @@ -35,6 +36,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -43,10 +45,16 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -57,7 +65,13 @@ namespace MediaBrowser.Controller.Entities public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.Where(i => i.People.Any(p => string.Equals(p.Name, Name, StringComparison.OrdinalIgnoreCase))); + return inputItems.Where(GetItemFilter()); + } + + + public Func<BaseItem, bool> GetItemFilter() + { + return i => i.People.Any(p => string.Equals(p.Name, Name, StringComparison.OrdinalIgnoreCase)); } } diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index 0d934ad0a..31bbaf422 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities { @@ -15,12 +16,12 @@ namespace MediaBrowser.Controller.Entities { Tags = new List<string>(); } - + /// <summary> /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "Studio-" + Name; } @@ -30,6 +31,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -38,10 +40,16 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -52,7 +60,13 @@ namespace MediaBrowser.Controller.Entities public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.Where(i => i.Studios.Contains(Name, StringComparer.OrdinalIgnoreCase)); + return inputItems.Where(GetItemFilter()); + } + + + public Func<BaseItem, bool> GetItemFilter() + { + return i => i.Studios.Contains(Name, StringComparer.OrdinalIgnoreCase); } } } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 6b67cebc8..c8408365d 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -56,6 +56,15 @@ namespace MediaBrowser.Controller.Entities.TV } [IgnoreDataMember] + protected override bool SupportsOwnedItems + { + get + { + return IsStacked || MediaSourceCount > 1; + } + } + + [IgnoreDataMember] public int? AiredSeasonNumber { get @@ -117,7 +126,7 @@ namespace MediaBrowser.Controller.Entities.TV /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var series = Series; @@ -126,7 +135,7 @@ namespace MediaBrowser.Controller.Entities.TV return series.GetUserDataKey() + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000"); } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } /// <summary> diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 54db12b6f..a99b8c659 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -81,10 +81,10 @@ namespace MediaBrowser.Controller.Entities.TV protected override IEnumerable<string> GetIndexByOptions() { return new List<string> { - {LocalizedStrings.Instance.GetString("NoneDispPref")}, - {LocalizedStrings.Instance.GetString("PerformerDispPref")}, - {LocalizedStrings.Instance.GetString("DirectorDispPref")}, - {LocalizedStrings.Instance.GetString("YearDispPref")}, + {"None"}, + {"Performer"}, + {"Director"}, + {"Year"}, }; } @@ -92,7 +92,7 @@ namespace MediaBrowser.Controller.Entities.TV /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { if (Series != null) { @@ -100,7 +100,7 @@ namespace MediaBrowser.Controller.Entities.TV return Series.GetUserDataKey() + seasonNo.ToString("000"); } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } /// <summary> @@ -244,7 +244,7 @@ namespace MediaBrowser.Controller.Entities.TV private IEnumerable<Episode> GetEpisodes() { - var episodes = RecursiveChildren.OfType<Episode>(); + var episodes = GetRecursiveChildren().OfType<Episode>(); var series = Series; if (series != null && series.ContainsEpisodesWithoutSeasonFolders) @@ -254,12 +254,12 @@ namespace MediaBrowser.Controller.Entities.TV if (seasonNumber.HasValue) { - list.AddRange(series.RecursiveChildren.OfType<Episode>() + list.AddRange(series.GetRecursiveChildren().OfType<Episode>() .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value)); } else { - list.AddRange(series.RecursiveChildren.OfType<Episode>() + list.AddRange(series.GetRecursiveChildren().OfType<Episode>() .Where(i => !i.ParentIndexNumber.HasValue)); } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 55cfffeb2..619617e9f 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Controller.Localization; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; @@ -14,7 +16,7 @@ namespace MediaBrowser.Controller.Entities.TV /// <summary> /// Class Series /// </summary> - public class Series : Folder, IHasSoundtracks, IHasTrailers, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo<SeriesInfo>, IHasSpecialFeatures + public class Series : Folder, IHasSoundtracks, IHasTrailers, IHasDisplayOrder, IHasLookupInfo<SeriesInfo>, IHasSpecialFeatures, IMetadataContainer { public List<Guid> SpecialFeatureIds { get; set; } public List<Guid> SoundtrackIds { get; set; } @@ -23,12 +25,6 @@ namespace MediaBrowser.Controller.Entities.TV public int? AnimeSeriesIndex { get; set; } - /// <summary> - /// Gets or sets the preferred metadata country code. - /// </summary> - /// <value>The preferred metadata country code.</value> - public string PreferredMetadataCountryCode { get; set; } - public Series() { AirDays = new List<DayOfWeek>(); @@ -93,7 +89,7 @@ namespace MediaBrowser.Controller.Entities.TV { get { - return RecursiveChildren.OfType<Episode>() + return GetRecursiveChildren(i => i is Episode) .Select(i => i.DateCreated) .OrderByDescending(i => i) .FirstOrDefault(); @@ -117,9 +113,9 @@ namespace MediaBrowser.Controller.Entities.TV /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { - return this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Tvcom) ?? base.GetUserDataKey(); + return this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Tvcom) ?? base.CreateUserDataKey(); } /// <summary> @@ -137,10 +133,10 @@ namespace MediaBrowser.Controller.Entities.TV protected override IEnumerable<string> GetIndexByOptions() { return new List<string> { - {LocalizedStrings.Instance.GetString("NoneDispPref")}, - {LocalizedStrings.Instance.GetString("PerformerDispPref")}, - {LocalizedStrings.Instance.GetString("DirectorDispPref")}, - {LocalizedStrings.Instance.GetString("YearDispPref")}, + {"None"}, + {"Performer"}, + {"Director"}, + {"Year"}, }; } @@ -191,6 +187,85 @@ namespace MediaBrowser.Controller.Entities.TV .Cast<Season>(); } + public IEnumerable<Episode> GetEpisodes(User user) + { + var config = user.Configuration; + + return GetEpisodes(user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); + } + + public IEnumerable<Episode> GetEpisodes(User user, bool includeMissing, bool includeVirtualUnaired) + { + var allEpisodes = GetSeasons(user, true, true) + .SelectMany(i => i.GetEpisodes(user, includeMissing, includeVirtualUnaired)) + .Reverse() + .ToList(); + + // Specials could appear twice based on above - once in season 0, once in the aired season + // This depends on settings for that series + // When this happens, remove the duplicate from season 0 + var returnList = new List<Episode>(); + + foreach (var episode in allEpisodes) + { + if (!returnList.Contains(episode)) + { + returnList.Insert(0, episode); + } + } + + return returnList; + } + + public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) + { + // Refresh bottom up, children first, then the boxset + // By then hopefully the movies within will have Tmdb collection values + var items = GetRecursiveChildren().ToList(); + + var seasons = items.OfType<Season>().ToList(); + var otherItems = items.Except(seasons).ToList(); + + var totalItems = seasons.Count + otherItems.Count; + var numComplete = 0; + + refreshOptions = new MetadataRefreshOptions(refreshOptions); + refreshOptions.IsPostRecursiveRefresh = true; + + // Refresh songs + foreach (var item in seasons) + { + cancellationToken.ThrowIfCancellationRequested(); + + await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); + + numComplete++; + double percent = numComplete; + percent /= totalItems; + progress.Report(percent * 100); + } + + // Refresh current item + await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); + + // Refresh all non-songs + foreach (var item in otherItems) + { + cancellationToken.ThrowIfCancellationRequested(); + + await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); + + numComplete++; + double percent = numComplete; + percent /= totalItems; + progress.Report(percent * 100); + } + + await ProviderManager.RefreshMetadata(this, refreshOptions, cancellationToken).ConfigureAwait(false); + + progress.Report(100); + } + public IEnumerable<Episode> GetEpisodes(User user, int seasonNumber) { var config = user.Configuration; @@ -206,8 +281,8 @@ namespace MediaBrowser.Controller.Entities.TV internal IEnumerable<Episode> GetEpisodes(User user, int seasonNumber, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable<Episode> additionalEpisodes) { - var episodes = GetRecursiveChildren(user) - .OfType<Episode>(); + var episodes = GetRecursiveChildren(user, i => i is Episode) + .Cast<Episode>(); episodes = FilterEpisodesBySeason(episodes, seasonNumber, DisplaySpecialsWithSeasons); @@ -262,8 +337,6 @@ namespace MediaBrowser.Controller.Entities.TV return config.BlockUnratedItems.Contains(UnratedItem.Series); } - public string PreferredMetadataLanguage { get; set; } - public SeriesInfo GetLookupInfo() { var info = GetItemLookupInfo<SeriesInfo>(); diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 7a1eef8db..522e6edf6 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -1,12 +1,12 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.Serialization; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -79,7 +79,7 @@ namespace MediaBrowser.Controller.Entities } } - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var key = this.GetProviderId(MetadataProviders.Imdb) ?? this.GetProviderId(MetadataProviders.Tmdb); @@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Entities return key; } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } protected override bool GetBlockUnratedValue(UserPolicy config) diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 626afcfdf..01a7486b3 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The password.</value> public string Password { get; set; } - public string LocalPassword { get; set; } + public string EasyPassword { get; set; } public string ConnectUserName { get; set; } public string ConnectUserId { get; set; } @@ -62,6 +62,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -74,6 +75,7 @@ namespace MediaBrowser.Controller.Entities /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -166,7 +168,7 @@ namespace MediaBrowser.Controller.Entities } // If only the casing is changing, leave the file system alone - if (!UsesIdForConfigurationPath && !newName.Equals(Name, StringComparison.OrdinalIgnoreCase)) + if (!UsesIdForConfigurationPath && !string.Equals(newName, Name, StringComparison.OrdinalIgnoreCase)) { UsesIdForConfigurationPath = true; @@ -177,7 +179,7 @@ namespace MediaBrowser.Controller.Entities // Exceptions will be thrown if these paths already exist if (Directory.Exists(newConfigDirectory)) { - Directory.Delete(newConfigDirectory, true); + FileSystem.DeleteDirectory(newConfigDirectory, true); } if (Directory.Exists(oldConfigurationDirectory)) @@ -227,16 +229,16 @@ namespace MediaBrowser.Controller.Entities /// <returns>System.String.</returns> private string GetConfigurationDirectoryPath(string username) { - if (string.IsNullOrEmpty(username)) - { - throw new ArgumentNullException("username"); - } - var parentPath = ConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath; // Legacy if (!UsesIdForConfigurationPath) { + if (string.IsNullOrEmpty(username)) + { + throw new ArgumentNullException("username"); + } + var safeFolderName = FileSystem.GetValidFilename(username); return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, safeFolderName); diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index a7276e262..b065ae171 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -18,10 +18,13 @@ namespace MediaBrowser.Controller.Entities { public override async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query) { + var user = query.User; + Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); + if (query.Recursive) { - var items = query.User.RootFolder.GetRecursiveChildren(query.User); - return SortAndFilter(items, query); + var items = query.User.RootFolder.GetRecursiveChildren(query.User, filter); + return PostFilterAndSort(items, query); } var result = await UserViewManager.GetUserViews(new UserViewQuery @@ -30,7 +33,7 @@ namespace MediaBrowser.Controller.Entities }, CancellationToken.None).ConfigureAwait(false); - return SortAndFilter(result, query); + return PostFilterAndSort(result.Where(filter), query); } public override bool IsPreSorted diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 0364ff678..5f7ca3d3f 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -40,12 +40,18 @@ namespace MediaBrowser.Controller.Entities return result.Items; } - public override IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true) + public override bool CanDelete() + { + return false; + } + + public override IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter) { var result = GetItems(new InternalItemsQuery { User = user, - Recursive = true + Recursive = true, + Filter = filter }).Result; @@ -63,8 +69,7 @@ namespace MediaBrowser.Controller.Entities { CollectionType.Books, CollectionType.HomeVideos, - CollectionType.Photos, - string.Empty + CollectionType.Photos }; var collectionFolder = folder as ICollectionFolder; diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 166d56c51..b5ca053ec 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -18,6 +18,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MoreLinq; namespace MediaBrowser.Controller.Entities { @@ -117,7 +118,7 @@ namespace MediaBrowser.Controller.Entities return await GetGameView(user, queryParent, query).ConfigureAwait(false); case CollectionType.BoxSets: - return GetResult(GetMediaFolders(user).SelectMany(i => i.GetRecursiveChildren(user)).OfType<BoxSet>(), queryParent, query); + return await GetBoxsetView(queryParent, user, query).ConfigureAwait(false); case CollectionType.TvShows: return await GetTvView(queryParent, user, query).ConfigureAwait(false); @@ -238,7 +239,9 @@ namespace MediaBrowser.Controller.Entities { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }, i => FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } var list = new List<BaseItem>(); @@ -392,27 +395,54 @@ namespace MediaBrowser.Controller.Entities private QueryResult<BaseItem> GetMusicAlbums(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is MusicAlbum), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }, i => (i is MusicAlbum) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetMusicSongs(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is Audio.Audio), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }, i => (i is Audio.Audio) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetMusicLatest(Folder parent, User user, InternalItemsQuery query) { - query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; - query.SortOrder = SortOrder.Descending; + var items = _userViewManager.GetLatestItems(new LatestItemsQuery + { + UserId = user.Id.ToString("N"), + Limit = GetSpecialItemsLimit(), + IncludeItemTypes = new[] { typeof(Audio.Audio).Name }, + ParentId = (parent == null ? null : parent.Id.ToString("N")), + GroupItems = true + + }).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null); + + query.SortBy = new string[] { }; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is MusicVideo || i is Audio.Audio), parent, GetSpecialItemsLimit(), query); + //var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }, i => i is MusicVideo || i is Audio.Audio && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie || i is BoxSet), parent, query); + var recursiveItems = GetRecursiveChildren(parent, user, + new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }) + .Where(i => i is Movie || i is BoxSet); + + //var collections = _collectionManager.CollapseItemsWithinBoxSets(recursiveItems, user).ToList(); + + //if (collections.Count > 0) + //{ + // recursiveItems.AddRange(_collectionManager.CollapseItemsWithinBoxSets(recursiveItems, user)); + // recursiveItems = recursiveItems.DistinctBy(i => i.Id).ToList(); + //} + + return GetResult(recursiveItems, parent, query); } var list = new List<BaseItem>(); @@ -431,45 +461,59 @@ namespace MediaBrowser.Controller.Entities { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => (i is Movie) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetFavoriteSeries(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => (i is Series) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetFavoriteEpisodes(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Episode), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => (i is Episode) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetFavoriteSongs(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is Audio.Audio), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }, i => (i is Audio.Audio) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetFavoriteAlbums(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is MusicAlbum), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }, i => (i is MusicAlbum) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => (i is Movie) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is BoxSet), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => (i is BoxSet) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query) @@ -477,7 +521,9 @@ namespace MediaBrowser.Controller.Entities query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => i is Movie && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query) @@ -486,7 +532,9 @@ namespace MediaBrowser.Controller.Entities query.SortOrder = SortOrder.Descending; query.IsResumable = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => i is Movie && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private async Task<QueryResult<BaseItem>> GetMovieGenres(Folder parent, User user, InternalItemsQuery query) @@ -526,11 +574,30 @@ namespace MediaBrowser.Controller.Entities return GetResult(items, queryParent, query); } + private async Task<QueryResult<BaseItem>> GetBoxsetView(Folder parent, User user, InternalItemsQuery query) + { + return GetResult(GetMediaFolders(user).SelectMany(i => + { + var hasCollectionType = i as ICollectionFolder; + Func<BaseItem, bool> filter = b => b is BoxSet; + + if (hasCollectionType != null && string.Equals(hasCollectionType.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) + { + return i.GetChildren(user, true).Where(filter); + } + + return i.GetRecursiveChildren(user, filter); + + }), parent, query); + } + private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series || i is Season || i is Episode), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => (i is Series || i is Season || i is Episode) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } var list = new List<BaseItem>(); @@ -550,7 +617,8 @@ namespace MediaBrowser.Controller.Entities { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => FilterItem(i, query)); + return PostFilterAndSort(items, parent, null, query); } var list = new List<BaseItem>(); @@ -569,7 +637,9 @@ namespace MediaBrowser.Controller.Entities query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is Game && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private QueryResult<BaseItem> GetRecentlyPlayedGames(Folder parent, User user, InternalItemsQuery query) @@ -578,14 +648,17 @@ namespace MediaBrowser.Controller.Entities query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is Game && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private QueryResult<BaseItem> GetFavoriteGames(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is Game && FilterItem(i, query)); + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query) @@ -593,7 +666,9 @@ namespace MediaBrowser.Controller.Entities query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => i is Episode && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private QueryResult<BaseItem> GetTvNextUp(Folder parent, InternalItemsQuery query) @@ -617,12 +692,16 @@ namespace MediaBrowser.Controller.Entities query.SortOrder = SortOrder.Descending; query.IsResumable = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => i is Episode && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Series>(), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => i is Series && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private async Task<QueryResult<BaseItem>> GetTvGenres(Folder parent, User user, InternalItemsQuery query) @@ -664,14 +743,15 @@ namespace MediaBrowser.Controller.Entities private QueryResult<BaseItem> GetGameSystems(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<GameSystem>(), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is GameSystem && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private async Task<QueryResult<BaseItem>> GetGameGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) { - var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Games }) - .OfType<Game>() - .Where(i => i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase)); + var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Games }, + i => i is Game && i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase)); return GetResult(items, queryParent, query); } @@ -719,29 +799,32 @@ namespace MediaBrowser.Controller.Entities InternalItemsQuery query) where T : BaseItem { - return GetResult(items, queryParent, null, query); + items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager)); + + return PostFilterAndSort(items, queryParent, null, query, _libraryManager); } - private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items, + public bool FilterItem(BaseItem item, InternalItemsQuery query) + { + return Filter(item, query.User, query, _userDataManager, _libraryManager); + } + + private QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, BaseItem queryParent, int? totalRecordLimit, InternalItemsQuery query) - where T : BaseItem { - return SortAndFilter(items, queryParent, totalRecordLimit, query, _libraryManager, _userDataManager); + return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager); } - public static QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items, + public static QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, BaseItem queryParent, int? totalRecordLimit, InternalItemsQuery query, - ILibraryManager libraryManager, - IUserDataManager userDataManager) + ILibraryManager libraryManager) { var user = query.User; - items = items.Where(i => Filter(i, user, query, userDataManager, libraryManager)); - items = FilterVirtualEpisodes(items, query.IsMissing, query.IsVirtualUnaired, @@ -763,6 +846,11 @@ namespace MediaBrowser.Controller.Entities BaseItem queryParent, User user) { + if (items == null) + { + throw new ArgumentNullException("items"); + } + if (CollapseBoxSetItems(query, queryParent, user)) { items = BaseItem.CollectionManager.CollapseItemsWithinBoxSets(items, user); @@ -1140,7 +1228,7 @@ namespace MediaBrowser.Controller.Entities }; } - private static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) + public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) { if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { @@ -1162,7 +1250,7 @@ namespace MediaBrowser.Controller.Entities return false; } - if (query.Filter != null && !query.Filter(item, user)) + if (query.Filter != null && !query.Filter(item)) { return false; } @@ -1612,6 +1700,16 @@ namespace MediaBrowser.Controller.Entities return parent.GetRecursiveChildren(user); } + private IEnumerable<BaseItem> GetRecursiveChildren(Folder parent, User user, IEnumerable<string> viewTypes, Func<BaseItem, bool> filter) + { + if (parent == null || parent is UserView) + { + return GetMediaFolders(user, viewTypes).SelectMany(i => i.GetRecursiveChildren(user, filter)); + } + + return parent.GetRecursiveChildren(user, filter); + } + private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user) { var list = new List<BaseItem>(); diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 3abaf095c..d4507bc33 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -64,6 +64,19 @@ namespace MediaBrowser.Controller.Entities LinkedAlternateVersions = new List<LinkedChild>(); } + public override bool CanDownload() + { + if (VideoType == VideoType.HdDvd || VideoType == VideoType.Dvd || + VideoType == VideoType.BluRay) + { + return false; + } + + var locationType = LocationType; + return locationType != LocationType.Remote && + locationType != LocationType.Virtual; + } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { @@ -409,7 +422,7 @@ namespace MediaBrowser.Controller.Entities public virtual IEnumerable<MediaStream> GetMediaStreams() { - return ItemRepository.GetMediaStreams(new MediaStreamQuery + return MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = Id }); @@ -422,7 +435,7 @@ namespace MediaBrowser.Controller.Entities return null; } - return ItemRepository.GetMediaStreams(new MediaStreamQuery + return MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = Id, Index = DefaultVideoStreamIndex.Value @@ -461,7 +474,8 @@ namespace MediaBrowser.Controller.Entities private static MediaSourceInfo GetVersionInfo(bool enablePathSubstitution, Video i, MediaSourceType type) { - var mediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(); + var mediaStreams = MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }) + .ToList(); var locationType = i.LocationType; diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index 8deb930e8..cf3ad3b6a 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities { @@ -13,7 +15,7 @@ namespace MediaBrowser.Controller.Entities /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "Year-" + Name; } @@ -23,6 +25,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -31,10 +34,16 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -47,8 +56,8 @@ namespace MediaBrowser.Controller.Entities { int year; - var usCulture = new CultureInfo("en-US"); - + var usCulture = new CultureInfo("en-US"); + if (!int.TryParse(Name, NumberStyles.Integer, usCulture, out year)) { return inputItems; @@ -56,5 +65,23 @@ namespace MediaBrowser.Controller.Entities return inputItems.Where(i => i.ProductionYear.HasValue && i.ProductionYear.Value == year); } + + public int? GetYearValue() + { + int i; + + if (int.TryParse(Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out i)) + { + return i; + } + + return null; + } + + public Func<BaseItem, bool> GetItemFilter() + { + var val = GetYearValue(); + return i => i.ProductionYear.HasValue && val.HasValue && i.ProductionYear.Value == val.Value; + } } } |
