diff options
Diffstat (limited to 'MediaBrowser.Controller/Entities/Video.cs')
| -rw-r--r-- | MediaBrowser.Controller/Entities/Video.cs | 161 |
1 files changed, 153 insertions, 8 deletions
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 10034d7e5..e30458dd8 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -19,15 +19,63 @@ namespace MediaBrowser.Controller.Entities public class Video : BaseItem, IHasMediaStreams, IHasAspectRatio, IHasTags, ISupportsPlaceHolders { public bool IsMultiPart { get; set; } + public bool HasLocalAlternateVersions { get; set; } public List<Guid> AdditionalPartIds { get; set; } + public List<Guid> AlternateVersionIds { get; set; } public Video() { PlayableStreamFileNames = new List<string>(); AdditionalPartIds = new List<Guid>(); + AlternateVersionIds = new List<Guid>(); Tags = new List<string>(); SubtitleFiles = new List<string>(); + LinkedAlternateVersions = new List<LinkedChild>(); + } + + [IgnoreDataMember] + public bool HasAlternateVersions + { + get + { + return HasLocalAlternateVersions || LinkedAlternateVersions.Count > 0; + } + } + + public List<LinkedChild> LinkedAlternateVersions { get; set; } + + /// <summary> + /// Gets the linked children. + /// </summary> + /// <returns>IEnumerable{BaseItem}.</returns> + public IEnumerable<BaseItem> GetAlternateVersions() + { + var filesWithinSameDirectory = AlternateVersionIds + .Select(i => LibraryManager.GetItemById(i)) + .Where(i => i != null) + .OfType<Video>(); + + var linkedVersions = LinkedAlternateVersions + .Select(GetLinkedChild) + .Where(i => i != null) + .OfType<Video>(); + + return filesWithinSameDirectory.Concat(linkedVersions) + .OrderBy(i => i.SortName); + } + + /// <summary> + /// Gets the additional parts. + /// </summary> + /// <returns>IEnumerable{Video}.</returns> + public IEnumerable<Video> GetAdditionalParts() + { + return AdditionalPartIds + .Select(i => LibraryManager.GetItemById(i)) + .Where(i => i != null) + .OfType<Video>() + .OrderBy(i => i.SortName); } /// <summary> @@ -43,13 +91,13 @@ namespace MediaBrowser.Controller.Entities public bool HasSubtitles { get; set; } public bool IsPlaceHolder { get; set; } - + /// <summary> /// Gets or sets the tags. /// </summary> /// <value>The tags.</value> public List<string> Tags { get; set; } - + /// <summary> /// Gets or sets the video bit rate. /// </summary> @@ -167,22 +215,53 @@ namespace MediaBrowser.Controller.Entities { var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); - // Must have a parent to have additional parts + // 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 (IsMultiPart && LocationType == LocationType.FileSystem && Parent != null) + if (LocationType == LocationType.FileSystem && Parent != null) { - var additionalPartsChanged = await RefreshAdditionalParts(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + if (IsMultiPart) + { + var additionalPartsChanged = await RefreshAdditionalParts(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); - if (additionalPartsChanged) + if (additionalPartsChanged) + { + hasChanges = true; + } + } + else { - hasChanges = true; + RefreshLinkedAlternateVersions(); + + if (HasLocalAlternateVersions) + { + var additionalPartsChanged = await RefreshAlternateVersionsWithinSameDirectory(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + + if (additionalPartsChanged) + { + hasChanges = true; + } + } } } return hasChanges; } + private bool RefreshLinkedAlternateVersions() + { + foreach (var child in LinkedAlternateVersions) + { + // Reset the cached value + if (child.ItemId.HasValue && child.ItemId.Value == Guid.Empty) + { + child.ItemId = null; + } + } + + return false; + } + /// <summary> /// Refreshes the additional parts. /// </summary> @@ -223,7 +302,7 @@ namespace MediaBrowser.Controller.Entities { if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory) { - return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsVideoFile(i.FullName) && EntityResolutionHelper.IsMultiPartFile(i.Name); + return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && EntityResolutionHelper.IsMultiPartFolder(i.FullName) && EntityResolutionHelper.IsMultiPartFile(i.Name); } return false; @@ -258,6 +337,72 @@ namespace MediaBrowser.Controller.Entities }).OrderBy(i => i.Path).ToList(); } + private async Task<bool> RefreshAlternateVersionsWithinSameDirectory(MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) + { + var newItems = LoadAlternateVersionsWithinSameDirectory(fileSystemChildren, options.DirectoryService).ToList(); + + var newItemIds = newItems.Select(i => i.Id).ToList(); + + var itemsChanged = !AlternateVersionIds.SequenceEqual(newItemIds); + + var tasks = newItems.Select(i => i.RefreshMetadata(options, cancellationToken)); + + await Task.WhenAll(tasks).ConfigureAwait(false); + + AlternateVersionIds = newItemIds; + + return itemsChanged; + } + + /// <summary> + /// Loads the additional parts. + /// </summary> + /// <returns>IEnumerable{Video}.</returns> + private IEnumerable<Video> LoadAlternateVersionsWithinSameDirectory(IEnumerable<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService) + { + IEnumerable<FileSystemInfo> files; + + var path = Path; + var currentFilename = System.IO.Path.GetFileNameWithoutExtension(path) ?? string.Empty; + + // Only support this for video files. For folder rips, they'll have to use the linking feature + if (VideoType == VideoType.VideoFile || VideoType == VideoType.Iso) + { + files = fileSystemChildren.Where(i => + { + if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory) + { + return false; + } + + return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && + EntityResolutionHelper.IsVideoFile(i.FullName) && + i.Name.StartsWith(currentFilename, 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.ImageInfos = ImageInfos; + + 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) |
