public ImporterWorkerAction(ActionType actionType, IMediaBrowsing mediaBrowsingCallback, IImportResultHandler importResultHandler) { if (actionType == ActionType.Startup) { throw new ArgumentException("ActionType.Startup must not relate to an IMediaBrowsing and an IImportResultHandler"); } if (actionType == ActionType.ScheduleImport) { throw new ArgumentException("ActionType.ScheduleImport must not relate to an IMediaBrowsing and an IImportResultHandler and requires an ImportJobInformation"); } if (actionType == ActionType.CancelImport) { throw new ArgumentException("ActionType.CancelImport must not relate to an IMediaBrowsing and an IImportResultHandler"); } if (actionType == ActionType.Suspend) { throw new ArgumentException("ActionType.Suspend must not relate to an IMediaBrowsing and an IImportResultHandler"); } if (actionType == ActionType.Shutdown) { throw new ArgumentException("ActionType.Shutdown must not relate to an IMediaBrowsing and an IImportResultHandler"); } _actionType = actionType; _importJobInformation = null; _mediaBrowsingCallback = mediaBrowsingCallback; _importResultHandler = importResultHandler; _tcs = new TaskCompletionSource <object>(); }
/// <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); }
private void DoActivate(IMediaBrowsing mediaBrowsingCallback, IImportResultHandler importResultHandler) { if (_status != Status.Suspended) { ServiceRegistration.Get <ILogger>().Error("ImporterWorker: Activation was requested although status was not 'Suspended' but '{0}'", _status); return; } _mediaBrowsing = mediaBrowsingCallback; _importResultHandler = importResultHandler; foreach (var kvp in _importJobControllers) { // To avoid peaks on system startup when multiple ImportJobs were saved to disk and are now // reactivated, we start one ImportJob every 500ms. // Currently we also need this because the MediaAccessor is not threadsafe on startup // see here: http://forum.team-mediaportal.com/threads/mediaaccessor-not-thread-safe.125132/ // ToDo: Make MediaAccessor threadsafe on startup Task.Delay(500).Wait(); kvp.Value.Activate(_mediaBrowsing, _importResultHandler); } _status = Status.Activated; ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Activated ({0} ImportJobs pending)", _importJobControllers.Count); }
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); }
/// <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; } }
public void Activate(IMediaBrowsing mediaBrowsingCallback, IImportResultHandler importResultHandler) { lock (_syncObj) { _mediaBrowsingCallback = mediaBrowsingCallback; _importResultHandler = importResultHandler; } StartImporterLoop_NoLock(); }
public void Activate(IMediaBrowsing mediaBrowsingCallback, IImportResultHandler importResultHandler) { _mediaBrowsingCallback = mediaBrowsingCallback; _importResultHandler = importResultHandler; _suspensionLink = InputBlock.LinkTo(InnerBlock, new DataflowLinkOptions { PropagateCompletion = true }); _stopWatch.Start(); Activated.Set(); }
public ImporterWorkerAction(ActionType actionType) { if (actionType == ActionType.Activate) throw new ArgumentException("ActionType.Activate requires an IMediaBrowsing and an IImportResultHandler"); if (actionType == ActionType.ScheduleImport) throw new ArgumentException("ActionType.ScheduleImport requires an ImportJobInformation"); _actionType = actionType; _importJobInformation = null; _mediaBrowsingCallback = null; _importResultHandler = null; _tcs = new TaskCompletionSource<object>(); }
/// <summary> /// Activates the ImportJob /// </summary> /// <param name="mediaBrowsingCallback"></param> /// <param name="importResultHandler"></param> public void Activate(IMediaBrowsing mediaBrowsingCallback, IImportResultHandler importResultHandler) { // To avoid peaks on system startup we start one Block every 100ms. // Currently we also need this because the MediaAccessor is not threadsafe on startup // see here: http://forum.team-mediaportal.com/threads/mediaaccessor-not-thread-safe.125132/ // ToDo: Make MediaAccessor threadsafe on startup foreach (var block in _dataflowBlocks) { block.Activate(mediaBrowsingCallback, importResultHandler); Task.Delay(100).Wait(); } ServiceRegistration.Get <ILogger>().Info("ImporterWorker.{0}: Activated", this); ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportStarted, _importJobInformation.BasePath); }
public void Activate(IMediaBrowsing mediaBrowsingCallback, IImportResultHandler importResultHandler) { if (mediaBrowsingCallback == null) { throw new ArgumentNullException("mediaBrowsingCallback"); } if (importResultHandler == null) { throw new ArgumentNullException("importResultHandler"); } ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Activation requested..."); RequestAction(new ImporterWorkerAction(ImporterWorkerAction.ActionType.Activate, mediaBrowsingCallback, importResultHandler)); }
public ImporterWorkerAction(ActionType actionType) { if (actionType == ActionType.Activate) { throw new ArgumentException("ActionType.Activate requires an IMediaBrowsing and an IImportResultHandler"); } if (actionType == ActionType.ScheduleImport) { throw new ArgumentException("ActionType.ScheduleImport requires an ImportJobInformation"); } _actionType = actionType; _importJobInformation = null; _mediaBrowsingCallback = null; _importResultHandler = null; _tcs = new TaskCompletionSource <object>(); }
public ImporterWorkerAction(ActionType actionType, ImportJobInformation importJobInformation) { if (actionType == ActionType.Startup) throw new ArgumentException("ActionType.Startup must not relate to an ImportJobInformation"); if (actionType == ActionType.Activate) throw new ArgumentException("ActionType.Activate must not relate to an ImportJobInformation and requires an IMediaBrowsing and an IImportResultHandler"); if (actionType == ActionType.Suspend) throw new ArgumentException("ActionType.Suspend must not relate to an ImportJobInformation"); if (actionType == ActionType.Shutdown) throw new ArgumentException("ActionType.Shutdown must not relate to an ImportJobInformation"); _actionType = actionType; _importJobInformation = importJobInformation; _mediaBrowsingCallback = null; _importResultHandler = null; _tcs = new TaskCompletionSource<object>(); }
/// <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 ImporterWorkerAction(ActionType actionType, IMediaBrowsing mediaBrowsingCallback, IImportResultHandler importResultHandler) { if (actionType == ActionType.Startup) throw new ArgumentException("ActionType.Startup must not relate to an IMediaBrowsing and an IImportResultHandler"); if (actionType == ActionType.ScheduleImport) throw new ArgumentException("ActionType.ScheduleImport must not relate to an IMediaBrowsing and an IImportResultHandler and requires an ImportJobInformation"); if (actionType == ActionType.CancelImport) throw new ArgumentException("ActionType.CancelImport must not relate to an IMediaBrowsing and an IImportResultHandler"); if (actionType == ActionType.Suspend) throw new ArgumentException("ActionType.Suspend must not relate to an IMediaBrowsing and an IImportResultHandler"); if (actionType == ActionType.Shutdown) throw new ArgumentException("ActionType.Shutdown must not relate to an IMediaBrowsing and an IImportResultHandler"); _actionType = actionType; _importJobInformation = null; _mediaBrowsingCallback = mediaBrowsingCallback; _importResultHandler = importResultHandler; _tcs = new TaskCompletionSource<object>(); }
public void Activate(IMediaBrowsing mediaBrowsingCallback, IImportResultHandler importResultHandler) { if (mediaBrowsingCallback == null) throw new ArgumentNullException("mediaBrowsingCallback"); if (importResultHandler == null) throw new ArgumentNullException("importResultHandler"); ServiceRegistration.Get<ILogger>().Info("ImporterWorker: Activation requested..."); RequestAction(new ImporterWorkerAction(ImporterWorkerAction.ActionType.Activate, mediaBrowsingCallback, importResultHandler)); }
/// <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); }
public MediaLibrary() { ISystemResolver systemResolver = ServiceRegistration.Get<ISystemResolver>(); _localSystemId = systemResolver.LocalSystemId; _mediaBrowsingCallback = new MediaBrowsingCallback(this); _importResultHandler = new ImportResultHandler(this); _messageQueue = new AsynchronousMessageQueue(this, new string[] { ImporterWorkerMessaging.CHANNEL }); _messageQueue.MessageReceived += OnMessageReceived; _messageQueue.Start(); }
/// <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(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, MediaItemAspect> aspects = mediaAccessor.ExtractMetadata(mediaItemAccessor, metadataExtractors, forceQuickMode); if (aspects == null) // No metadata could be extracted return false; resultHandler.UpdateMediaItem(parentDirectoryId, path, aspects.Values); resultHandler.DeleteUnderPath(path); return true; }
/// <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(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, MediaItemAspect> aspects = mediaAccessor.ExtractMetadata(mediaItemAccessor, metadataExtractors, forceQuickMode); if (aspects == null) { // No metadata could be extracted return(false); } resultHandler.UpdateMediaItem(parentDirectoryId, path, aspects.Values); resultHandler.DeleteUnderPath(path); return(true); }
/// <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; } }
protected Guid GetOrAddDirectory(IFileSystemResourceAccessor directoryAccessor, Guid parentDirectoryId, IMediaBrowsing mediaBrowsing, IImportResultHandler resultHandler) { ResourcePath directoryPath = directoryAccessor.CanonicalLocalResourcePath; MediaItem directoryItem = mediaBrowsing.LoadLocalItem(directoryPath, EMPTY_MIA_ID_ENUMERATION, DIRECTORY_MIA_ID_ENUMERATION); if (directoryItem != null) { MediaItemAspect da; if (!directoryItem.Aspects.TryGetValue(DirectoryAspect.ASPECT_ID, out da)) { // This is the case if the path was formerly imported as a non-directory media item; we cannot reuse it resultHandler.DeleteMediaItem(directoryPath); directoryItem = null; } } if (directoryItem == null) { // Add directory item to ML MediaItemAspect mia = new MediaItemAspect(MediaAspect.Metadata); mia.SetAttribute(MediaAspect.ATTR_TITLE, directoryAccessor.ResourceName); mia.SetAttribute(MediaAspect.ATTR_MIME_TYPE, null); 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 MediaItemAspect(DirectoryAspect.Metadata); IList<MediaItemAspect> aspects = new List<MediaItemAspect>(new[] { mia, da, }); return resultHandler.UpdateMediaItem(parentDirectoryId, directoryPath, aspects); } return directoryItem.MediaItemId; }
private void DoActivate(IMediaBrowsing mediaBrowsingCallback, IImportResultHandler importResultHandler) { if (_status != Status.Suspended) { ServiceRegistration.Get<ILogger>().Error("ImporterWorker: Activation was requested although status was not 'Suspended' but '{0}'", _status); return; } _mediaBrowsing = mediaBrowsingCallback; _importResultHandler = importResultHandler; foreach (var kvp in _importJobControllers) { // To avoid peaks on system startup when multiple ImportJobs were saved to disk and are now // reactivated, we start one ImportJob every 500ms. // Currently we also need this because the MediaAccessor is not threadsafe on startup // see here: http://forum.team-mediaportal.com/threads/mediaaccessor-not-thread-safe.125132/ // ToDo: Make MediaAccessor threadsafe on startup Task.Delay(500).Wait(); kvp.Value.Activate(_mediaBrowsing, _importResultHandler); } _status = Status.Activated; ServiceRegistration.Get<ILogger>().Info("ImporterWorker: Activated ({0} ImportJobs pending)", _importJobControllers.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(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; }
/// <summary> /// Activates the ImportJob /// </summary> /// <param name="mediaBrowsingCallback"></param> /// <param name="importResultHandler"></param> public void Activate(IMediaBrowsing mediaBrowsingCallback, IImportResultHandler importResultHandler) { // To avoid peaks on system startup we start one Block every 100ms. // Currently we also need this because the MediaAccessor is not threadsafe on startup // see here: http://forum.team-mediaportal.com/threads/mediaaccessor-not-thread-safe.125132/ // ToDo: Make MediaAccessor threadsafe on startup foreach (var block in _dataflowBlocks) { block.Activate(mediaBrowsingCallback, importResultHandler); Task.Delay(100).Wait(); } ServiceRegistration.Get<ILogger>().Info("ImporterWorker.{0}: Activated", this); ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportStarted, _importJobInformation.BasePath); }
/// <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; } }