/// <summary>
        /// Imports the resource with the given <paramref name="mediaItemAccessor"/>.
        /// </summary>
        /// <remarks>
        /// This method will be called for file resources as well as for directory resources because some metadata extractors
        /// extract their metadata from directories.
        /// </remarks>
        /// <param name="mediaItemAccessor">File or directory resource to be imported.</param>
        /// <param name="parentDirectoryId">Media item id of the parent directory, if present, else <see cref="Guid.Empty"/>.</param>
        /// <param name="metadataExtractors">Collection of metadata extractors to apply to the given resoure.</param>
        /// <param name="resultHandler">Callback to notify the import results.</param>
        /// <param name="mediaAccessor">Convenience reference to the media accessor.</param>
        /// <returns><c>true</c>, if metadata could be extracted from the given <paramref name="mediaItemAccessor"/>, else
        /// <c>false</c>.</returns>
        protected bool ImportResource(ImportJob importJob, IResourceAccessor mediaItemAccessor, Guid parentDirectoryId, ICollection <IMetadataExtractor> metadataExtractors,
                                      IImportResultHandler resultHandler, IMediaAccessor mediaAccessor)
        {
            const bool   forceQuickMode = false; // Allow extractions with probably longer runtime.
            ResourcePath path           = mediaItemAccessor.CanonicalLocalResourcePath;

            ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportStatus, path);
            IDictionary <Guid, IList <MediaItemAspect> > aspects = mediaAccessor.ExtractMetadataAsync(mediaItemAccessor, metadataExtractors, forceQuickMode).Result;

            if (aspects == null)
            {
                // No metadata could be extracted
                return(false);
            }
            using (CancellationTokenSource cancelToken = new CancellationTokenSource())
            {
                try
                {
                    resultHandler.UpdateMediaItemAsync(parentDirectoryId, path, MediaItemAspect.GetAspects(aspects), importJob.JobType == ImportJobType.Refresh, importJob.BasePath);
                    resultHandler.DeleteUnderPathAsync(path);
                }
                catch
                {
                    cancelToken.Cancel();
                    throw;
                }
            }
            return(true);
        }
        /// <summary>
        /// Imports or refreshes a single file without a parent directory with the specified <paramref name="fileAccessor"/>.
        /// </summary>
        /// <param name="importJob">The import job being processed.</param>
        /// <param name="fileAccessor">Resource accessor for the file to import.</param>
        /// <param name="metadataExtractors">Metadata extractors to apply on the resource.</param>
        /// <param name="mediaBrowsing">Callback interface to the media library for the refresh import type.</param>
        /// <param name="resultHandler">Callback to notify the import result.</param>
        /// <param name="mediaAccessor">Convenience reference to the media accessor.</param>
        protected void ImportSingleFile(ImportJob importJob, IResourceAccessor fileAccessor,
                                        ICollection <IMetadataExtractor> metadataExtractors, IMediaBrowsing mediaBrowsing,
                                        IImportResultHandler resultHandler, IMediaAccessor mediaAccessor)
        {
            ResourcePath currentFilePath = fileAccessor.CanonicalLocalResourcePath;

            try
            {
                if (importJob.JobType == ImportJobType.Refresh)
                {
                    MediaItem mediaItem = mediaBrowsing.LoadLocalItem(currentFilePath,
                                                                      IMPORTER_MIA_ID_ENUMERATION, EMPTY_MIA_ID_ENUMERATION);
                    MediaItemAspect importerAspect;
                    if (mediaItem != null && mediaItem.Aspects.TryGetValue(ImporterAspect.ASPECT_ID, out importerAspect) &&
                        (DateTime)importerAspect[ImporterAspect.ATTR_LAST_IMPORT_DATE] > fileAccessor.LastChanged)
                    {
                        return;
                    }
                }
                ImportResource(fileAccessor, Guid.Empty, metadataExtractors, resultHandler, mediaAccessor);
            }
            catch (Exception e)
            {
                CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
                ServiceRegistration.Get <ILogger>().Warn("ImporterWorker: Problem while importing resource '{0}'", e, currentFilePath);
                importJob.State = ImportJobState.Erroneous;
            }
        }
        protected Guid GetOrAddDirectory(ImportJob importJob, IFileSystemResourceAccessor directoryAccessor, Guid parentDirectoryId,
                                         IMediaBrowsing mediaBrowsing, IImportResultHandler resultHandler)
        {
            ResourcePath directoryPath = directoryAccessor.CanonicalLocalResourcePath;
            MediaItem    directoryItem = mediaBrowsing.LoadLocalItemAsync(directoryPath, EMPTY_MIA_ID_ENUMERATION, DIRECTORY_MIA_ID_ENUMERATION).Result;

            if (directoryItem != null)
            {
                SingleMediaItemAspect da;
                if (!MediaItemAspect.TryGetAspect(directoryItem.Aspects, DirectoryAspect.Metadata, out da))
                { // This is the case if the path was formerly imported as a non-directory media item; we cannot reuse it
                    resultHandler.DeleteMediaItemAsync(directoryPath);
                    directoryItem = null;
                }
            }
            if (directoryItem == null)
            { // Add directory item to ML
                MediaItemAspect mia = new SingleMediaItemAspect(MediaAspect.Metadata);
                mia.SetAttribute(MediaAspect.ATTR_TITLE, directoryAccessor.ResourceName);
                mia.SetAttribute(MediaAspect.ATTR_SORT_TITLE, directoryAccessor.ResourceName);
                mia.SetAttribute(MediaAspect.ATTR_ISVIRTUAL, false);
                mia.SetAttribute(MediaAspect.ATTR_RECORDINGTIME, DateTime.MinValue);
                mia.SetAttribute(MediaAspect.ATTR_RATING, 0);
                mia.SetAttribute(MediaAspect.ATTR_COMMENT, null);
                mia.SetAttribute(MediaAspect.ATTR_LASTPLAYED, DateTime.MinValue);
                MediaItemAspect         da      = new SingleMediaItemAspect(DirectoryAspect.Metadata);
                IList <MediaItemAspect> aspects = new List <MediaItemAspect>(new[]
                {
                    mia,
                    da,
                });
                return(resultHandler.UpdateMediaItemAsync(parentDirectoryId, directoryPath, aspects, importJob.JobType == ImportJobType.Refresh, importJob.BasePath).Result);
            }
            return(directoryItem.MediaItemId);
        }
        public void ScheduleRefresh(ResourcePath path, IEnumerable <string> mediaCategories, bool includeSubDirectories)
        {
            ICollection <ImportJob> importJobs;

            lock (_syncObj)
                importJobs = new List <ImportJob>(_importJobs);
            ICollection <ImportJob> removeImportJobs = new List <ImportJob>();

            foreach (ImportJob checkJob in importJobs)
            {
                if (checkJob.BasePath.IsSameOrParentOf(path))
                {
                    // The new job is included in an already existing job - re-schedule existing job
                    path = checkJob.BasePath;
                    checkJob.Cancel();
                    removeImportJobs.Add(checkJob);
                }
                if (path.IsParentOf(checkJob.BasePath))
                { // The new job will include the old job
                    checkJob.Cancel();
                    removeImportJobs.Add(checkJob);
                }
            }
            lock (_syncObj)
                foreach (ImportJob removeJob in removeImportJobs)
                {
                    _importJobs.Remove(removeJob);
                }
            ICollection <Guid> metadataExtractorIds = GetMetadataExtractorIdsForMediaCategories(mediaCategories);
            ImportJob          job = new ImportJob(ImportJobType.Refresh, path, metadataExtractorIds, includeSubDirectories);

            EnqueueImportJob(job);
            ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportScheduled, path, ImportJobType.Refresh);
        }
 protected void EnqueueImportJob(ImportJob job)
 {
     lock (_syncObj)
     {
         job.State = ImportJobState.Scheduled;
         _importJobs.Insert(0, job);
         _importJobsReadyAvailableEvent.Set();
     }
 }
Example #6
0
        public override bool Equals(object obj)
        {
            if (!(obj is ImportJob))
            {
                return(false);
            }
            ImportJob other = (ImportJob)obj;

            return(_jobInfo.Equals(other._jobInfo));
        }
 protected ImportJob DequeueImportJob()
 {
     lock (_syncObj)
     {
         ImportJob job = PeekImportJob();
         if (job != null)
         {
             _importJobs.RemoveAt(_importJobs.Count - 1);
         }
         return(job);
     }
 }
        /// <summary>
        /// Imports or refreshes a single file without a parent directory with the specified <paramref name="resourceAccessor"/>.
        /// </summary>
        /// <param name="importJob">The import job being processed.</param>
        /// <param name="resourceAccessor">Resource accessor for the file to import.</param>
        /// <param name="metadataExtractors">Metadata extractors to apply on the resource.</param>
        /// <param name="mediaBrowsing">Callback interface to the media library for the refresh import type.</param>
        /// <param name="resultHandler">Callback to notify the import result.</param>
        /// <param name="mediaAccessor">Convenience reference to the media accessor.</param>
        protected void ImportSingleFile(ImportJob importJob, IResourceAccessor resourceAccessor,
                                        ICollection <IMetadataExtractor> metadataExtractors, IMediaBrowsing mediaBrowsing,
                                        IImportResultHandler resultHandler, IMediaAccessor mediaAccessor)
        {
            ResourcePath currentFilePath = resourceAccessor.CanonicalLocalResourcePath;

            try
            {
                ImportResource(importJob, resourceAccessor, Guid.Empty, metadataExtractors, resultHandler, mediaAccessor);
            }
            catch (Exception e)
            {
                CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
                ServiceRegistration.Get <ILogger>().Warn("ImporterWorker: Problem while importing resource '{0}'", e, currentFilePath);
                importJob.State = ImportJobState.Erroneous;
            }
        }
        public void ScheduleImport(ResourcePath path, IEnumerable <string> mediaCategories, bool includeSubDirectories)
        {
            ICollection <ImportJob> importJobs;

            lock (_syncObj)
                importJobs = new List <ImportJob>(_importJobs);
            if (importJobs.Any(checkJob => checkJob.JobType == ImportJobType.Import && checkJob.BasePath.IsSameOrParentOf(path)))
            {
                // Path is already being scheduled as Import job
                // => the new job is already included in an already existing job
                return;
            }
            CancelJobsForPath(path);
            ICollection <Guid> metadataExtractorIds = GetMetadataExtractorIdsForMediaCategories(mediaCategories);
            ImportJob          job = new ImportJob(ImportJobType.Import, path, metadataExtractorIds, includeSubDirectories);

            EnqueueImportJob(job);
            ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportScheduled, path, ImportJobType.Import);
        }
Example #10
0
 /// <summary>
 /// Imports or refreshes a single file without a parent directory with the specified <paramref name="fileAccessor"/>.
 /// </summary>
 /// <param name="importJob">The import job being processed.</param>
 /// <param name="fileAccessor">Resource accessor for the file to import.</param>
 /// <param name="metadataExtractors">Metadata extractors to apply on the resource.</param>
 /// <param name="mediaBrowsing">Callback interface to the media library for the refresh import type.</param>
 /// <param name="resultHandler">Callback to notify the import result.</param>
 /// <param name="mediaAccessor">Convenience reference to the media accessor.</param>
 protected void ImportSingleFile(ImportJob importJob, IResourceAccessor fileAccessor,
     ICollection<IMetadataExtractor> metadataExtractors, IMediaBrowsing mediaBrowsing,
     IImportResultHandler resultHandler, IMediaAccessor mediaAccessor)
 {
   ResourcePath currentFilePath = fileAccessor.CanonicalLocalResourcePath;
   try
   {
     if (importJob.JobType == ImportJobType.Refresh)
     {
       MediaItem mediaItem = mediaBrowsing.LoadLocalItem(currentFilePath,
           IMPORTER_MIA_ID_ENUMERATION, EMPTY_MIA_ID_ENUMERATION);
       MediaItemAspect importerAspect;
       if (mediaItem != null && mediaItem.Aspects.TryGetValue(ImporterAspect.ASPECT_ID, out importerAspect) &&
           (DateTime) importerAspect[ImporterAspect.ATTR_LAST_IMPORT_DATE] > fileAccessor.LastChanged)
         return;
     }
     ImportResource(fileAccessor, Guid.Empty, metadataExtractors, resultHandler, mediaAccessor);
   }
   catch (Exception e)
   {
     CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
     ServiceRegistration.Get<ILogger>().Warn("ImporterWorker: Problem while importing resource '{0}'", e, currentFilePath);
     importJob.State = ImportJobState.Erroneous;
   }
 }
        /// <summary>
        /// Executes the given <paramref name="importJob"/>.
        /// </summary>
        /// <remarks>
        /// This method automatically terminates if it encounters that this importer worker was suspended or that the
        /// given <paramref name="importJob"/> was cancelled.
        /// </remarks>
        /// <param name="importJob">Import job to be executed. The state variables of this parameter will be updated by
        /// this method.</param>
        protected void Process(ImportJob importJob)
        {
            ImportJobState state = importJob.State;

            if (state == ImportJobState.Finished || state == ImportJobState.Cancelled || state == ImportJobState.Erroneous)
            {
                return;
            }

            // Preparation
            IMediaAccessor       mediaAccessor = ServiceRegistration.Get <IMediaAccessor>();
            IImportResultHandler resultHandler;
            IMediaBrowsing       mediaBrowsing;

            lock (_syncObj)
            {
                resultHandler = _importResultHandler;
                mediaBrowsing = _mediaBrowsingCallback;
            }
            if (mediaBrowsing == null || resultHandler == null)
            {
                // Can be the case if this importer worker was asynchronously suspended
                return;
            }
            try
            {
                try
                {
                    ICollection <IMetadataExtractor> metadataExtractors = new List <IMetadataExtractor>();
                    foreach (Guid metadataExtractorId in importJob.MetadataExtractorIds)
                    {
                        IMetadataExtractor extractor;
                        if (!mediaAccessor.LocalMetadataExtractors.TryGetValue(metadataExtractorId, out extractor))
                        {
                            continue;
                        }
                        metadataExtractors.Add(extractor);
                    }

                    // Prepare import
                    if (state == ImportJobState.Scheduled)
                    {
                        ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Starting import job '{0}'", importJob);
                        ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportStarted, importJob.BasePath);
                        IResourceAccessor ra;
                        if (!importJob.BasePath.TryCreateLocalResourceAccessor(out ra))
                        {
                            throw new ArgumentException(string.Format("Unable to access resource path '{0}'", importJob.BasePath));
                        }
                        using (ra)
                        {
                            IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor;
                            if (fsra != null)
                            { // Prepare complex import process
                                importJob.PendingResources.Add(new PendingImportResource(Guid.Empty, (IFileSystemResourceAccessor)fsra.Clone()));
                                importJob.State = ImportJobState.Active;
                            }
                            else
                            { // Simple resource import
                                ImportSingleFile(importJob, ra, metadataExtractors, mediaBrowsing, resultHandler, mediaAccessor);
                                lock (importJob.SyncObj)
                                    if (importJob.State == ImportJobState.Active)
                                    {
                                        importJob.State = ImportJobState.Finished;
                                    }
                                return;
                            }
                        }
                    }
                    else
                    {
                        ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Resuming import job '{0}' ({1} items pending)", importJob, importJob.PendingResources.Count);
                    }

                    // Actual import process
                    while (importJob.HasPendingResources)
                    {
                        Thread.Sleep(0);
                        CheckImportStillRunning(importJob.State);
                        PendingImportResource pendingImportResource;
                        lock (importJob.SyncObj)
                            pendingImportResource = importJob.PendingResources.FirstOrDefault();
                        if (pendingImportResource.IsValid)
                        {
                            IFileSystemResourceAccessor fsra = pendingImportResource.ResourceAccessor;
                            int    numPending    = importJob.PendingResources.Count;
                            string moreResources = numPending > 1 ? string.Format(" ({0} more resources pending)", numPending) : string.Empty;
                            ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Importing '{0}'{1}", fsra.ResourcePathName, moreResources);
                            if (fsra.IsFile && fsra.Exists)
                            {
                                ImportResource(importJob, fsra, pendingImportResource.ParentDirectory, metadataExtractors, resultHandler, mediaAccessor);
                            }
                            else if (!fsra.IsFile)
                            {
                                CheckImportStillRunning(importJob.State);
                                Guid?currentDirectoryId = ImportDirectory(importJob, pendingImportResource.ParentDirectory, fsra, metadataExtractors,
                                                                          mediaBrowsing, resultHandler, mediaAccessor);
                                CheckImportStillRunning(importJob.State);
                                if (currentDirectoryId.HasValue && importJob.IncludeSubDirectories)
                                {
                                    // Add subdirectories in front of work queue
                                    lock (importJob.SyncObj)
                                    {
                                        ICollection <IFileSystemResourceAccessor> directories = FileSystemResourceNavigator.GetChildDirectories(fsra, false);
                                        if (directories != null)
                                        {
                                            foreach (IFileSystemResourceAccessor childDirectory in directories)
                                            {
                                                importJob.PendingResources.Insert(0, new PendingImportResource(currentDirectoryId.Value, childDirectory));
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                ServiceRegistration.Get <ILogger>().Warn("ImporterWorker: Cannot import resource '{0}': It's neither a file nor a directory", fsra.CanonicalLocalResourcePath.Serialize());
                            }
                        }
                        lock (importJob.SyncObj)
                            importJob.PendingResources.Remove(pendingImportResource);
                        pendingImportResource.Dispose();
                    }
                    lock (importJob.SyncObj)
                        if (importJob.State == ImportJobState.Active)
                        {
                            importJob.State = ImportJobState.Finished;
                        }
                    ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Finished import job '{0}'", importJob);
                    ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportCompleted, importJob.BasePath);
                }
                catch (Exception e)
                {
                    CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
                    ServiceRegistration.Get <ILogger>().Warn("ImporterWorker: Problem processing '{0}'", e, importJob);
                    ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportCompleted, importJob.BasePath);
                    importJob.State = ImportJobState.Erroneous;
                }
            }
            catch (ImportSuspendedException)
            {
                ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Suspending import job '{0}' ({1} items pending - will be continued next time)", importJob, importJob.PendingResources.Count);
            }
            catch (ImportAbortException)
            {
                ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Aborting import job '{0}' ({1} items pending)", importJob, importJob.PendingResources.Count);
            }
        }
        /// <summary>
        /// Imports or refreshes the directory with the specified <paramref name="directoryAccessor"/>. Sub directories will not
        /// be processed in this method.
        /// </summary>
        /// <param name="importJob">The import job being processed.</param>
        /// <param name="parentDirectoryId">Media item id of the parent directory, if present, else <see cref="Guid.Empty"/>.</param>
        /// <param name="directoryAccessor">Resource accessor for the directory to import.</param>
        /// <param name="metadataExtractors">Metadata extractors to apply on the resources.</param>
        /// <param name="mediaBrowsing">Callback interface to the media library for the refresh import type.</param>
        /// <param name="resultHandler">Callback to notify the import result.</param>
        /// <param name="mediaAccessor">Convenience reference to the media accessor.</param>
        /// <returns>Id of the directory's media item or <c>null</c>, if the given <paramref name="directoryAccessor"/>
        /// was imported as a media item or if an error occured. If <c>null</c> is returned, the directory import should be
        /// considered to be finished.</returns>
        protected Guid?ImportDirectory(ImportJob importJob, Guid parentDirectoryId, IFileSystemResourceAccessor directoryAccessor,
                                       ICollection <IMetadataExtractor> metadataExtractors, IMediaBrowsing mediaBrowsing,
                                       IImportResultHandler resultHandler, IMediaAccessor mediaAccessor)
        {
            ResourcePath currentDirectoryPath = directoryAccessor.CanonicalLocalResourcePath;

            try
            {
                ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportStatus, currentDirectoryPath);
                if (ImportResource(importJob, directoryAccessor, parentDirectoryId, metadataExtractors, resultHandler, mediaAccessor))
                {
                    // The directory could be imported as a media item.
                    // If the directory itself was identified as a normal media item, don't import its children.
                    // Necessary for DVD directories, for example.
                    return(null);
                }
                Guid directoryId = GetOrAddDirectory(importJob, directoryAccessor, parentDirectoryId, mediaBrowsing, resultHandler);
                IDictionary <string, MediaItem> path2Item = new Dictionary <string, MediaItem>();
                if (importJob.JobType == ImportJobType.Refresh)
                {
                    foreach (MediaItem mediaItem in mediaBrowsing.BrowseAsync(directoryId,
                                                                              IMPORTER_PROVIDER_MIA_ID_ENUMERATION, EMPTY_MIA_ID_ENUMERATION, null, false).Result)
                    {
                        IList <MultipleMediaItemAspect> providerResourceAspects;
                        if (MediaItemAspect.TryGetAspects(mediaItem.Aspects, ProviderResourceAspect.Metadata, out providerResourceAspects))
                        {
                            path2Item[providerResourceAspects[0].GetAttributeValue <string>(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH)] = mediaItem;
                        }
                    }
                }
                CheckImportStillRunning(importJob.State);
                ICollection <IFileSystemResourceAccessor> files = FileSystemResourceNavigator.GetFiles(directoryAccessor, false);
                if (files != null)
                {
                    foreach (IFileSystemResourceAccessor fileAccessor in files)
                    {
                        using (fileAccessor)
                        { // Add & update files
                            ResourcePath currentFilePath    = fileAccessor.CanonicalLocalResourcePath;
                            string       serializedFilePath = currentFilePath.Serialize();
                            try
                            {
                                SingleMediaItemAspect importerAspect;
                                MediaItem             mediaItem;
                                if (importJob.JobType == ImportJobType.Refresh &&
                                    path2Item.TryGetValue(serializedFilePath, out mediaItem) &&
                                    MediaItemAspect.TryGetAspect(mediaItem.Aspects, ImporterAspect.Metadata, out importerAspect) &&
                                    importerAspect.GetAttributeValue <DateTime>(ImporterAspect.ATTR_LAST_IMPORT_DATE) > fileAccessor.LastChanged)
                                { // We can skip this file; it was imported after the last change time of the item
                                    path2Item.Remove(serializedFilePath);
                                    continue;
                                }
                                if (ImportResource(importJob, fileAccessor, directoryId, metadataExtractors, resultHandler, mediaAccessor))
                                {
                                    path2Item.Remove(serializedFilePath);
                                }
                            }
                            catch (Exception e)
                            {
                                CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
                                ServiceRegistration.Get <ILogger>().Warn("ImporterWorker: Problem while importing resource '{0}'", e, serializedFilePath);
                                importJob.State = ImportJobState.Erroneous;
                            }
                            CheckImportStillRunning(importJob.State);
                        }
                    }
                }
                if (importJob.JobType == ImportJobType.Refresh)
                { // Remove remaining (= non-present) files
                    foreach (string pathStr in path2Item.Keys)
                    {
                        ResourcePath path = ResourcePath.Deserialize(pathStr);
                        try
                        {
                            IResourceAccessor ra;
                            if (!path.TryCreateLocalResourceAccessor(out ra))
                            {
                                throw new IllegalCallException("Unable to access resource path '{0}'", importJob.BasePath);
                            }
                            using (ra)
                            {
                                IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor;
                                if (fsra == null || !fsra.IsFile)
                                {
                                    // Don't touch directories because they will be imported in a different call of ImportDirectory
                                    continue;
                                }
                            }
                        }
                        catch (IllegalCallException)
                        {
                            // This happens if the resource doesn't exist any more - we also catch missing directories here
                        }
                        // Delete all remaining items
                        resultHandler.DeleteMediaItemAsync(path);
                        CheckImportStillRunning(importJob.State);
                    }
                }
                return(directoryId);
            }
            catch (ImportSuspendedException)
            {
                throw;
            }
            catch (ImportAbortException)
            {
                throw;
            }
            catch (UnauthorizedAccessException e)
            {
                // If the access to the file or folder was denied, simply continue with the others
                ServiceRegistration.Get <ILogger>().Warn("ImporterWorker: Problem accessing resource '{0}', continueing with one", e, currentDirectoryPath);
            }
            catch (Exception e)
            {
                CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
                ServiceRegistration.Get <ILogger>().Warn("ImporterWorker: Problem while importing directory '{0}'", e, currentDirectoryPath);
                importJob.State = ImportJobState.Erroneous;
            }
            return(null);
        }
Example #13
0
 protected void EnqueueImportJob(ImportJob job)
 {
   lock (_syncObj)
   {
     job.State = ImportJobState.Scheduled;
     _importJobs.Insert(0, job);
     _importJobsReadyAvailableEvent.Set();
   }
 }
Example #14
0
 protected void RemoveImportJob(ImportJob job)
 {
   lock (_syncObj)
     _importJobs.Remove(job);
   job.Dispose();
 }
 protected void RemoveImportJob(ImportJob job)
 {
     lock (_syncObj)
         _importJobs.Remove(job);
     job.Dispose();
 }
Example #16
0
 /// <summary>
 /// Imports or refreshes a single file without a parent directory with the specified <paramref name="resourceAccessor"/>.
 /// </summary>
 /// <param name="importJob">The import job being processed.</param>
 /// <param name="resourceAccessor">Resource accessor for the file to import.</param>
 /// <param name="metadataExtractors">Metadata extractors to apply on the resource.</param>
 /// <param name="mediaBrowsing">Callback interface to the media library for the refresh import type.</param>
 /// <param name="resultHandler">Callback to notify the import result.</param>
 /// <param name="mediaAccessor">Convenience reference to the media accessor.</param>
 protected void ImportSingleFile(ImportJob importJob, IResourceAccessor resourceAccessor,
     ICollection<IMetadataExtractor> metadataExtractors, IMediaBrowsing mediaBrowsing,
     IImportResultHandler resultHandler, IMediaAccessor mediaAccessor)
 {
   ResourcePath currentFilePath = resourceAccessor.CanonicalLocalResourcePath;
   try
   {
     ImportResource(resourceAccessor, Guid.Empty, metadataExtractors, resultHandler, mediaAccessor);
   }
   catch (Exception e)
   {
     CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
     ServiceRegistration.Get<ILogger>().Warn("ImporterWorker: Problem while importing resource '{0}'", e, currentFilePath);
     importJob.State = ImportJobState.Erroneous;
   }
 }
Example #17
0
 public void ScheduleRefresh(ResourcePath path, IEnumerable<string> mediaCategories, bool includeSubDirectories)
 {
   ICollection<ImportJob> importJobs;
   lock (_syncObj)
     importJobs = new List<ImportJob>(_importJobs);
   ICollection<ImportJob> removeImportJobs = new List<ImportJob>();
   foreach (ImportJob checkJob in importJobs)
   {
     if (checkJob.BasePath.IsSameOrParentOf(path))
     {
       // The new job is included in an already existing job - re-schedule existing job
       path = checkJob.BasePath;
       checkJob.Cancel();
       removeImportJobs.Add(checkJob);
     }
     if (path.IsParentOf(checkJob.BasePath))
     { // The new job will include the old job
       checkJob.Cancel();
       removeImportJobs.Add(checkJob);
     }
   }
   lock (_syncObj)
     foreach (ImportJob removeJob in removeImportJobs)
       _importJobs.Remove(removeJob);
   ICollection<Guid> metadataExtractorIds = GetMetadataExtractorIdsForMediaCategories(mediaCategories);
   ImportJob job = new ImportJob(ImportJobType.Refresh, path, metadataExtractorIds, includeSubDirectories);
   EnqueueImportJob(job);
   ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportScheduled, path, ImportJobType.Refresh);
 }
Example #18
0
 public void ScheduleImport(ResourcePath path, IEnumerable<string> mediaCategories, bool includeSubDirectories)
 {
   ICollection<ImportJob> importJobs;
   lock (_syncObj)
     importJobs = new List<ImportJob>(_importJobs);
   if (importJobs.Any(checkJob => checkJob.JobType == ImportJobType.Import && checkJob.BasePath.IsSameOrParentOf(path)))
     // Path is already being scheduled as Import job
     // => the new job is already included in an already existing job
     return;
   CancelJobsForPath(path);
   ICollection<Guid> metadataExtractorIds = GetMetadataExtractorIdsForMediaCategories(mediaCategories);
   ImportJob job = new ImportJob(ImportJobType.Import, path, metadataExtractorIds, includeSubDirectories);
   EnqueueImportJob(job);
   ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportScheduled, path, ImportJobType.Import);
 }
Example #19
0
    /// <summary>
    /// Executes the given <paramref name="importJob"/>.
    /// </summary>
    /// <remarks>
    /// This method automatically terminates if it encounters that this importer worker was suspended or that the
    /// given <paramref name="importJob"/> was cancelled.
    /// </remarks>
    /// <param name="importJob">Import job to be executed. The state variables of this parameter will be updated by
    /// this method.</param>
    protected void Process(ImportJob importJob)
    {
      ImportJobState state = importJob.State;
      if (state == ImportJobState.Finished || state == ImportJobState.Cancelled || state == ImportJobState.Erroneous)
        return;

      // Preparation
      IMediaAccessor mediaAccessor = ServiceRegistration.Get<IMediaAccessor>();
      IImportResultHandler resultHandler;
      IMediaBrowsing mediaBrowsing;
      lock (_syncObj)
      {
        resultHandler = _importResultHandler;
        mediaBrowsing = _mediaBrowsingCallback;
      }
      if (mediaBrowsing == null || resultHandler == null)
        // Can be the case if this importer worker was asynchronously suspended
        return;
      try
      {
        try
        {
          ICollection<IMetadataExtractor> metadataExtractors = new List<IMetadataExtractor>();
          foreach (Guid metadataExtractorId in importJob.MetadataExtractorIds)
          {
            IMetadataExtractor extractor;
            if (!mediaAccessor.LocalMetadataExtractors.TryGetValue(metadataExtractorId, out extractor))
              continue;
            metadataExtractors.Add(extractor);
          }

          // Prepare import
          if (state == ImportJobState.Scheduled)
          {
            ServiceRegistration.Get<ILogger>().Info("ImporterWorker: Starting import job '{0}'", importJob);
            ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportStarted, importJob.BasePath);
            IResourceAccessor ra;
            if (!importJob.BasePath.TryCreateLocalResourceAccessor(out ra))
              throw new ArgumentException(string.Format("Unable to access resource path '{0}'", importJob.BasePath));
            using (ra)
            {
              IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor;
              if (fsra != null)
              { // Prepare complex import process
                importJob.PendingResources.Add(new PendingImportResource(Guid.Empty, (IFileSystemResourceAccessor) fsra.Clone()));
                importJob.State = ImportJobState.Active;
              }
              else
              { // Simple resource import
                ImportSingleFile(importJob, ra, metadataExtractors, mediaBrowsing, resultHandler, mediaAccessor);
                lock (importJob.SyncObj)
                  if (importJob.State == ImportJobState.Active)
                    importJob.State = ImportJobState.Finished;
                return;
              }
            }
          }
          else
            ServiceRegistration.Get<ILogger>().Info("ImporterWorker: Resuming import job '{0}' ({1} items pending)", importJob, importJob.PendingResources.Count);

          // Actual import process
          while (importJob.HasPendingResources)
          {
            Thread.Sleep(0);
            CheckImportStillRunning(importJob.State);
            PendingImportResource pendingImportResource;
            lock (importJob.SyncObj)
              pendingImportResource = importJob.PendingResources.FirstOrDefault();
            if (pendingImportResource.IsValid)
            {
              IFileSystemResourceAccessor fsra = pendingImportResource.ResourceAccessor;
              int numPending = importJob.PendingResources.Count;
              string moreResources = numPending > 1 ? string.Format(" ({0} more resources pending)", numPending) : string.Empty;
              ServiceRegistration.Get<ILogger>().Info("ImporterWorker: Importing '{0}'{1}", fsra.ResourcePathName, moreResources);
              if (fsra.IsFile && fsra.Exists)
                ImportResource(fsra, pendingImportResource.ParentDirectory, metadataExtractors, resultHandler, mediaAccessor);
              else if (!fsra.IsFile)
              {
                CheckImportStillRunning(importJob.State);
                Guid? currentDirectoryId = ImportDirectory(importJob, pendingImportResource.ParentDirectory, fsra, metadataExtractors,
                    mediaBrowsing, resultHandler, mediaAccessor);
                CheckImportStillRunning(importJob.State);
                if (currentDirectoryId.HasValue && importJob.IncludeSubDirectories)
                  // Add subdirectories in front of work queue
                  lock (importJob.SyncObj)
                  {
                    ICollection<IFileSystemResourceAccessor> directories = FileSystemResourceNavigator.GetChildDirectories(fsra, false);
                    if (directories != null)
                      foreach (IFileSystemResourceAccessor childDirectory in directories)
                        importJob.PendingResources.Insert(0, new PendingImportResource(currentDirectoryId.Value, childDirectory));
                  }
              }
              else
                ServiceRegistration.Get<ILogger>().Warn("ImporterWorker: Cannot import resource '{0}': It's neither a file nor a directory", fsra.CanonicalLocalResourcePath.Serialize());
            }
            lock (importJob.SyncObj)
              importJob.PendingResources.Remove(pendingImportResource);
            pendingImportResource.Dispose();
          }
          lock (importJob.SyncObj)
            if (importJob.State == ImportJobState.Active)
              importJob.State = ImportJobState.Finished;
          ServiceRegistration.Get<ILogger>().Info("ImporterWorker: Finished import job '{0}'", importJob);
          ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportCompleted, importJob.BasePath);
        }
        catch (Exception e)
        {
          CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
          ServiceRegistration.Get<ILogger>().Warn("ImporterWorker: Problem processing '{0}'", e, importJob);
          ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportCompleted, importJob.BasePath);
          importJob.State = ImportJobState.Erroneous;
        }
      }
      catch (ImportSuspendedException)
      {
        ServiceRegistration.Get<ILogger>().Info("ImporterWorker: Suspending import job '{0}' ({1} items pending - will be continued next time)", importJob, importJob.PendingResources.Count);
      }
      catch (ImportAbortException)
      {
        ServiceRegistration.Get<ILogger>().Info("ImporterWorker: Aborting import job '{0}' ({1} items pending)", importJob, importJob.PendingResources.Count);
      }
    }
Example #20
0
 /// <summary>
 /// Imports or refreshes the directory with the specified <paramref name="directoryAccessor"/>. Sub directories will not
 /// be processed in this method.
 /// </summary>
 /// <param name="importJob">The import job being processed.</param>
 /// <param name="parentDirectoryId">Media item id of the parent directory, if present, else <see cref="Guid.Empty"/>.</param>
 /// <param name="directoryAccessor">Resource accessor for the directory to import.</param>
 /// <param name="metadataExtractors">Metadata extractors to apply on the resources.</param>
 /// <param name="mediaBrowsing">Callback interface to the media library for the refresh import type.</param>
 /// <param name="resultHandler">Callback to notify the import result.</param>
 /// <param name="mediaAccessor">Convenience reference to the media accessor.</param>
 /// <returns>Id of the directory's media item or <c>null</c>, if the given <paramref name="directoryAccessor"/>
 /// was imported as a media item or if an error occured. If <c>null</c> is returned, the directory import should be
 /// considered to be finished.</returns>
 protected Guid? ImportDirectory(ImportJob importJob, Guid parentDirectoryId, IFileSystemResourceAccessor directoryAccessor,
     ICollection<IMetadataExtractor> metadataExtractors, IMediaBrowsing mediaBrowsing,
     IImportResultHandler resultHandler, IMediaAccessor mediaAccessor)
 {
   ResourcePath currentDirectoryPath = directoryAccessor.CanonicalLocalResourcePath;
   try
   {
     ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportStatus, currentDirectoryPath);
     if (ImportResource(directoryAccessor, parentDirectoryId, metadataExtractors, resultHandler, mediaAccessor))
       // The directory could be imported as a media item.
       // If the directory itself was identified as a normal media item, don't import its children.
       // Necessary for DVD directories, for example.
       return null;
     Guid directoryId = GetOrAddDirectory(directoryAccessor, parentDirectoryId, mediaBrowsing, resultHandler);
     IDictionary<string, MediaItem> path2Item = new Dictionary<string, MediaItem>();
     if (importJob.JobType == ImportJobType.Refresh)
     {
       foreach (MediaItem mediaItem in mediaBrowsing.Browse(directoryId,
           IMPORTER_PROVIDER_MIA_ID_ENUMERATION, EMPTY_MIA_ID_ENUMERATION))
       {
         MediaItemAspect providerResourceAspect;
         if (mediaItem.Aspects.TryGetValue(ProviderResourceAspect.ASPECT_ID, out providerResourceAspect))
           path2Item[providerResourceAspect.GetAttributeValue<string>(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH)] = mediaItem;
       }
     }
     CheckImportStillRunning(importJob.State);
     ICollection<IFileSystemResourceAccessor> files = FileSystemResourceNavigator.GetFiles(directoryAccessor, false);
     if (files != null)
       foreach (IFileSystemResourceAccessor fileAccessor in files)
         using (fileAccessor)
         { // Add & update files
           ResourcePath currentFilePath = fileAccessor.CanonicalLocalResourcePath;
           string serializedFilePath = currentFilePath.Serialize();
           try
           {
             MediaItemAspect importerAspect;
             MediaItem mediaItem;
             if (importJob.JobType == ImportJobType.Refresh &&
                 path2Item.TryGetValue(serializedFilePath, out mediaItem) &&
                 mediaItem.Aspects.TryGetValue(ImporterAspect.ASPECT_ID, out importerAspect) &&
                 importerAspect.GetAttributeValue<DateTime>(ImporterAspect.ATTR_LAST_IMPORT_DATE) > fileAccessor.LastChanged)
             { // We can skip this file; it was imported after the last change time of the item
               path2Item.Remove(serializedFilePath);
               continue;
             }
             if (ImportResource(fileAccessor, directoryId, metadataExtractors, resultHandler, mediaAccessor))
               path2Item.Remove(serializedFilePath);
           }
           catch (Exception e)
           {
             CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
             ServiceRegistration.Get<ILogger>().Warn("ImporterWorker: Problem while importing resource '{0}'", e, serializedFilePath);
             importJob.State = ImportJobState.Erroneous;
           }
           CheckImportStillRunning(importJob.State);
         }
     if (importJob.JobType == ImportJobType.Refresh)
     { // Remove remaining (= non-present) files
       foreach (string pathStr in path2Item.Keys)
       {
         ResourcePath path = ResourcePath.Deserialize(pathStr);
         try
         {
           IResourceAccessor ra;
           if (!path.TryCreateLocalResourceAccessor(out ra))
             throw new IllegalCallException("Unable to access resource path '{0}'", importJob.BasePath);
           using (ra)
           {
             IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor;
             if (fsra == null || !fsra.IsFile)
               // Don't touch directories because they will be imported in a different call of ImportDirectory
               continue;
           }
         }
         catch (IllegalCallException)
         {
           // This happens if the resource doesn't exist any more - we also catch missing directories here
         }
         // Delete all remaining items
         resultHandler.DeleteMediaItem(path);
         CheckImportStillRunning(importJob.State);
       }
     }
     return directoryId;
   }
   catch (ImportSuspendedException)
   {
     throw;
   }
   catch (ImportAbortException)
   {
     throw;
   }
   catch (UnauthorizedAccessException e)
   {
     // If the access to the file or folder was denied, simply continue with the others
     ServiceRegistration.Get<ILogger>().Warn("ImporterWorker: Problem accessing resource '{0}', continueing with one", e, currentDirectoryPath);
   }
   catch (Exception e)
   {
     CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
     ServiceRegistration.Get<ILogger>().Warn("ImporterWorker: Problem while importing directory '{0}'", e, currentDirectoryPath);
     importJob.State = ImportJobState.Erroneous;
   }
   return null;
 }