Esempio n. 1
0
 protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger <MetadataService <TItemType, TIdType> > logger, IProviderManager providerManager, IFileSystem fileSystem, ILibraryManager libraryManager)
 {
     ServerConfigurationManager = serverConfigurationManager;
     Logger          = logger;
     ProviderManager = providerManager;
     FileSystem      = fileSystem;
     LibraryManager  = libraryManager;
     ImageProvider   = new ItemImageProvider(Logger, ProviderManager, FileSystem);
 }
Esempio n. 2
0
        protected virtual async Task <RefreshResult> RefreshWithProviders(MetadataResult <TItemType> metadata,
                                                                          TIdType id,
                                                                          MetadataRefreshOptions options,
                                                                          List <IMetadataProvider> providers,
                                                                          ItemImageProvider imageService,
                                                                          CancellationToken cancellationToken)
        {
            var refreshResult = new RefreshResult
            {
                UpdateType = ItemUpdateType.None,
                Providers  = providers.Select(i => i.GetType().FullName.GetMD5()).ToList()
            };

            var item = metadata.Item;

            var customProviders = providers.OfType <ICustomMetadataProvider <TItemType> >().ToList();
            var logName         = item.LocationType == LocationType.Remote ? item.Name ?? item.Path : item.Path ?? item.Name;

            foreach (var provider in customProviders.Where(i => i is IPreRefreshProvider))
            {
                await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false);
            }

            var temp = new MetadataResult <TItemType>
            {
                Item = CreateNew()
            };

            temp.Item.Path = item.Path;

            var userDataList = new List <UserItemData>();

            // If replacing all metadata, run internet providers first
            if (options.ReplaceAllMetadata)
            {
                var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken)
                                   .ConfigureAwait(false);

                refreshResult.UpdateType   = refreshResult.UpdateType | remoteResult.UpdateType;
                refreshResult.ErrorMessage = remoteResult.ErrorMessage;
                refreshResult.Failures    += remoteResult.Failures;
            }

            var hasLocalMetadata = false;

            foreach (var provider in providers.OfType <ILocalMetadataProvider <TItemType> >().ToList())
            {
                var providerName = provider.GetType().Name;
                Logger.Debug("Running {0} for {1}", providerName, logName);

                var itemInfo = new ItemInfo(item);

                try
                {
                    var localItem = await provider.GetMetadata(itemInfo, options.DirectoryService, cancellationToken).ConfigureAwait(false);

                    if (localItem.HasMetadata)
                    {
                        if (imageService.MergeImages(item, localItem.Images))
                        {
                            refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.ImageUpdate;
                        }

                        if (localItem.UserDataList != null)
                        {
                            userDataList.AddRange(localItem.UserDataList);
                        }

                        MergeData(localItem, temp, new List <MetadataFields>(), !options.ReplaceAllMetadata, true);
                        refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport;

                        // Only one local provider allowed per item
                        if (IsFullLocalMetadata(localItem.Item))
                        {
                            hasLocalMetadata = true;
                        }
                        break;
                    }

                    Logger.Debug("{0} returned no metadata for {1}", providerName, logName);
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    refreshResult.Failures++;

                    Logger.ErrorException("Error in {0}", ex, provider.Name);

                    // If a local provider fails, consider that a failure
                    refreshResult.ErrorMessage = ex.Message;
                }
            }

            // Local metadata is king - if any is found don't run remote providers
            if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh))
            {
                var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken)
                                   .ConfigureAwait(false);

                refreshResult.UpdateType   = refreshResult.UpdateType | remoteResult.UpdateType;
                refreshResult.ErrorMessage = remoteResult.ErrorMessage;
                refreshResult.Failures    += remoteResult.Failures;
            }

            if (providers.Any(i => !(i is ICustomMetadataProvider)))
            {
                if (refreshResult.UpdateType > ItemUpdateType.None)
                {
                    // If no local metadata, take data from item itself
                    if (!hasLocalMetadata)
                    {
                        // TODO: If the new metadata from above has some blank data, this can cause old data to get filled into those empty fields
                        MergeData(metadata, temp, new List <MetadataFields>(), false, true);
                    }

                    MergeData(temp, metadata, item.LockedFields, true, true);
                }
            }

            //var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0;

            foreach (var provider in customProviders.Where(i => !(i is IPreRefreshProvider)))
            {
                await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false);
            }

            await ImportUserData(item, userDataList, cancellationToken).ConfigureAwait(false);

            return(refreshResult);
        }
Esempio n. 3
0
        public async Task <ItemUpdateType> RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
        {
            var itemOfType = (TItemType)item;
            var config     = ProviderManager.GetMetadataOptions(item);

            var updateType = ItemUpdateType.None;

            var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager, FileSystem);
            var localImagesFailed = false;

            var allImageProviders = ((ProviderManager)ProviderManager).GetImageProviders(item, refreshOptions).ToList();

            // Start by validating images
            try
            {
                // Always validate images and check for new locally stored ones.
                if (itemImageProvider.ValidateImages(item, allImageProviders.OfType <ILocalImageProvider>(), refreshOptions.DirectoryService))
                {
                    updateType = updateType | ItemUpdateType.ImageUpdate;
                }
            }
            catch (Exception ex)
            {
                localImagesFailed = true;
                Logger.ErrorException("Error validating images for {0}", ex, item.Path ?? item.Name ?? "Unknown name");
            }

            var metadataResult = new MetadataResult <TItemType>
            {
                Item = itemOfType
            };

            bool hasRefreshedMetadata = true;
            bool hasRefreshedImages   = true;
            var  requiresRefresh      = false;

            // Next run metadata providers
            if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
            {
                // TODO: If this returns true, should we instead just change metadata refresh mode to Full?
                requiresRefresh = item.RequiresRefresh();

                var providers = GetProviders(item, refreshOptions, requiresRefresh)
                                .ToList();

                var dateLastRefresh = item.DateLastRefreshed;

                if (providers.Count > 0 || dateLastRefresh == default(DateTime))
                {
                    if (item.BeforeMetadataRefresh())
                    {
                        updateType = updateType | ItemUpdateType.MetadataImport;
                    }
                }

                if (providers.Count > 0)
                {
                    var id = itemOfType.GetLookupInfo();

                    if (refreshOptions.SearchResult != null)
                    {
                        ApplySearchResult(id, refreshOptions.SearchResult);
                    }

                    //await FindIdentities(id, cancellationToken).ConfigureAwait(false);
                    id.IsAutomated = refreshOptions.IsAutomated;

                    var result = await RefreshWithProviders(metadataResult, id, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false);

                    updateType = updateType | result.UpdateType;
                    if (result.Failures == 0)
                    {
                        hasRefreshedMetadata = true;
                    }
                    else
                    {
                        hasRefreshedMetadata = false;
                    }
                }
            }

            // Next run remote image providers, but only if local image providers didn't throw an exception
            if (!localImagesFailed && refreshOptions.ImageRefreshMode != ImageRefreshMode.ValidationOnly)
            {
                var providers = GetNonLocalImageProviders(item, allImageProviders, refreshOptions).ToList();

                if (providers.Count > 0)
                {
                    var result = await itemImageProvider.RefreshImages(itemOfType, providers, refreshOptions, config, cancellationToken).ConfigureAwait(false);

                    updateType = updateType | result.UpdateType;
                    if (result.Failures == 0)
                    {
                        hasRefreshedImages = true;
                    }
                    else
                    {
                        hasRefreshedImages = false;
                    }
                }
            }

            var isFirstRefresh = item.DateLastRefreshed == default(DateTime);

            var beforeSaveResult = await BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh, updateType).ConfigureAwait(false);

            updateType = updateType | beforeSaveResult;

            if (item.LocationType == LocationType.FileSystem)
            {
                var file = refreshOptions.DirectoryService.GetFile(item.Path);
                if (file != null)
                {
                    var fileLastWriteTime = file.LastWriteTimeUtc;
                    if (item.EnableForceSaveOnDateModifiedChange && fileLastWriteTime != item.DateModified)
                    {
                        Logger.Debug("Date modified for {0}. Old date {1} new date {2} Id {3}", item.Path, item.DateModified, fileLastWriteTime, item.Id);
                        requiresRefresh = true;
                    }

                    item.DateModified = fileLastWriteTime;
                }
            }

            // Save if changes were made, or it's never been saved before
            if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata || requiresRefresh)
            {
                // If any of these properties are set then make sure the updateType is not None, just to force everything to save
                if (refreshOptions.ForceSave || refreshOptions.ReplaceAllMetadata)
                {
                    updateType = updateType | ItemUpdateType.MetadataDownload;
                }

                if (hasRefreshedMetadata && hasRefreshedImages)
                {
                    item.DateLastRefreshed = DateTime.UtcNow;
                }
                else
                {
                    item.DateLastRefreshed = default(DateTime);
                }

                // Save to database
                await SaveItem(metadataResult, updateType, cancellationToken).ConfigureAwait(false);
            }

            await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false);

            return(updateType);
        }
Esempio n. 4
0
        public async Task RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
        {
            if (refreshOptions.DirectoryService == null)
            {
                refreshOptions.DirectoryService = new DirectoryService(Logger);
            }

            var itemOfType = (TItemType)item;
            var config     = ProviderManager.GetMetadataOptions(item);

            var updateType    = ItemUpdateType.None;
            var refreshResult = GetLastResult(item);

            refreshResult.LastErrorMessage = string.Empty;
            refreshResult.LastStatus       = ProviderRefreshStatus.Success;

            var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager, FileSystem);
            var localImagesFailed = false;

            var allImageProviders = ((ProviderManager)ProviderManager).GetImageProviders(item).ToList();

            // Start by validating images
            try
            {
                // Always validate images and check for new locally stored ones.
                if (itemImageProvider.ValidateImages(item, allImageProviders.OfType <ILocalImageProvider>(), refreshOptions.DirectoryService))
                {
                    updateType = updateType | ItemUpdateType.ImageUpdate;
                }
            }
            catch (Exception ex)
            {
                localImagesFailed = true;
                Logger.ErrorException("Error validating images for {0}", ex, item.Path ?? item.Name);
                refreshResult.AddStatus(ProviderRefreshStatus.Failure, ex.Message);
            }

            // Next run metadata providers
            if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
            {
                var providers = GetProviders(item, refreshResult.DateLastMetadataRefresh.HasValue, refreshOptions)
                                .ToList();

                if (providers.Count > 0 || !refreshResult.DateLastMetadataRefresh.HasValue)
                {
                    if (item.BeforeMetadataRefresh())
                    {
                        updateType = updateType | ItemUpdateType.MetadataImport;
                    }
                }

                if (providers.Count > 0)
                {
                    var result = await RefreshWithProviders(itemOfType, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false);

                    updateType = updateType | result.UpdateType;
                    refreshResult.AddStatus(result.Status, result.ErrorMessage);
                    refreshResult.SetDateLastMetadataRefresh(DateTime.UtcNow);
                    refreshResult.AddImageProvidersRefreshed(result.Providers);
                }
            }

            // Next run remote image providers, but only if local image providers didn't throw an exception
            if (!localImagesFailed && refreshOptions.ImageRefreshMode != ImageRefreshMode.ValidationOnly)
            {
                var providers = GetNonLocalImageProviders(item, allImageProviders, refreshResult.DateLastImagesRefresh, refreshOptions).ToList();

                if (providers.Count > 0)
                {
                    var result = await itemImageProvider.RefreshImages(itemOfType, providers, refreshOptions, config, cancellationToken).ConfigureAwait(false);

                    updateType = updateType | result.UpdateType;
                    refreshResult.AddStatus(result.Status, result.ErrorMessage);
                    refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow);
                    refreshResult.AddImageProvidersRefreshed(result.Providers);
                }
            }

            updateType = updateType | BeforeSave(itemOfType);

            var providersHadChanges = updateType > ItemUpdateType.None;

            // Save if changes were made, or it's never been saved before
            if (refreshOptions.ForceSave || providersHadChanges || item.DateLastSaved == default(DateTime))
            {
                // Save to database
                await SaveItem(itemOfType, updateType, cancellationToken);
            }

            if (providersHadChanges || refreshResult.IsDirty)
            {
                await SaveProviderResult(itemOfType, refreshResult).ConfigureAwait(false);
            }
        }
Esempio n. 5
0
        protected virtual async Task <RefreshResult> RefreshWithProviders(TItemType item, MetadataRefreshOptions options, List <IMetadataProvider> providers, ItemImageProvider imageService, CancellationToken cancellationToken)
        {
            var refreshResult = new RefreshResult
            {
                UpdateType = ItemUpdateType.None,
                Providers  = providers.Select(i => i.GetType().FullName.GetMD5()).ToList()
            };

            var customProviders = providers.OfType <ICustomMetadataProvider <TItemType> >().ToList();

            foreach (var provider in customProviders.Where(i => i is IPreRefreshProvider))
            {
                await RunCustomProvider(provider, item, options.DirectoryService, refreshResult, cancellationToken).ConfigureAwait(false);
            }

            var temp = CreateNew();

            temp.Path = item.Path;

            // If replacing all metadata, run internet providers first
            if (options.ReplaceAllMetadata)
            {
                await ExecuteRemoteProviders(item, temp, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), refreshResult, cancellationToken).ConfigureAwait(false);
            }

            var hasLocalMetadata = false;

            foreach (var provider in providers.OfType <ILocalMetadataProvider <TItemType> >())
            {
                var providerName = provider.GetType().Name;
                Logger.Debug("Running {0} for {1}", providerName, item.Path ?? item.Name);

                var itemInfo = new ItemInfo {
                    Path = item.Path, IsInMixedFolder = item.IsInMixedFolder
                };

                try
                {
                    var localItem = await provider.GetMetadata(itemInfo, cancellationToken).ConfigureAwait(false);

                    if (localItem.HasMetadata)
                    {
                        if (imageService.MergeImages(item, localItem.Images))
                        {
                            refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.ImageUpdate;
                        }

                        if (string.IsNullOrWhiteSpace(localItem.Item.Name))
                        {
                            localItem.Item.Name = item.Name ?? Path.GetFileNameWithoutExtension(item.Path);
                        }

                        MergeData(localItem.Item, temp, new List <MetadataFields>(), !options.ReplaceAllMetadata, true);
                        refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport;

                        // Only one local provider allowed per item
                        hasLocalMetadata    = true;
                        item.IsUnidentified = false;
                        break;
                    }

                    Logger.Debug("{0} returned no metadata for {1}", providerName, item.Path ?? item.Name);
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    // If a local provider fails, consider that a failure
                    refreshResult.Status       = ProviderRefreshStatus.Failure;
                    refreshResult.ErrorMessage = ex.Message;
                    Logger.ErrorException("Error in {0}", ex, provider.Name);

                    // If the local provider fails don't continue with remote providers because the user's saved metadata could be lost
                    return(refreshResult);
                }
            }

            // Local metadata is king - if any is found don't run remote providers
            if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh))
            {
                await ExecuteRemoteProviders(item, temp, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), refreshResult, cancellationToken).ConfigureAwait(false);
            }

            if (refreshResult.UpdateType > ItemUpdateType.None)
            {
                MergeData(temp, item, item.LockedFields, true, true);
            }

            foreach (var provider in customProviders.Where(i => !(i is IPreRefreshProvider)))
            {
                await RunCustomProvider(provider, item, options.DirectoryService, refreshResult, cancellationToken).ConfigureAwait(false);
            }

            return(refreshResult);
        }
Esempio n. 6
0
        public async Task <ItemUpdateType> RefreshMetadata(BaseItem item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
        {
            var itemOfType = (TItemType)item;

            var updateType      = ItemUpdateType.None;
            var requiresRefresh = false;

            var libraryOptions = LibraryManager.GetLibraryOptions(item);

            if (!requiresRefresh && libraryOptions.AutomaticRefreshIntervalDays > 0 && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= libraryOptions.AutomaticRefreshIntervalDays)
            {
                requiresRefresh = true;
            }

            if (!requiresRefresh && refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
            {
                // TODO: If this returns true, should we instead just change metadata refresh mode to Full?
                requiresRefresh = item.RequiresRefresh();

                if (requiresRefresh)
                {
                    Logger.LogDebug("Refreshing {0} {1} because item.RequiresRefresh() returned true", typeof(TItemType).Name, item.Path ?? item.Name);
                }
            }

            var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, FileSystem);
            var localImagesFailed = false;

            var allImageProviders = ((ProviderManager)ProviderManager).GetImageProviders(item, refreshOptions).ToList();

            // Start by validating images
            try
            {
                // Always validate images and check for new locally stored ones.
                if (itemImageProvider.ValidateImages(item, allImageProviders.OfType <ILocalImageProvider>(), refreshOptions.DirectoryService))
                {
                    updateType |= ItemUpdateType.ImageUpdate;
                }
            }
            catch (Exception ex)
            {
                localImagesFailed = true;
                Logger.LogError(ex, "Error validating images for {0}", item.Path ?? item.Name ?? "Unknown name");
            }

            var metadataResult = new MetadataResult <TItemType>
            {
                Item = itemOfType
            };

            bool hasRefreshedMetadata = true;
            bool hasRefreshedImages   = true;
            var  isFirstRefresh       = item.DateLastRefreshed == default;

            // Next run metadata providers
            if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
            {
                var providers = GetProviders(item, libraryOptions, refreshOptions, isFirstRefresh, requiresRefresh)
                                .ToList();

                if (providers.Count > 0 || isFirstRefresh || requiresRefresh)
                {
                    if (item.BeforeMetadataRefresh(refreshOptions.ReplaceAllMetadata))
                    {
                        updateType |= ItemUpdateType.MetadataImport;
                    }
                }

                if (providers.Count > 0)
                {
                    var id = itemOfType.GetLookupInfo();

                    if (refreshOptions.SearchResult != null)
                    {
                        ApplySearchResult(id, refreshOptions.SearchResult);
                    }

                    // await FindIdentities(id, cancellationToken).ConfigureAwait(false);
                    id.IsAutomated = refreshOptions.IsAutomated;

                    var result = await RefreshWithProviders(metadataResult, id, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false);

                    updateType |= result.UpdateType;
                    if (result.Failures > 0)
                    {
                        hasRefreshedMetadata = false;
                    }
                }
            }

            // Next run remote image providers, but only if local image providers didn't throw an exception
            if (!localImagesFailed && refreshOptions.ImageRefreshMode != MetadataRefreshMode.ValidationOnly)
            {
                var providers = GetNonLocalImageProviders(item, allImageProviders, refreshOptions).ToList();

                if (providers.Count > 0)
                {
                    var result = await itemImageProvider.RefreshImages(itemOfType, libraryOptions, providers, refreshOptions, cancellationToken).ConfigureAwait(false);

                    updateType |= result.UpdateType;
                    if (result.Failures > 0)
                    {
                        hasRefreshedImages = false;
                    }
                }
            }

            var beforeSaveResult = BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh || refreshOptions.ForceSave, updateType);

            updateType |= beforeSaveResult;

            // Save if changes were made, or it's never been saved before
            if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata || requiresRefresh)
            {
                if (item.IsFileProtocol)
                {
                    var file = TryGetFile(item.Path, refreshOptions.DirectoryService);
                    if (file != null)
                    {
                        item.DateModified = file.LastWriteTimeUtc;
                    }
                }

                // If any of these properties are set then make sure the updateType is not None, just to force everything to save
                if (refreshOptions.ForceSave || refreshOptions.ReplaceAllMetadata)
                {
                    updateType |= ItemUpdateType.MetadataDownload;
                }

                if (hasRefreshedMetadata && hasRefreshedImages)
                {
                    item.DateLastRefreshed = DateTime.UtcNow;
                }
                else
                {
                    item.DateLastRefreshed = default;
                }

                // Save to database
                await SaveItemAsync(metadataResult, libraryOptions, updateType, cancellationToken).ConfigureAwait(false);
            }

            await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false);

            return(updateType);
        }
Esempio n. 7
0
        public async Task <ItemUpdateType> RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
        {
            var itemOfType = (TItemType)item;
            var config     = ProviderManager.GetMetadataOptions(item);

            var updateType    = ItemUpdateType.None;
            var refreshResult = GetLastResult(item);

            refreshResult.LastErrorMessage = string.Empty;
            refreshResult.LastStatus       = ProviderRefreshStatus.Success;

            var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager, FileSystem);
            var localImagesFailed = false;

            var allImageProviders = ((ProviderManager)ProviderManager).GetImageProviders(item).ToList();

            // Start by validating images
            try
            {
                // Always validate images and check for new locally stored ones.
                if (itemImageProvider.ValidateImages(item, allImageProviders.OfType <ILocalImageProvider>(), refreshOptions.DirectoryService))
                {
                    updateType = updateType | ItemUpdateType.ImageUpdate;
                }
            }
            catch (Exception ex)
            {
                localImagesFailed = true;
                Logger.ErrorException("Error validating images for {0}", ex, item.Path ?? item.Name ?? "Unknown name");
                refreshResult.AddStatus(ProviderRefreshStatus.Failure, ex.Message);
            }

            // Next run metadata providers
            if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
            {
                var providers = GetProviders(item, refreshResult, refreshOptions)
                                .ToList();

                if (providers.Count > 0 || !refreshResult.DateLastMetadataRefresh.HasValue)
                {
                    if (item.BeforeMetadataRefresh())
                    {
                        updateType = updateType | ItemUpdateType.MetadataImport;
                    }
                }

                if (providers.Count > 0)
                {
                    var id = await CreateInitialLookupInfo(itemOfType, cancellationToken).ConfigureAwait(false);

                    var result = await RefreshWithProviders(itemOfType, id, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false);

                    updateType = updateType | result.UpdateType;
                    refreshResult.AddStatus(result.Status, result.ErrorMessage);
                    refreshResult.SetDateLastMetadataRefresh(DateTime.UtcNow);
                    refreshResult.AddMetadataProvidersRefreshed(result.Providers);

                    MergeIdentities(itemOfType, id);
                }
            }

            // Next run remote image providers, but only if local image providers didn't throw an exception
            if (!localImagesFailed && refreshOptions.ImageRefreshMode != ImageRefreshMode.ValidationOnly)
            {
                var providers = GetNonLocalImageProviders(item, allImageProviders, refreshResult, refreshOptions).ToList();

                if (providers.Count > 0)
                {
                    var result = await itemImageProvider.RefreshImages(itemOfType, providers, refreshOptions, config, cancellationToken).ConfigureAwait(false);

                    updateType = updateType | result.UpdateType;
                    refreshResult.AddStatus(result.Status, result.ErrorMessage);
                    refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow);
                    refreshResult.AddImageProvidersRefreshed(result.Providers);
                }
            }

            var beforeSaveResult = await BeforeSave(itemOfType, item.DateLastSaved == default(DateTime) || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh, updateType).ConfigureAwait(false);

            updateType = updateType | beforeSaveResult;

            // Save if changes were made, or it's never been saved before
            if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || item.DateLastSaved == default(DateTime) || refreshOptions.ReplaceAllMetadata)
            {
                // If any of these properties are set then make sure the updateType is not None, just to force everything to save
                if (refreshOptions.ForceSave || refreshOptions.ReplaceAllMetadata)
                {
                    updateType = updateType | ItemUpdateType.MetadataDownload;
                }

                // Save to database
                await SaveItem(itemOfType, updateType, cancellationToken);
            }

            if (updateType > ItemUpdateType.None || refreshResult.IsDirty)
            {
                await SaveProviderResult(itemOfType, refreshResult, refreshOptions.DirectoryService).ConfigureAwait(false);
            }

            await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false);

            return(updateType);
        }
Esempio n. 8
0
        protected virtual async Task <RefreshResult> RefreshWithProviders(TItemType item,
                                                                          TIdType id,
                                                                          MetadataRefreshOptions options,
                                                                          List <IMetadataProvider> providers,
                                                                          ItemImageProvider imageService,
                                                                          CancellationToken cancellationToken)
        {
            var refreshResult = new RefreshResult
            {
                UpdateType = ItemUpdateType.None,
                Providers  = providers.Select(i => i.GetType().FullName.GetMD5()).ToList()
            };

            var customProviders = providers.OfType <ICustomMetadataProvider <TItemType> >().ToList();
            var logName         = item.LocationType == LocationType.Remote ? item.Name ?? item.Path : item.Path ?? item.Name;

            foreach (var provider in customProviders.Where(i => i is IPreRefreshProvider))
            {
                await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false);
            }

            var temp = CreateNew();

            temp.Path = item.Path;
            var successfulProviderCount = 0;
            var failedProviderCount     = 0;

            // If replacing all metadata, run internet providers first
            if (options.ReplaceAllMetadata)
            {
                var remoteResult = await ExecuteRemoteProviders(item, temp, logName, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken)
                                   .ConfigureAwait(false);

                refreshResult.UpdateType   = refreshResult.UpdateType | remoteResult.UpdateType;
                refreshResult.Status       = remoteResult.Status;
                refreshResult.ErrorMessage = remoteResult.ErrorMessage;
                successfulProviderCount   += remoteResult.Successes;
                failedProviderCount       += remoteResult.Failures;
            }

            var hasLocalMetadata = false;
            var userDataList     = new List <UserItemData>();
            var localProviders   = providers.OfType <ILocalMetadataProvider <TItemType> >().ToList();

            foreach (var provider in localProviders)
            {
                var providerName = provider.GetType().Name;
                Logger.Debug("Running {0} for {1}", providerName, logName);

                var itemInfo = new ItemInfo {
                    Path = item.Path, IsInMixedFolder = item.IsInMixedFolder
                };

                try
                {
                    var localItem = await provider.GetMetadata(itemInfo, options.DirectoryService, cancellationToken).ConfigureAwait(false);

                    if (localItem.HasMetadata)
                    {
                        if (imageService.MergeImages(item, localItem.Images))
                        {
                            refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.ImageUpdate;
                        }

                        userDataList = localItem.UserDataLIst;

                        MergeData(localItem.Item, temp, new List <MetadataFields>(), !options.ReplaceAllMetadata, true);
                        refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport;

                        // Only one local provider allowed per item
                        hasLocalMetadata = true;
                        successfulProviderCount++;
                        break;
                    }

                    Logger.Debug("{0} returned no metadata for {1}", providerName, logName);
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    failedProviderCount++;

                    Logger.ErrorException("Error in {0}", ex, provider.Name);

                    // If a local provider fails, consider that a failure
                    refreshResult.Status       = ProviderRefreshStatus.Failure;
                    refreshResult.ErrorMessage = ex.Message;

                    if (options.MetadataRefreshMode != MetadataRefreshMode.FullRefresh)
                    {
                        // If the local provider fails don't continue with remote providers because the user's saved metadata could be lost
                        return(refreshResult);
                    }
                }
            }

            // Local metadata is king - if any is found don't run remote providers
            if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh))
            {
                var remoteResult = await ExecuteRemoteProviders(item, temp, logName, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken)
                                   .ConfigureAwait(false);

                refreshResult.UpdateType = refreshResult.UpdateType | remoteResult.UpdateType;
                if (remoteResult.Status != ProviderRefreshStatus.Success)
                {
                    refreshResult.Status       = remoteResult.Status;
                    refreshResult.ErrorMessage = remoteResult.ErrorMessage;
                }
                successfulProviderCount += remoteResult.Successes;
            }

            // If no local providers and doing a full refresh, take data from item itself
            if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh &&
                localProviders.Count == 0 &&
                refreshResult.UpdateType > ItemUpdateType.None)
            {
                // TODO: If the new metadata from above has some blank data, this
                // can cause old data to get filled into those empty fields
                MergeData(item, temp, new List <MetadataFields>(), false, true);
            }

            if (refreshResult.UpdateType > ItemUpdateType.None)
            {
                MergeData(temp, item, item.LockedFields, true, true);
            }

            var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0;

            if (item.IsUnidentified != isUnidentified)
            {
                item.IsUnidentified      = isUnidentified;
                refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport;
            }

            foreach (var provider in customProviders.Where(i => !(i is IPreRefreshProvider)))
            {
                await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false);
            }

            await ImportUserData(item, userDataList, cancellationToken).ConfigureAwait(false);

            return(refreshResult);
        }
Esempio n. 9
0
        protected virtual async Task <RefreshResult> RefreshWithProviders(
            MetadataResult <TItemType> metadata,
            TIdType id,
            MetadataRefreshOptions options,
            ICollection <IMetadataProvider> providers,
            ItemImageProvider imageService,
            CancellationToken cancellationToken)
        {
            var refreshResult = new RefreshResult
            {
                UpdateType = ItemUpdateType.None
            };

            var item = metadata.Item;

            var customProviders = providers.OfType <ICustomMetadataProvider <TItemType> >().ToList();
            var logName         = !item.IsFileProtocol ? item.Name ?? item.Path : item.Path ?? item.Name;

            foreach (var provider in customProviders.Where(i => i is IPreRefreshProvider))
            {
                await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false);
            }

            var temp = new MetadataResult <TItemType>
            {
                Item = CreateNew()
            };

            temp.Item.Path = item.Path;

            var userDataList = new List <UserItemData>();

            // If replacing all metadata, run internet providers first
            if (options.ReplaceAllMetadata)
            {
                var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken)
                                   .ConfigureAwait(false);

                refreshResult.UpdateType  |= remoteResult.UpdateType;
                refreshResult.ErrorMessage = remoteResult.ErrorMessage;
                refreshResult.Failures    += remoteResult.Failures;
            }

            var hasLocalMetadata = false;

            foreach (var provider in providers.OfType <ILocalMetadataProvider <TItemType> >().ToList())
            {
                var providerName = provider.GetType().Name;
                Logger.LogDebug("Running {Provider} for {Item}", providerName, logName);

                var itemInfo = new ItemInfo(item);

                try
                {
                    var localItem = await provider.GetMetadata(itemInfo, options.DirectoryService, cancellationToken).ConfigureAwait(false);

                    if (localItem.HasMetadata)
                    {
                        foreach (var remoteImage in localItem.RemoteImages)
                        {
                            try
                            {
                                await ProviderManager.SaveImage(item, remoteImage.Url, remoteImage.Type, null, cancellationToken).ConfigureAwait(false);

                                refreshResult.UpdateType |= ItemUpdateType.ImageUpdate;
                            }
                            catch (HttpRequestException ex)
                            {
                                Logger.LogError(ex, "Could not save {ImageType} image: {Url}", Enum.GetName(remoteImage.Type), remoteImage.Url);
                            }
                        }

                        if (imageService.MergeImages(item, localItem.Images))
                        {
                            refreshResult.UpdateType |= ItemUpdateType.ImageUpdate;
                        }

                        if (localItem.UserDataList != null)
                        {
                            userDataList.AddRange(localItem.UserDataList);
                        }

                        MergeData(localItem, temp, Array.Empty <MetadataField>(), !options.ReplaceAllMetadata, true);
                        refreshResult.UpdateType |= ItemUpdateType.MetadataImport;

                        // Only one local provider allowed per item
                        if (item.IsLocked || localItem.Item.IsLocked || IsFullLocalMetadata(localItem.Item))
                        {
                            hasLocalMetadata = true;
                        }

                        break;
                    }

                    Logger.LogDebug("{Provider} returned no metadata for {Item}", providerName, logName);
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex, "Error in {Provider}", provider.Name);

                    // If a local provider fails, consider that a failure
                    refreshResult.ErrorMessage = ex.Message;
                }
            }

            // Local metadata is king - if any is found don't run remote providers
            if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || !item.StopRefreshIfLocalMetadataFound))
            {
                var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken)
                                   .ConfigureAwait(false);

                refreshResult.UpdateType  |= remoteResult.UpdateType;
                refreshResult.ErrorMessage = remoteResult.ErrorMessage;
                refreshResult.Failures    += remoteResult.Failures;
            }

            if (providers.Any(i => i is not ICustomMetadataProvider))
            {
                if (refreshResult.UpdateType > ItemUpdateType.None)
                {
                    if (hasLocalMetadata)
                    {
                        MergeData(temp, metadata, item.LockedFields, true, true);
                    }
                    else
                    {
                        if (!options.RemoveOldMetadata)
                        {
                            MergeData(metadata, temp, Array.Empty <MetadataField>(), false, false);
                        }

                        MergeData(temp, metadata, item.LockedFields, true, false);
                    }
                }
            }

            // var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0;

            foreach (var provider in customProviders.Where(i => i is not IPreRefreshProvider))
            {
                await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false);
            }

            // ImportUserData(item, userDataList, cancellationToken);

            return(refreshResult);
        }