diff options
| author | Luke <luke.pulverenti@gmail.com> | 2014-12-14 00:38:07 -0500 |
|---|---|---|
| committer | Luke <luke.pulverenti@gmail.com> | 2014-12-14 00:38:07 -0500 |
| commit | 524293ea79ab61228f8326561be70bcca4d0ea8f (patch) | |
| tree | ccfe163c8edafc8dd14b0b63d48712a6d504de9d /MediaBrowser.Controller/Entities | |
| parent | 00da34b90a2f2fcee4d6aa584e25fccebb375b6d (diff) | |
| parent | 9df9723fa8554df0fd51d777d3f781b0136de926 (diff) | |
Merge pull request #954 from MediaBrowser/dev
3.0.5462.0
Diffstat (limited to 'MediaBrowser.Controller/Entities')
| -rw-r--r-- | MediaBrowser.Controller/Entities/BaseItem.cs | 228 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Folder.cs | 69 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Game.cs | 13 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/IHasImages.cs | 6 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/IHasTrailers.cs | 9 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 33 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Movies/Movie.cs | 31 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/MusicVideo.cs | 36 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Share.cs | 15 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/TV/Series.cs | 15 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Trailer.cs | 6 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/User.cs | 3 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/UserView.cs | 3 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/UserViewBuilder.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Video.cs | 274 |
15 files changed, 366 insertions, 377 deletions
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 990ea49f6..e01b8857f 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -53,16 +53,6 @@ namespace MediaBrowser.Controller.Entities public static string ThemeSongFilename = "theme"; public static string ThemeVideosFolderName = "backdrops"; - public static List<KeyValuePair<string, ExtraType>> ExtraSuffixes = new List<KeyValuePair<string, ExtraType>> - { - new KeyValuePair<string,ExtraType>("-trailer", ExtraType.Trailer), - new KeyValuePair<string,ExtraType>("-deleted", ExtraType.DeletedScene), - new KeyValuePair<string,ExtraType>("-behindthescenes", ExtraType.BehindTheScenes), - new KeyValuePair<string,ExtraType>("-interview", ExtraType.Interview), - new KeyValuePair<string,ExtraType>("-scene", ExtraType.Scene), - new KeyValuePair<string,ExtraType>("-sample", ExtraType.Sample) - }; - public List<ItemImageInfo> ImageInfos { get; set; } [IgnoreDataMember] @@ -222,6 +212,20 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public virtual string FileNameWithoutExtension + { + get + { + if (LocationType == LocationType.FileSystem) + { + return System.IO.Path.GetFileNameWithoutExtension(Path); + } + + return null; + } + } + /// <summary> /// This is just a helper for convenience /// </summary> @@ -361,6 +365,15 @@ namespace MediaBrowser.Controller.Entities } } + public bool ContainsPerson(string name) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentNullException("name"); + } + return People.Any(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase)); + } + public string GetInternalMetadataPath() { return GetInternalMetadataPath(ConfigurationManager.ApplicationPaths.InternalMetadataPath); @@ -594,118 +607,6 @@ namespace MediaBrowser.Controller.Entities } /// <summary> - /// Loads local trailers from the file system - /// </summary> - /// <returns>List{Video}.</returns> - private IEnumerable<Trailer> LoadLocalTrailers(List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService) - { - var files = fileSystemChildren.OfType<DirectoryInfo>() - .Where(i => string.Equals(i.Name, TrailerFolderName, StringComparison.OrdinalIgnoreCase)) - .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)) - .ToList(); - - var extraTypes = new List<ExtraType> { ExtraType.Trailer }; - var suffixes = ExtraSuffixes.Where(i => extraTypes.Contains(i.Value)) - .Select(i => i.Key) - .ToList(); - - files.AddRange(fileSystemChildren.OfType<FileInfo>() - .Where(i => - { - var nameEithoutExtension = FileSystem.GetFileNameWithoutExtension(i); - - if (!suffixes.Any(s => nameEithoutExtension.EndsWith(s, StringComparison.OrdinalIgnoreCase))) - { - return false; - } - - return !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase); - })); - - return LibraryManager.ResolvePaths<Trailer>(files, directoryService, null).Select(video => - { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = LibraryManager.GetItemById(video.Id) as Trailer; - - if (dbItem != null) - { - video = dbItem; - } - - if (video != null) - { - video.ExtraType = ExtraType.Trailer; - } - - return video; - - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path).ToList(); - } - - protected IEnumerable<Video> LoadSpecialFeatures(List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService) - { - var files = fileSystemChildren.OfType<DirectoryInfo>() - .Where(i => string.Equals(i.Name, "extras", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "specials", StringComparison.OrdinalIgnoreCase)) - .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)) - .ToList(); - - var extraTypes = new List<ExtraType> { ExtraType.BehindTheScenes, ExtraType.DeletedScene, ExtraType.Interview, ExtraType.Sample, ExtraType.Scene, ExtraType.Clip }; - var suffixes = ExtraSuffixes.Where(i => extraTypes.Contains(i.Value)) - .Select(i => i.Key) - .ToList(); - - files.AddRange(fileSystemChildren.OfType<FileInfo>() - .Where(i => - { - var nameEithoutExtension = FileSystem.GetFileNameWithoutExtension(i); - - if (!suffixes.Any(s => nameEithoutExtension.EndsWith(s, StringComparison.OrdinalIgnoreCase))) - { - return false; - } - - return !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase); - })); - - return LibraryManager.ResolvePaths<Video>(files, directoryService, null).Select(video => - { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = LibraryManager.GetItemById(video.Id) as Video; - - if (dbItem != null) - { - video = dbItem; - } - - if (video != null) - { - SetExtraTypeFromFilename(video); - } - - return video; - - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path).ToList(); - } - - private void SetExtraTypeFromFilename(Video item) - { - var name = System.IO.Path.GetFileNameWithoutExtension(item.Path) ?? string.Empty; - - foreach (var suffix in ExtraSuffixes) - { - if (name.EndsWith(suffix.Key, StringComparison.OrdinalIgnoreCase)) - { - item.ExtraType = suffix.Value; - return; - } - } - - item.ExtraType = ExtraType.Clip; - } - - /// <summary> /// Loads the theme songs. /// </summary> /// <returns>List{Audio.Audio}.</returns> @@ -721,7 +622,9 @@ namespace MediaBrowser.Controller.Entities .Where(i => string.Equals(FileSystem.GetFileNameWithoutExtension(i), ThemeSongFilename, StringComparison.OrdinalIgnoreCase)) ); - return LibraryManager.ResolvePaths<Audio.Audio>(files, directoryService, null).Select(audio => + return LibraryManager.ResolvePaths(files, directoryService, null) + .OfType<Audio.Audio>() + .Select(audio => { // Try to retrieve it from the db. If we don't find it, use the resolved version var dbItem = LibraryManager.GetItemById(audio.Id) as Audio.Audio; @@ -731,10 +634,7 @@ namespace MediaBrowser.Controller.Entities audio = dbItem; } - if (audio != null) - { - audio.ExtraType = ExtraType.ThemeSong; - } + audio.ExtraType = ExtraType.ThemeSong; return audio; @@ -752,7 +652,9 @@ namespace MediaBrowser.Controller.Entities .Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase)) .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)); - return LibraryManager.ResolvePaths<Video>(files, directoryService, null).Select(item => + return LibraryManager.ResolvePaths(files, directoryService, null) + .OfType<Video>() + .Select(item => { // Try to retrieve it from the db. If we don't find it, use the resolved version var dbItem = LibraryManager.GetItemById(item.Id) as Video; @@ -762,10 +664,7 @@ namespace MediaBrowser.Controller.Entities item = dbItem; } - if (item != null) - { - item.ExtraType = ExtraType.ThemeVideo; - } + item.ExtraType = ExtraType.ThemeVideo; return item; @@ -870,7 +769,8 @@ namespace MediaBrowser.Controller.Entities private async Task<bool> RefreshLocalTrailers(IHasTrailers item, MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - var newItems = LoadLocalTrailers(fileSystemChildren, options.DirectoryService).ToList(); + var newItems = LibraryManager.FindTrailers(this, fileSystemChildren, options.DirectoryService).ToList(); + var newItemIds = newItems.Select(i => i.Id).ToList(); var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds); @@ -995,6 +895,28 @@ namespace MediaBrowser.Controller.Entities return Id.ToString(); } + internal virtual bool IsValidFromResolver(BaseItem newItem) + { + var current = this; + + var currentAsPlaceHolder = current as ISupportsPlaceHolders; + + if (currentAsPlaceHolder != null) + { + var newHasPlaceHolder = newItem as ISupportsPlaceHolders; + + if (newHasPlaceHolder != null) + { + if (currentAsPlaceHolder.IsPlaceHolder != newHasPlaceHolder.IsPlaceHolder) + { + return false; + } + } + } + + return current.IsInMixedFolder == newItem.IsInMixedFolder; + } + /// <summary> /// Gets the preferred metadata language. /// </summary> @@ -1390,7 +1312,7 @@ namespace MediaBrowser.Controller.Entities /// <param name="resetPosition">if set to <c>true</c> [reset position].</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException"></exception> - public virtual async Task MarkPlayed(User user, + public virtual async Task MarkPlayed(User user, DateTime? datePlayed, bool resetPosition) { @@ -1778,7 +1700,8 @@ namespace MediaBrowser.Controller.Entities Name = Name, ProviderIds = ProviderIds, IndexNumber = IndexNumber, - ParentIndexNumber = ParentIndexNumber + ParentIndexNumber = ParentIndexNumber, + Year = ProductionYear }; } @@ -1820,9 +1743,42 @@ namespace MediaBrowser.Controller.Entities if (pct > 0) { pct = userData.PlaybackPositionTicks / pct; - dto.PlayedPercentage = 100 * pct; + + if (pct > 0) + { + dto.PlayedPercentage = 100 * pct; + } } } } + + protected Task RefreshMetadataForOwnedVideo(MetadataRefreshOptions options, string path, CancellationToken cancellationToken) + { + var newOptions = new MetadataRefreshOptions(options.DirectoryService) + { + ImageRefreshMode = options.ImageRefreshMode, + MetadataRefreshMode = options.MetadataRefreshMode, + ReplaceAllMetadata = options.ReplaceAllMetadata + }; + + var id = LibraryManager.GetNewItemId(path, typeof(Video)); + + // Try to retrieve it from the db. If we don't find it, use the resolved version + var video = LibraryManager.GetItemById(id) as Video; + + if (video == null) + { + video = LibraryManager.ResolvePath(new FileInfo(path)) as Video; + + newOptions.ForceSave = true; + } + + if (video == null) + { + return Task.FromResult(true); + } + + return video.RefreshMetadata(newOptions, cancellationToken); + } } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 34f52aac5..87ad9c380 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Progress; +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; @@ -59,6 +58,20 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override string FileNameWithoutExtension + { + get + { + if (LocationType == LocationType.FileSystem) + { + return System.IO.Path.GetFileName(Path); + } + + return null; + } + } + /// <summary> /// Gets or sets a value indicating whether this instance is physical root. /// </summary> @@ -103,7 +116,7 @@ namespace MediaBrowser.Controller.Entities if (item.Id == Guid.Empty) { - item.Id = item.Path.GetMBId(item.GetType()); + item.Id = LibraryManager.GetNewItemId(item.Path, item.GetType()); } if (ActualChildren.Any(i => i.Id == item.Id)) @@ -364,47 +377,7 @@ namespace MediaBrowser.Controller.Entities private bool IsValidFromResolver(BaseItem current, BaseItem newItem) { - var currentAsVideo = current as Video; - - if (currentAsVideo != null) - { - var newAsVideo = newItem as Video; - - if (newAsVideo != null) - { - if (currentAsVideo.IsPlaceHolder != newAsVideo.IsPlaceHolder) - { - return false; - } - if (currentAsVideo.IsMultiPart != newAsVideo.IsMultiPart) - { - return false; - } - if (currentAsVideo.HasLocalAlternateVersions != newAsVideo.HasLocalAlternateVersions) - { - return false; - } - } - } - else - { - var currentAsPlaceHolder = current as ISupportsPlaceHolders; - - if (currentAsPlaceHolder != null) - { - var newHasPlaceHolder = newItem as ISupportsPlaceHolders; - - if (newHasPlaceHolder != null) - { - if (currentAsPlaceHolder.IsPlaceHolder != newHasPlaceHolder.IsPlaceHolder) - { - return false; - } - } - } - } - - return current.IsInMixedFolder == newItem.IsInMixedFolder; + return current.IsValidFromResolver(newItem); } /// <summary> @@ -737,7 +710,7 @@ namespace MediaBrowser.Controller.Entities { var collectionType = LibraryManager.FindCollectionType(this); - return LibraryManager.ResolvePaths<BaseItem>(GetFileSystemChildren(directoryService), directoryService, this, collectionType); + return LibraryManager.ResolvePaths(GetFileSystemChildren(directoryService), directoryService, this, collectionType); } /// <summary> @@ -782,6 +755,12 @@ namespace MediaBrowser.Controller.Entities private BaseItem RetrieveChild(BaseItem child) { + if (child.Id == Guid.Empty) + { + Logger.Error("Item found with empty Id: " + (child.Path ?? child.Name)); + return null; + } + var item = LibraryManager.GetMemoryItemById(child.Id); if (item != null) diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index 062bdfa88..e4d032359 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -28,12 +28,14 @@ namespace MediaBrowser.Controller.Entities SoundtrackIds = new List<Guid>(); RemoteTrailers = new List<MediaUrl>(); LocalTrailerIds = new List<Guid>(); + RemoteTrailerIds = new List<Guid>(); ThemeSongIds = new List<Guid>(); ThemeVideoIds = new List<Guid>(); Tags = new List<string>(); } public List<Guid> LocalTrailerIds { get; set; } + public List<Guid> RemoteTrailerIds { get; set; } /// <summary> /// Gets or sets the tags. @@ -119,5 +121,16 @@ namespace MediaBrowser.Controller.Entities return id; } + + /// <summary> + /// Gets the trailer ids. + /// </summary> + /// <returns>List<Guid>.</returns> + public List<Guid> GetTrailerIds() + { + var list = LocalTrailerIds.ToList(); + list.AddRange(RemoteTrailerIds); + return list; + } } } diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index 5c523d2e3..5aafc8eb3 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -22,6 +22,12 @@ namespace MediaBrowser.Controller.Entities string Path { get; set; } /// <summary> + /// Gets the file name without extension. + /// </summary> + /// <value>The file name without extension.</value> + string FileNameWithoutExtension { get; } + + /// <summary> /// Gets the identifier. /// </summary> /// <value>The identifier.</value> diff --git a/MediaBrowser.Controller/Entities/IHasTrailers.cs b/MediaBrowser.Controller/Entities/IHasTrailers.cs index 47779064b..bc1c7d875 100644 --- a/MediaBrowser.Controller/Entities/IHasTrailers.cs +++ b/MediaBrowser.Controller/Entities/IHasTrailers.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { - public interface IHasTrailers + public interface IHasTrailers : IHasProviderIds { /// <summary> /// Gets or sets the remote trailers. @@ -17,5 +17,12 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The local trailer ids.</value> List<Guid> LocalTrailerIds { get; set; } + List<Guid> RemoteTrailerIds { get; set; } + + /// <summary> + /// Gets the trailer ids. + /// </summary> + /// <returns>List<Guid>.</returns> + List<Guid> GetTrailerIds(); } } diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 705cf9057..9dc600675 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -15,15 +15,19 @@ namespace MediaBrowser.Controller.Entities.Movies /// <summary> /// Class BoxSet /// </summary> - public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IMetadataContainer + public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IMetadataContainer, IHasShares { + public List<Share> Shares { get; set; } + public BoxSet() { RemoteTrailers = new List<MediaUrl>(); LocalTrailerIds = new List<Guid>(); + RemoteTrailerIds = new List<Guid>(); DisplayOrder = ItemSortBy.PremiereDate; Keywords = new List<string>(); + Shares = new List<Share>(); } protected override bool FilterLinkedChildrenPerUser @@ -35,6 +39,7 @@ namespace MediaBrowser.Controller.Entities.Movies } public List<Guid> LocalTrailerIds { get; set; } + public List<Guid> RemoteTrailerIds { get; set; } /// <summary> /// Gets or sets the remote trailers. @@ -76,6 +81,17 @@ namespace MediaBrowser.Controller.Entities.Movies } } + /// <summary> + /// Gets the trailer ids. + /// </summary> + /// <returns>List<Guid>.</returns> + public List<Guid> GetTrailerIds() + { + var list = LocalTrailerIds.ToList(); + list.AddRange(RemoteTrailerIds); + return list; + } + public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren) { var children = base.GetChildren(user, includeLinkedChildren); @@ -147,5 +163,20 @@ namespace MediaBrowser.Controller.Entities.Movies progress.Report(100); } + + public override bool IsVisible(User user) + { + if (base.IsVisible(user)) + { + var userId = user.Id.ToString("N"); + + return Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase)) || + + // Need to support this for boxsets created prior to the creation of Shares + Shares.Count == 0; + } + + return false; + } } } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 686abdaf5..e749d89e4 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -36,6 +36,7 @@ namespace MediaBrowser.Controller.Entities.Movies SoundtrackIds = new List<Guid>(); RemoteTrailers = new List<MediaUrl>(); LocalTrailerIds = new List<Guid>(); + RemoteTrailerIds = new List<Guid>(); ThemeSongIds = new List<Guid>(); ThemeVideoIds = new List<Guid>(); BoxSetIdList = new List<Guid>(); @@ -49,6 +50,7 @@ namespace MediaBrowser.Controller.Entities.Movies public float? Metascore { get; set; } public List<Guid> LocalTrailerIds { get; set; } + public List<Guid> RemoteTrailerIds { get; set; } public List<string> Keywords { get; set; } public List<MediaUrl> RemoteTrailers { get; set; } @@ -90,6 +92,17 @@ namespace MediaBrowser.Controller.Entities.Movies public string TmdbCollectionName { get; set; } /// <summary> + /// Gets the trailer ids. + /// </summary> + /// <returns>List<Guid>.</returns> + public List<Guid> GetTrailerIds() + { + var list = LocalTrailerIds.ToList(); + list.AddRange(RemoteTrailerIds); + return list; + } + + /// <summary> /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> @@ -119,7 +132,7 @@ namespace MediaBrowser.Controller.Entities.Movies private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - var newItems = LoadSpecialFeatures(fileSystemChildren, options.DirectoryService).ToList(); + var newItems = LibraryManager.FindExtras(this, fileSystemChildren, options.DirectoryService).ToList(); var newItemIds = newItems.Select(i => i.Id).ToList(); var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds); @@ -158,6 +171,22 @@ namespace MediaBrowser.Controller.Entities.Movies ProductionYear = yearInName; hasChanges = true; } + else + { + // Try to get the year from the folder name + if (!IsInMixedFolder) + { + info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath)); + + yearInName = info.Year; + + if (yearInName.HasValue) + { + ProductionYear = yearInName; + hasChanges = true; + } + } + } } return hasChanges; diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index 015e4b4ae..d7cd62aa6 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -89,5 +89,41 @@ namespace MediaBrowser.Controller.Entities { return GetItemLookupInfo<MusicVideoInfo>(); } + + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + if (!ProductionYear.HasValue) + { + var info = LibraryManager.ParseName(Name); + + var yearInName = info.Year; + + if (yearInName.HasValue) + { + ProductionYear = yearInName; + hasChanges = true; + } + else + { + // Try to get the year from the folder name + if (!IsInMixedFolder) + { + info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath)); + + yearInName = info.Year; + + if (yearInName.HasValue) + { + ProductionYear = yearInName; + hasChanges = true; + } + } + } + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/Share.cs b/MediaBrowser.Controller/Entities/Share.cs new file mode 100644 index 000000000..e194f6238 --- /dev/null +++ b/MediaBrowser.Controller/Entities/Share.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Entities +{ + public interface IHasShares + { + List<Share> Shares { get; set; } + } + + public class Share + { + public string UserId { get; set; } + public bool CanEdit { get; set; } + } +} diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 3d1051b18..4c0d1fdfb 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -36,6 +36,7 @@ namespace MediaBrowser.Controller.Entities.TV SoundtrackIds = new List<Guid>(); RemoteTrailers = new List<MediaUrl>(); LocalTrailerIds = new List<Guid>(); + RemoteTrailerIds = new List<Guid>(); DisplaySpecialsWithSeasons = true; } @@ -57,7 +58,8 @@ namespace MediaBrowser.Controller.Entities.TV public bool DisplaySpecialsWithSeasons { get; set; } public List<Guid> LocalTrailerIds { get; set; } - + public List<Guid> RemoteTrailerIds { get; set; } + public List<MediaUrl> RemoteTrailers { get; set; } /// <summary> @@ -109,6 +111,17 @@ namespace MediaBrowser.Controller.Entities.TV return this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Tvcom) ?? base.GetUserDataKey(); } + /// <summary> + /// Gets the trailer ids. + /// </summary> + /// <returns>List<Guid>.</returns> + public List<Guid> GetTrailerIds() + { + var list = LocalTrailerIds.ToList(); + list.AddRange(RemoteTrailerIds); + return list; + } + // Studio, Genre and Rating will all be the same so makes no sense to index by these protected override IEnumerable<string> GetIndexByOptions() { diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index bbbf2358f..bb165d790 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -12,7 +12,8 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Class Trailer /// </summary> - public class Trailer : Video, IHasCriticRating, IHasSoundtracks, IHasProductionLocations, IHasBudget, IHasTrailers, IHasKeywords, IHasTaglines, IHasMetascore, IHasLookupInfo<TrailerInfo> + [Obsolete] + public class Trailer : Video, IHasCriticRating, IHasSoundtracks, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTaglines, IHasMetascore, IHasLookupInfo<TrailerInfo> { public List<Guid> SoundtrackIds { get; set; } @@ -23,15 +24,12 @@ namespace MediaBrowser.Controller.Entities RemoteTrailers = new List<MediaUrl>(); Taglines = new List<string>(); SoundtrackIds = new List<Guid>(); - LocalTrailerIds = new List<Guid>(); Keywords = new List<string>(); ProductionLocations = new List<string>(); } public float? Metascore { get; set; } - public List<Guid> LocalTrailerIds { get; set; } - public List<MediaUrl> RemoteTrailers { get; set; } public List<string> Keywords { get; set; } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 0bbd2eeca..3fa0a0435 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Connect; using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Users; using System; using System.IO; using System.Linq; @@ -287,7 +288,7 @@ namespace MediaBrowser.Controller.Entities var localTime = date.ToLocalTime(); - return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek) && + return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek) && IsWithinTime(schedule, localTime); } diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 7674dc1d3..926ffa19c 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -63,8 +63,7 @@ namespace MediaBrowser.Controller.Entities { CollectionType.Books, CollectionType.HomeVideos, - CollectionType.Photos, - CollectionType.Trailers + CollectionType.Photos }; var collectionFolder = folder as ICollectionFolder; diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index aff4af468..166d56c51 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -1428,7 +1428,7 @@ namespace MediaBrowser.Controller.Entities var hasTrailers = item as IHasTrailers; if (hasTrailers != null) { - trailerCount = hasTrailers.LocalTrailerIds.Count; + trailerCount = hasTrailers.GetTrailerIds().Count; } var ok = val ? trailerCount > 0 : trailerCount == 0; diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 1c59b8bfb..6b098cbd8 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -1,12 +1,10 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -19,24 +17,23 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Class Video /// </summary> - public class Video : BaseItem, - IHasAspectRatio, - IHasTags, + public class Video : BaseItem, + IHasAspectRatio, + IHasTags, ISupportsPlaceHolders, IHasMediaSources, IHasShortOverview, IHasPreferredMetadataLanguage, IThemeMedia { - public bool IsMultiPart { get; set; } - public bool HasLocalAlternateVersions { get; set; } public Guid? PrimaryVersionId { get; set; } - public List<Guid> AdditionalPartIds { get; set; } - public List<Guid> LocalAlternateVersionIds { get; set; } + public List<string> AdditionalParts { get; set; } + public List<string> LocalAlternateVersions { get; set; } + public List<LinkedChild> LinkedAlternateVersions { get; set; } public bool IsThemeMedia { get; set; } - + public string FormatName { get; set; } public long? Size { get; set; } public string Container { get; set; } @@ -56,12 +53,12 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The timestamp.</value> public TransportStreamTimestamp? Timestamp { get; set; } - + public Video() { PlayableStreamFileNames = new List<string>(); - AdditionalPartIds = new List<Guid>(); - LocalAlternateVersionIds = new List<Guid>(); + AdditionalParts = new List<string>(); + LocalAlternateVersions = new List<string>(); Tags = new List<string>(); SubtitleFiles = new List<string>(); LinkedAlternateVersions = new List<LinkedChild>(); @@ -78,11 +75,31 @@ namespace MediaBrowser.Controller.Entities { get { - return LinkedAlternateVersions.Count + LocalAlternateVersionIds.Count + 1; + return LinkedAlternateVersions.Count + LocalAlternateVersions.Count + 1; } } - public List<LinkedChild> LinkedAlternateVersions { get; set; } + [IgnoreDataMember] + public bool IsStacked + { + get { return AdditionalParts.Count > 0; } + } + + [IgnoreDataMember] + public bool HasLocalAlternateVersions + { + get { return LocalAlternateVersions.Count > 0; } + } + + public IEnumerable<Guid> GetAdditionalPartIds() + { + return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video))); + } + + public IEnumerable<Guid> GetLocalAlternateVersionIds() + { + return LocalAlternateVersions.Select(i => LibraryManager.GetNewItemId(i, typeof(Video))); + } /// <summary> /// Gets the linked children. @@ -90,7 +107,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>IEnumerable{BaseItem}.</returns> public IEnumerable<Video> GetAlternateVersions() { - var filesWithinSameDirectory = LocalAlternateVersionIds + var filesWithinSameDirectory = GetLocalAlternateVersionIds() .Select(i => LibraryManager.GetItemById(i)) .Where(i => i != null) .OfType<Video>(); @@ -116,7 +133,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>IEnumerable{Video}.</returns> public IEnumerable<Video> GetAdditionalParts() { - return AdditionalPartIds + return GetAdditionalPartIds() .Select(i => LibraryManager.GetItemById(i)) .Where(i => i != null) .OfType<Video>() @@ -200,7 +217,7 @@ namespace MediaBrowser.Controller.Entities { get { - if (IsMultiPart) + if (IsStacked) { return System.IO.Path.GetDirectoryName(Path); } @@ -218,6 +235,46 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override string FileNameWithoutExtension + { + get + { + if (LocationType == LocationType.FileSystem) + { + if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd || VideoType == VideoType.HdDvd) + { + return System.IO.Path.GetFileName(Path); + } + + return System.IO.Path.GetFileNameWithoutExtension(Path); + } + + return null; + } + } + + internal override bool IsValidFromResolver(BaseItem newItem) + { + var current = this; + + var newAsVideo = newItem as Video; + + if (newAsVideo != null) + { + if (!current.AdditionalParts.SequenceEqual(newAsVideo.AdditionalParts, StringComparer.OrdinalIgnoreCase)) + { + return false; + } + if (!current.LocalAlternateVersions.SequenceEqual(newAsVideo.LocalAlternateVersions, StringComparer.OrdinalIgnoreCase)) + { + return false; + } + } + + return base.IsValidFromResolver(newItem); + } + public string MainFeaturePlaylistName { get; set; } /// <summary> @@ -263,37 +320,34 @@ namespace MediaBrowser.Controller.Entities { var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + if (IsStacked) + { + var tasks = AdditionalParts + .Select(i => RefreshMetadataForOwnedVideo(options, i, cancellationToken)); + + await Task.WhenAll(tasks).ConfigureAwait(false); + } + // Must have a parent to have additional parts or alternate versions // In other words, it must be part of the Parent/Child tree // The additional parts won't have additional parts themselves if (LocationType == LocationType.FileSystem && Parent != null) { - if (IsMultiPart) - { - var additionalPartsChanged = await RefreshAdditionalParts(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); - - if (additionalPartsChanged) - { - hasChanges = true; - } - } - else + if (!IsStacked) { RefreshLinkedAlternateVersions(); - var additionalPartsChanged = await RefreshAlternateVersionsWithinSameDirectory(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + var tasks = LocalAlternateVersions + .Select(i => RefreshMetadataForOwnedVideo(options, i, cancellationToken)); - if (additionalPartsChanged) - { - hasChanges = true; - } + await Task.WhenAll(tasks).ConfigureAwait(false); } } return hasChanges; } - private bool RefreshLinkedAlternateVersions() + private void RefreshLinkedAlternateVersions() { foreach (var child in LinkedAlternateVersions) { @@ -303,111 +357,13 @@ namespace MediaBrowser.Controller.Entities child.ItemId = null; } } - - return false; - } - - /// <summary> - /// Refreshes the additional parts. - /// </summary> - /// <param name="options">The options.</param> - /// <param name="fileSystemChildren">The file system children.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{System.Boolean}.</returns> - private async Task<bool> RefreshAdditionalParts(MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) - { - var newItems = LoadAdditionalParts(fileSystemChildren, options.DirectoryService).ToList(); - - var newItemIds = newItems.Select(i => i.Id).ToList(); - - var itemsChanged = !AdditionalPartIds.SequenceEqual(newItemIds); - - var tasks = newItems.Select(i => i.RefreshMetadata(options, cancellationToken)); - - await Task.WhenAll(tasks).ConfigureAwait(false); - - AdditionalPartIds = newItemIds; - - return itemsChanged; - } - - /// <summary> - /// Loads the additional parts. - /// </summary> - /// <returns>IEnumerable{Video}.</returns> - private IEnumerable<Video> LoadAdditionalParts(IEnumerable<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService) - { - var files = LibraryManager.GetAdditionalParts(Path, VideoType, fileSystemChildren); - - return LibraryManager.ResolvePaths<Video>(files, directoryService, null).Select(video => - { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = LibraryManager.GetItemById(video.Id) as Video; - - if (dbItem != null) - { - video = dbItem; - } - - return video; - - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path).ToList(); - } - - private async Task<bool> RefreshAlternateVersionsWithinSameDirectory(MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) - { - var newItems = HasLocalAlternateVersions ? - LoadAlternateVersionsWithinSameDirectory(fileSystemChildren, options.DirectoryService).ToList() : - new List<Video>(); - - var newItemIds = newItems.Select(i => i.Id).ToList(); - - var itemsChanged = !LocalAlternateVersionIds.SequenceEqual(newItemIds); - - var tasks = newItems.Select(i => RefreshAlternateVersion(options, i, cancellationToken)); - - await Task.WhenAll(tasks).ConfigureAwait(false); - - LocalAlternateVersionIds = newItemIds; - - return itemsChanged; - } - - private Task RefreshAlternateVersion(MetadataRefreshOptions options, Video video, CancellationToken cancellationToken) - { - var currentImagePath = video.GetImagePath(ImageType.Primary); - var ownerImagePath = this.GetImagePath(ImageType.Primary); - - var newOptions = new MetadataRefreshOptions(options.DirectoryService) - { - ImageRefreshMode = options.ImageRefreshMode, - MetadataRefreshMode = options.MetadataRefreshMode, - ReplaceAllMetadata = options.ReplaceAllMetadata - }; - - if (!string.Equals(currentImagePath, ownerImagePath, StringComparison.OrdinalIgnoreCase)) - { - newOptions.ForceSave = true; - - if (string.IsNullOrWhiteSpace(ownerImagePath)) - { - video.ImageInfos.Clear(); - } - else - { - video.SetImagePath(ImageType.Primary, ownerImagePath); - } - } - - return video.RefreshMetadata(newOptions, cancellationToken); } public override async Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) { await base.UpdateToRepository(updateReason, cancellationToken).ConfigureAwait(false); - foreach (var item in LocalAlternateVersionIds.Select(i => LibraryManager.GetItemById(i))) + foreach (var item in GetLocalAlternateVersionIds().Select(i => LibraryManager.GetItemById(i))) { item.ImageInfos = ImageInfos; item.Overview = Overview; @@ -422,56 +378,6 @@ namespace MediaBrowser.Controller.Entities } } - /// <summary> - /// Loads the additional parts. - /// </summary> - /// <returns>IEnumerable{Video}.</returns> - private IEnumerable<Video> LoadAlternateVersionsWithinSameDirectory(IEnumerable<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService) - { - IEnumerable<FileSystemInfo> files; - - // Only support this for video files. For folder rips, they'll have to use the linking feature - if (VideoType == VideoType.VideoFile || VideoType == VideoType.Iso) - { - var path = Path; - - var filenamePrefix = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(path)); - - files = fileSystemChildren.Where(i => - { - if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory) - { - return false; - } - - return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && - LibraryManager.IsVideoFile(i.FullName) && - i.Name.StartsWith(filenamePrefix + " - ", StringComparison.OrdinalIgnoreCase); - }); - } - else - { - files = new List<FileSystemInfo>(); - } - - return LibraryManager.ResolvePaths<Video>(files, directoryService, null).Select(video => - { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = LibraryManager.GetItemById(video.Id) as Video; - - if (dbItem != null) - { - video = dbItem; - } - - video.PrimaryVersionId = Id; - - return video; - - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path).ToList(); - } - public override IEnumerable<string> GetDeletePaths() { if (!IsInMixedFolder) @@ -539,7 +445,7 @@ namespace MediaBrowser.Controller.Entities var mediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(); var locationType = i.LocationType; - + var info = new MediaSourceInfo { Id = i.Id.ToString("N"), |
