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(); }
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); } }
/// <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); }
/// <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); }
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); }
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); }
/// <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); }
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; }
/// <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; }
/// <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); }
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); }
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); }
/// <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); }
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; }
/// <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; }
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); }
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; }
/// <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); } }
private Task ValidateChildrenWithCancellationSupport(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { return ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService); }
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); } } }
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); }
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(); }
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; }
/// <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); }
/// <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); }
/// <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"); }