示例#1
0
        public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
        {
            var items = GetRecursiveChildren().ToList();

            var totalItems = items.Count;
            var numComplete = 0;

            // Refresh songs
            foreach (var item in items)
            {
                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);

            progress.Report(100);
        }
        public MetadataRefreshOptions(MetadataRefreshOptions copy)
            : base(copy.DirectoryService)
        {
            MetadataRefreshMode = copy.MetadataRefreshMode;
            ForceSave = copy.ForceSave;
            ReplaceAllMetadata = copy.ReplaceAllMetadata;

            ImageRefreshMode = copy.ImageRefreshMode;
            ReplaceAllImages = copy.ReplaceAllImages;
            ReplaceImages = copy.ReplaceImages.ToList();
        }
示例#3
0
        protected override async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
        {
            await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService)
                .ConfigureAwait(false);

            // Not the best way to handle this, but it solves an issue
            // CollectionFolders aren't always getting saved after changes
            // This means that grabbing the item by Id may end up returning the old one
            // Fix is in two places - make sure the folder gets saved
            // And here to remedy it for affected users.
            // In theory this can be removed eventually.
            foreach (var item in Children)
            {
                LibraryManager.RegisterItem(item);
            }
        }
示例#4
0
        /// <summary>
        /// Validates the people.
        /// </summary>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="options">The options.</param>
        /// <param name="progress">The progress.</param>
        /// <returns>Task.</returns>
        public async Task ValidatePeople(CancellationToken cancellationToken, MetadataRefreshOptions options, IProgress<double> progress)
        {
            var innerProgress = new ActionableProgress<double>();

            innerProgress.RegisterAction(pct => progress.Report(pct * .15));

            var people = _libraryManager.RootFolder.GetRecursiveChildren()
                .SelectMany(c => c.People)
                .Where(i => !string.IsNullOrWhiteSpace(i.Name))
                .Select(i => i.Name)
                .Distinct(StringComparer.OrdinalIgnoreCase)
                .ToList();

            var numComplete = 0;

            foreach (var person in people)
            {
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    var item = _libraryManager.GetPerson(person);

                    await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error validating IBN entry {0}", ex, person);
                }

                // Update progress
                numComplete++;
                double percent = numComplete;
                percent /= people.Count;

                progress.Report(15 + 85 * percent);
            }

            progress.Report(100);

            _logger.Info("People validation complete");

            // Bad practice, i know. But we keep a lot in memory, unfortunately.
            GC.Collect(2, GCCollectionMode.Forced, true);
            GC.Collect(2, GCCollectionMode.Forced, true);
        }
示例#5
0
        /// <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***
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
        /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param>
        /// <param name="refreshOptions">The refresh options.</param>
        /// <param name="directoryService">The directory service.</param>
        /// <returns>Task.</returns>
        protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
        {
            var list = PhysicalLocationsList.ToList();

            CreateResolveArgs(directoryService);

            if (!list.SequenceEqual(PhysicalLocationsList))
            {
                return UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken);
            }

            return Task.FromResult(true);
        }
示例#6
0
        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
            {
                DirectoryService = 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);
        }
示例#7
0
 protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
 {
     _hasChildren = null;
     return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService);
 }
示例#8
0
        /// <summary>
        /// Validates the people.
        /// </summary>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="progress">The progress.</param>
        /// <returns>Task.</returns>
        public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
        {
            var innerProgress = new ActionableProgress<double>();

            innerProgress.RegisterAction(pct => progress.Report(pct * .15));

            var peopleOptions = _config.Configuration.PeopleMetadataOptions;

            var people = _libraryManager.GetAllPeople();

            var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);

            foreach (var person in people)
            {
                var isMetadataEnabled = DownloadMetadata(person, peopleOptions);

                bool currentValue;
                if (dict.TryGetValue(person.Name, out currentValue))
                {
                    if (!currentValue && isMetadataEnabled)
                    {
                        dict[person.Name] = true;
                    }
                }
                else
                {
                    dict[person.Name] = isMetadataEnabled;
                }
            }

            var numComplete = 0;
            var validIds = new List<Guid>();
            
            foreach (var person in dict)
            {
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    var item = _libraryManager.GetPerson(person.Key);

                    validIds.Add(item.Id);

                    var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview);
                    var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 30;

                    var defaultMetadataRefreshMode = performFullRefresh
                        ? MetadataRefreshMode.FullRefresh
                        : MetadataRefreshMode.Default;

                    var imageRefreshMode = performFullRefresh
                        ? ImageRefreshMode.FullRefresh
                        : ImageRefreshMode.Default;

                    var options = new MetadataRefreshOptions(_fileSystem)
                    {
                        MetadataRefreshMode = person.Value ? defaultMetadataRefreshMode : MetadataRefreshMode.ValidationOnly,
                        ImageRefreshMode = person.Value ? imageRefreshMode : ImageRefreshMode.ValidationOnly
                    };

                    await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error validating IBN entry {0}", ex, person);
                }

                // Update progress
                numComplete++;
                double percent = numComplete;
                percent /= people.Count;

                progress.Report(100 * percent);
            }

            var allIds = _libraryManager.GetItemIds(new InternalItemsQuery
            {
                IncludeItemTypes = new[] { typeof(Person).Name }
            });

            var invalidIds = allIds
                .Except(validIds)
                .ToList();

            foreach (var id in invalidIds)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var item = _libraryManager.GetItemById(id);

                if (item != null)
                {
                    await _libraryManager.DeleteItem(item, new DeleteOptions
                    {
                        DeleteFileLocation = false

                    }).ConfigureAwait(false);
                }
            }

            progress.Report(100);

            _logger.Info("People validation complete");

            // Bad practice, i know. But we keep a lot in memory, unfortunately.
            GC.Collect(2, GCCollectionMode.Forced, true);
            GC.Collect(2, GCCollectionMode.Forced, true);
        }
示例#9
0
        public async Task<FileOrganizationResult> OrganizeWithCorrection(EpisodeFileOrganizationRequest request, AutoOrganizeOptions options, CancellationToken cancellationToken)
        {
            var result = _organizationService.GetResult(request.ResultId);

            Series series = null;

            if (request.NewSeriesProviderIds.Count > 0)
            {
                // We're having a new series here
                SeriesInfo seriesRequest = new SeriesInfo();
                seriesRequest.ProviderIds = request.NewSeriesProviderIds;

                var refreshOptions = new MetadataRefreshOptions(_fileSystem);
                series = new Series();
                series.Id = Guid.NewGuid();
                series.Name = request.NewSeriesName;

                int year;
                if (int.TryParse(request.NewSeriesYear, out year))
                {
                    series.ProductionYear = year;
                }

                var seriesFolderName = series.Name;
                if (series.ProductionYear.HasValue)
                {
                    seriesFolderName = string.Format("{0} ({1})", seriesFolderName, series.ProductionYear);
                }

                series.Path = Path.Combine(request.TargetFolder, seriesFolderName);

                series.ProviderIds = request.NewSeriesProviderIds;

                await series.RefreshMetadata(refreshOptions, cancellationToken);
            }

            if (series == null)
            {
                // Existing Series
                series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId));
            }

            await OrganizeEpisode(result.OriginalPath,
                series,
                request.SeasonNumber,
                request.EpisodeNumber,
                request.EndingEpisodeNumber,
                null,
                options,
                true,
                request.RememberCorrection,
                result,
                cancellationToken).ConfigureAwait(false);

            await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false);

            return result;
        }
示例#10
0
        /// <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***
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
        /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param>
        /// <param name="refreshOptions">The refresh options.</param>
        /// <param name="directoryService">The directory service.</param>
        /// <returns>Task.</returns>
        protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
        {
            CreateResolveArgs(directoryService);
            ResetDynamicChildren();

            return NullTaskResult;
        }
示例#11
0
        /// <summary>
        /// Validates the children internal.
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
        /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param>
        /// <param name="refreshOptions">The refresh options.</param>
        /// <param name="directoryService">The directory service.</param>
        /// <returns>Task.</returns>
        protected async virtual Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
        {
            var locationType = LocationType;

            cancellationToken.ThrowIfCancellationRequested();

            var validChildren = new List<BaseItem>();

            if (locationType != LocationType.Remote && locationType != LocationType.Virtual)
            {
                IEnumerable<BaseItem> nonCachedChildren;

                try
                {
                    nonCachedChildren = GetNonCachedChildren(directoryService);
                }
                catch (IOException ex)
                {
                    nonCachedChildren = new BaseItem[] { };

                    Logger.ErrorException("Error getting file system entries for {0}", ex, Path);
                }

                if (nonCachedChildren == null) return; //nothing to validate

                progress.Report(5);

                //build a dictionary of the current children we have now by Id so we can compare quickly and easily
                var currentChildren = GetActualChildrenDictionary();

                //create a list for our validated children
                var newItems = new List<BaseItem>();

                cancellationToken.ThrowIfCancellationRequested();

                foreach (var child in nonCachedChildren)
                {
                    BaseItem currentChild;

                    if (currentChildren.TryGetValue(child.Id, out currentChild))
                    {
                        if (IsValidFromResolver(currentChild, child))
                        {
                            var currentChildLocationType = currentChild.LocationType;
                            if (currentChildLocationType != LocationType.Remote &&
                                currentChildLocationType != LocationType.Virtual)
                            {
                                currentChild.DateModified = child.DateModified;
                            }

                            currentChild.IsOffline = false;
                            validChildren.Add(currentChild);
                        }
                        else
                        {
                            newItems.Add(child);
                            validChildren.Add(child);
                        }
                    }
                    else
                    {
                        // Brand new item - needs to be added
                        newItems.Add(child);
                        validChildren.Add(child);
                    }
                }

                // If any items were added or removed....
                if (newItems.Count > 0 || currentChildren.Count != validChildren.Count)
                {
                    // That's all the new and changed ones - now see if there are any that are missing
                    var itemsRemoved = currentChildren.Values.Except(validChildren).ToList();
                    var actualRemovals = new List<BaseItem>();

                    foreach (var item in itemsRemoved)
                    {
                        if (item.LocationType == LocationType.Virtual ||
                            item.LocationType == LocationType.Remote)
                        {
                            // Don't remove these because there's no way to accurately validate them.
                            validChildren.Add(item);
                        }

                        else if (!string.IsNullOrEmpty(item.Path) && IsPathOffline(item.Path))
                        {
                            item.IsOffline = true;
                            validChildren.Add(item);
                        }
                        else
                        {
                            item.IsOffline = false;
                            actualRemovals.Add(item);
                        }
                    }

                    if (actualRemovals.Count > 0)
                    {
                        RemoveChildrenInternal(actualRemovals);

                        foreach (var item in actualRemovals)
                        {
                            LibraryManager.ReportItemRemoved(item);
                        }
                    }

                    await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);

                    AddChildrenInternal(newItems);

                    await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
                }
            }

            progress.Report(10);

            cancellationToken.ThrowIfCancellationRequested();

            if (recursive)
            {
                await ValidateSubFolders(ActualChildren.OfType<Folder>().ToList(), directoryService, progress, cancellationToken).ConfigureAwait(false);
            }

            progress.Report(20);

            if (refreshChildMetadata)
            {
                var container = this as IMetadataContainer;

                var innerProgress = new ActionableProgress<double>();

                innerProgress.RegisterAction(p => progress.Report((.80 * p) + 20));

                if (container != null)
                {
                    await container.RefreshAllMetadata(refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    await RefreshMetadataRecursive(refreshOptions, recursive, innerProgress, cancellationToken);
                }
            }

            progress.Report(100);
        }
示例#12
0
        private async Task RefreshChildMetadata(BaseItem child, MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
        {
            var container = child as IMetadataContainer;

            if (container != null)
            {
                await container.RefreshAllMetadata(refreshOptions, progress, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                await child.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);

                if (recursive)
                {
                    var folder = child as Folder;

                    if (folder != null)
                    {
                        await folder.RefreshMetadataRecursive(refreshOptions, true, progress, cancellationToken);
                    }
                }
            }
            progress.Report(100);
        }
示例#13
0
文件: Folder.cs 项目: paul-777/Emby
        private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
        {
            var children = ActualChildren.ToList();

            var percentages = new Dictionary<Guid, double>(children.Count);
            var numComplete = 0;
            var count = children.Count;

            foreach (var child in children)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (child.IsFolder)
                {
                    var innerProgress = new ActionableProgress<double>();

                    // Avoid implicitly captured closure
                    var currentChild = child;
                    innerProgress.RegisterAction(p =>
                    {
                        lock (percentages)
                        {
                            percentages[currentChild.Id] = p / 100;

                            var innerPercent = percentages.Values.Sum();
                            innerPercent /= count;
                            innerPercent *= 100;
                            progress.Report(innerPercent);
                        }
                    });

                    await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken)
                      .ConfigureAwait(false);
                }
                else
                {
                    await RefreshChildMetadata(child, refreshOptions, false, new Progress<double>(), cancellationToken)
                      .ConfigureAwait(false);
                }

                numComplete++;
                double percent = numComplete;
                percent /= count;
                percent *= 100;

                progress.Report(percent);
            }

            progress.Report(100);
        }
示例#14
0
 /// <summary>
 /// Validates that the children of the folder still exist
 /// </summary>
 /// <param name="progress">The progress.</param>
 /// <param name="cancellationToken">The cancellation token.</param>
 /// <param name="metadataRefreshOptions">The metadata refresh options.</param>
 /// <param name="recursive">if set to <c>true</c> [recursive].</param>
 /// <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);
 }
示例#15
0
        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;
        }
示例#16
0
        /// <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;
        }
示例#17
0
        protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
        {
            var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).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
                {
                    RefreshLinkedAlternateVersions();

                    var additionalPartsChanged = await RefreshAlternateVersionsWithinSameDirectory(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);

                    if (additionalPartsChanged)
                    {
                        hasChanges = true;
                    }
                }
            }

            return hasChanges;
        }
 public Task<ItemUpdateType> FetchAsync(Movie item, MetadataRefreshOptions options, CancellationToken cancellationToken)
 {
     return FetchAsync(item, cancellationToken);
 }
        public Task<ItemUpdateType> FetchAsync(Trailer item, MetadataRefreshOptions options, CancellationToken cancellationToken)
        {
            if (item.IsLocalTrailer)
            {
                return Task.FromResult(ItemUpdateType.None);
            }

            return FetchAsync(item, cancellationToken);
        }
示例#20
0
        protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
        {
            var changesFound = false;

            if (SupportsShortcutChildren && LocationType == LocationType.FileSystem)
            {
                if (RefreshLinkedChildren(fileSystemChildren))
                {
                    changesFound = true;
                }
            }

            var baseHasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);

            return baseHasChanges || changesFound;
        }
示例#21
0
        /// <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***
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
        /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param>
        /// <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)
        {
            var list = PhysicalLocationsList.ToList();

            CreateResolveArgs(directoryService);

            if (!list.SequenceEqual(PhysicalLocationsList))
            {
                await UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
            }
        }
示例#22
0
 private Task ValidateChildrenWithCancellationSupport(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
 {
     return ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService);
 }
示例#23
0
        private async Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
        {
            var collection = _libraryManager.GetItemById(collectionId) as BoxSet;

            if (collection == null)
            {
                throw new ArgumentException("No collection exists with the supplied Id");
            }

            var list = new List<LinkedChild>();
            var itemList = new List<BaseItem>();
            var currentLinkedChildren = collection.GetLinkedChildren().ToList();

            foreach (var itemId in ids)
            {
                var item = _libraryManager.GetItemById(itemId);

                if (item == null)
                {
                    throw new ArgumentException("No item exists with the supplied Id");
                }

                itemList.Add(item);

                if (currentLinkedChildren.All(i => i.Id != itemId))
                {
                    list.Add(LinkedChild.Create(item));
                }
            }

            if (list.Count > 0)
            {
                collection.LinkedChildren.AddRange(list);

                collection.UpdateRatingToContent();

                await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);

                _providerManager.QueueRefresh(collection.Id, refreshOptions);

                if (fireEvent)
                {
                    EventHelper.FireEventIfNotNull(ItemsAddedToCollection, this, new CollectionModifiedEventArgs
                    {
                        Collection = collection,
                        ItemsChanged = itemList

                    }, _logger);
                }
            }
        }
示例#24
0
        private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
        {
            var children = ActualChildren.ToList();

            var percentages = new Dictionary<Guid, double>(children.Count);

            var tasks = new List<Task>();

            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 =>
                {
                    lock (percentages)
                    {
                        percentages[currentChild.Id] = p / 100;

                        var percent = percentages.Values.Sum();
                        percent /= children.Count;
                        percent *= 100;
                        progress.Report(percent);
                    }
                });

                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 Task.WhenAll(tasks).ConfigureAwait(false);
            progress.Report(100);
        }
示例#25
0
        protected override async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
        {
            ClearCache();

            await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService)
                .ConfigureAwait(false);

            ClearCache();
        }
示例#26
0
文件: Video.cs 项目: 7illusions/Emby
        protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
        {
            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 && GetParent() != null)
            {
                if (!IsStacked)
                {
                    RefreshLinkedAlternateVersions();

                    var tasks = LocalAlternateVersions
                        .Select(i => RefreshMetadataForOwnedVideo(options, i, cancellationToken));

                    await Task.WhenAll(tasks).ConfigureAwait(false);
                }
            }

            return hasChanges;
        }
示例#27
0
        /// <summary>
        /// Validates the people.
        /// </summary>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="progress">The progress.</param>
        /// <returns>Task.</returns>
        public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
        {
            var innerProgress = new ActionableProgress<double>();

            innerProgress.RegisterAction(pct => progress.Report(pct * .15));

            var peopleOptions = _config.Configuration.PeopleMetadataOptions;

            var people = _libraryManager.RootFolder.GetRecursiveChildren()
                .SelectMany(i => i.People)
                .Where(i => !string.IsNullOrWhiteSpace(i.Name))
                .ToList();

            var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);

            foreach (var person in people)
            {
                bool current;
                if (!dict.TryGetValue(person.Name, out current) || !current)
                {
                    dict[person.Name] = DownloadMetadata(person, peopleOptions);
                }
            }

            var numComplete = 0;

            foreach (var person in dict)
            {
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    var item = _libraryManager.GetPerson(person.Key);

                    var options = new MetadataRefreshOptions
                    {
                         MetadataRefreshMode = person.Value ? MetadataRefreshMode.Default : MetadataRefreshMode.ValidationOnly,
                         ImageRefreshMode = person.Value ? ImageRefreshMode.Default : ImageRefreshMode.ValidationOnly
                    };

                    await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error validating IBN entry {0}", ex, person);
                }

                // Update progress
                numComplete++;
                double percent = numComplete;
                percent /= people.Count;

                progress.Report(100 * percent);
            }

            progress.Report(100);

            _logger.Info("People validation complete");

            // Bad practice, i know. But we keep a lot in memory, unfortunately.
            GC.Collect(2, GCCollectionMode.Forced, true);
            GC.Collect(2, GCCollectionMode.Forced, true);
        }
示例#28
0
 /// <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***
 /// </summary>
 /// <param name="progress">The progress.</param>
 /// <param name="cancellationToken">The cancellation token.</param>
 /// <param name="recursive">if set to <c>true</c> [recursive].</param>
 /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param>
 /// <param name="refreshOptions">The refresh options.</param>
 /// <param name="directoryService">The directory service.</param>
 /// <returns>Task.</returns>
 protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
 {
     return Task.FromResult(true);
 }
示例#29
0
        /// <summary>
        /// Validates the people.
        /// </summary>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="progress">The progress.</param>
        /// <returns>Task.</returns>
        public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
        {
            var innerProgress = new ActionableProgress<double>();

            innerProgress.RegisterAction(pct => progress.Report(pct * .15));

            var peopleOptions = _config.Configuration.PeopleMetadataOptions;

            var people = _libraryManager.GetPeople(new InternalPeopleQuery());

            var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);

            foreach (var person in people)
            {
                var isMetadataEnabled = DownloadMetadata(person, peopleOptions);

                bool currentValue;
                if (dict.TryGetValue(person.Name, out currentValue))
                {
                    if (!currentValue && isMetadataEnabled)
                    {
                        dict[person.Name] = true;
                    }
                }
                else
                {
                    dict[person.Name] = isMetadataEnabled;
                }
            }

            var numComplete = 0;

            _logger.Debug("Will refresh {0} people", dict.Count);

            var numPeople = dict.Count;

            foreach (var person in dict)
            {
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    var item = _libraryManager.GetPerson(person.Key);

                    var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview);
                    var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 30;

                    var defaultMetadataRefreshMode = performFullRefresh
                        ? MetadataRefreshMode.FullRefresh
                        : MetadataRefreshMode.Default;

                    var imageRefreshMode = performFullRefresh
                        ? ImageRefreshMode.FullRefresh
                        : ImageRefreshMode.Default;

                    var options = new MetadataRefreshOptions(_fileSystem)
                    {
                        MetadataRefreshMode = person.Value ? defaultMetadataRefreshMode : MetadataRefreshMode.ValidationOnly,
                        ImageRefreshMode = person.Value ? imageRefreshMode : ImageRefreshMode.ValidationOnly,
                        ForceSave = performFullRefresh
                    };

                    await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error validating IBN entry {0}", ex, person);
                }

                // Update progress
                numComplete++;
                double percent = numComplete;
                percent /= numPeople;

                progress.Report(100 * percent);
            }

            progress.Report(100);

            _logger.Info("People validation complete");
        }