/// <summary> /// Returns a resource accessor instance of interface <see cref="ILocalFsResourceAccessor"/>. This instance will return the /// given <paramref name="baseResourceAccessor"/>, casted to <see cref="ILocalFsResourceAccessor"/> if possible, or /// a new instance of <see cref="StreamedResourceToLocalFsAccessBridge"/> to provide the <see cref="ILocalFsResourceAccessor"/> /// instance. /// </summary> /// <remarks> /// The ownership of the given <paramref name="baseResourceAccessor"/> is transferred from the caller to the returned /// result value. That means, if this method succeeds, the caller must dispose the result value, it must not dispose /// the given <paramref name="baseResourceAccessor"/> any more. /// </remarks> /// <param name="baseResourceAccessor">Resource accessor which is used to provide the resource contents.</param> /// <param name="path">Relative path based on the given baseResourceAccessor.</param> /// <returns>Resource accessor which implements <see cref="ILocalFsResourceAccessor"/>.</returns> public static ILocalFsResourceAccessor GetLocalFsResourceAccessor(IResourceAccessor baseResourceAccessor, string path) { // Try to get an ILocalFsResourceAccessor ILocalFsResourceAccessor result = baseResourceAccessor as ILocalFsResourceAccessor; if (result != null) { // Simple case: The media item is located in the local file system or the resource provider returns // an ILocalFsResourceAccessor from elsewhere - simply return it return(result); } // Set up a resource bridge mapping the remote or complex resource to a local file or directory string key = baseResourceAccessor.CanonicalLocalResourcePath.Serialize(); MountingDataProxy md; bool dispose = false; lock (_syncObj) { if (_activeMounts.TryGetValue(key, out md)) { // Base accessor not needed - we use our cached accessor dispose = true; } else { _activeMounts.Add(key, md = CreateMountingDataProxy(key, baseResourceAccessor)); } } if (dispose) { baseResourceAccessor.Dispose(); } return(new StreamedResourceToLocalFsAccessBridge(md, path)); }
public void Dispose() { if (_accessor != null) { _accessor.Dispose(); } }
protected override void FreeData() { _texture = null; _stream.Close(); _resourceAccessor.Dispose(); base.FreeData(); }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { try { IResourceAccessor ra = mediaItemAccessor.Clone(); try { using (ILocalFsResourceAccessor fsra = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(ra)) if (fsra != null && fsra.IsDirectory && fsra.ResourceExists("BDMV")) { IFileSystemResourceAccessor fsraBDMV = fsra.GetResource("BDMV"); if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv")) { // This line is important to keep in, if no VideoAspect is created here, the MediaItems is not detected as Video! MediaItemAspect.GetOrCreateAspect(extractedAspectData, VideoAspect.Metadata); MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata); mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, "video/bluray"); // BluRay disc string bdmvDirectory = fsra.LocalFileSystemPath; BDInfoExt bdinfo = new BDInfoExt(bdmvDirectory); string title = bdinfo.GetTitle(); mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, title ?? mediaItemAccessor.ResourceName); // Check for BD disc thumbs FileInfo thumbnail = bdinfo.GetBiggestThumb(); if (thumbnail != null) { byte[] binary = new byte[thumbnail.Length]; using (FileStream fileStream = new FileStream(thumbnail.FullName, FileMode.Open, FileAccess.Read)) using (BinaryReader binaryReader = new BinaryReader(fileStream)) binaryReader.Read(binary, 0, binary.Length); MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, binary); } return(true); } } } catch { ra.Dispose(); throw; } return(false); } catch { // Only log at the info level here - And simply return false. This makes the importer know that we // couldn't perform our task here if (mediaItemAccessor != null) { ServiceRegistration.Get <ILogger>().Info("BluRayMetadataExtractor: Exception reading source '{0}'", mediaItemAccessor.ResourcePathName); } return(false); } }
public bool TryCreateLocalFsAccessor(out ILocalFsResourceAccessor localFsResourceAccessor) { IResourceAccessor accessor = CreateAccessor(); IFileSystemResourceAccessor fsra = accessor as IFileSystemResourceAccessor; if (fsra == null) { accessor.Dispose(); localFsResourceAccessor = null; return(false); } try { localFsResourceAccessor = StreamedResourceToLocalFsAccessBridge.StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(fsra); return(true); } catch { accessor.Dispose(); throw; } }
public IFileSystemResourceAccessor GetResource(string path) { IResourceAccessor ra = _mountingDataProxy.ResourceAccessor.Clone(); try { return(GetLocalFsResourceAccessor(ra, ProviderPathHelper.Combine(_path, path))); } catch { ra.Dispose(); throw; } }
public void Dispose() { if (_baseAccessor == null) { // Already disposed return; } if (!UnmountResource()) { // The ownership was transferred to the resource mounting service, so if unmounting was succesful, we must not dispose our base accessor _baseAccessor.Dispose(); } _baseAccessor = null; }
public ILocalFsResourceAccessor CreateLocalFsAccessor() { IResourceAccessor accessor = CreateAccessor(); try { return(StreamedResourceToLocalFsAccessBridge.StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(accessor)); } catch { accessor.Dispose(); throw; } }
/// <summary> /// This method handles two cases: /// <list type="bullet"> /// <item>No player available to play the resource</item> /// <item>The resouce to play is broken</item> /// </list> /// </summary> /// <param name="item"></param> /// <param name="exceptions"></param> protected void HandleUnableToPlay(MediaItem item, ICollection <Exception> exceptions) { INotificationService notificationService = ServiceRegistration.Get <INotificationService>(); // Start a heuristics to find a proper error message for the user IResourceLocator locator = item.GetResourceLocator(); if (locator == null) { ServiceRegistration.Get <ILogger>().Warn("PlayerSlotController: Could not play media item '{0}', resource locator could not be built", item); return; } if (exceptions.Count != 0) // This is the indicator that at least one player builder tried to open the resource but threw an exception { // 1) Check if resource is present IResourceAccessor ra = null; try { bool exists; try { ra = locator.CreateAccessor(); IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor; exists = fsra != null && fsra.Exists; } catch (Exception) { exists = false; } notificationService.EnqueueNotification( NotificationType.UserInteractionRequired, RES_ERROR_PLAYING_MEDIA_ITEM_TITLE, exists ? LocalizationHelper.Translate(RES_UNABLE_TO_PLAY_MEDIA_ITEM_TEXT, ra.ResourceName) : LocalizationHelper.Translate(RES_RESOURCE_NOT_FOUND_TEXT, locator.NativeResourcePath.FileName), true); } finally { if (ra != null) { ra.Dispose(); } } } else { using (IResourceAccessor ra = locator.CreateAccessor()) notificationService.EnqueueNotification(NotificationType.UserInteractionRequired, RES_NO_PLAYER_AVAILABLE_NOTIFICATION_TITLE, LocalizationHelper.Translate(RES_NO_PLAYER_AVAILABLE_NOTIFICATION_TEXT, ra.ResourceName), true); } }
public async Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode) { IResourceAccessor disposeAccessor = null; try { IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor; if (fsra == null) { return(false); } if (!fsra.IsFile) { if (!IsChainedResourceProvider(mediaItemAccessor)) { return(false); } // The importer mounts iso and zip files as virtual directories but we need the accessor // to the original file so we have to create one here and remember to dispose it later. ResourcePath path = new ResourcePath(new[] { mediaItemAccessor.CanonicalLocalResourcePath.BasePathSegment }); if (!path.TryCreateLocalResourceAccessor(out disposeAccessor)) { return(false); } } using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(disposeAccessor ?? mediaItemAccessor)) return(await ExtractGameData(rah.LocalFsResourceAccessor, extractedAspectData, forceQuickMode).ConfigureAwait(false)); } catch (Exception e) { // Only log at the info level here - And simply return false. This lets the caller know that we // couldn't perform our task here. Logger.Info("GamesMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message); } finally { if (disposeAccessor != null) { disposeAccessor.Dispose(); } } return(false); }
public virtual void Dispose() { foreach (FileHandle handle in _fileHandles) { handle.Cleanup(); } if (_resourceAccessor != null) { try { _resourceAccessor.Dispose(); } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("Dokan virtual filesystem resource: Error disposing resource accessor '{0}'", e, _resourceAccessor); } } _resourceAccessor = null; }
public void Dispose() { foreach (string tempFilePath in _tempFilePaths.Values) { try { File.Delete(tempFilePath); } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("ZipResourceProxy: Unable to delete temp file '{0}'", e, tempFilePath); } } _tempFilePaths.Clear(); CloseZipFile(); if (_zipFileResourceAccessor != null) { _zipFileResourceAccessor.Dispose(); _zipFileResourceAccessor = null; } }
public bool Init(MediaItem mediaItem) { // Prepare process information Prepare(mediaItem); IResourceAccessor ra = null; try { ra = mediaItem.GetResourceLocator().CreateAccessor(); RawUrlResourceAccessor rua = ra as RawUrlResourceAccessor; if (rua != null) { _fileOrUrl = rua.URL; } else { RawTokenResourceAccessor rra = ra as RawTokenResourceAccessor; if (rra == null) { return(false); } _fileOrUrl = rra.Token; } Play(); return(true); } catch (Exception) { // Log } finally { if (ra != null) { ra.Dispose(); } } return(false); }
public static ImageSource ResourceLocatorSource(object source, int width, int height) { IResourceLocator locator = source as IResourceLocator; if (locator == null) { return(null); } IResourceLocator resourceLocator = locator; IResourceAccessor ra = resourceLocator.CreateAccessor(); IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor; if (fsra == null) { ra.Dispose(); } else { return(new ResourceAccessorTextureImageSource(fsra, RightAngledRotation.Zero)); } return(null); }
public void Dispose() { if (_diskFileSystem != null) { IDisposable d = _diskFileSystem as IDisposable; if (d != null) { d.Dispose(); } _diskFileSystem = null; } if (_underlayingStream != null) { _underlayingStream.Dispose(); _underlayingStream = null; } if (_isoFileResourceAccessor != null) { _isoFileResourceAccessor.Dispose(); _isoFileResourceAccessor = null; } }
static void OnResourcePathObjectsPruned(ILRUCache <ResourcePath, IResourceAccessor> sender, ResourcePath key, IResourceAccessor value) { value.Dispose(); }
/// <summary> /// Loads an ImageSource and allows control of thumbnail use. /// Morpheus_xx, 2011-12-13: For fallback sources no thumbnails should be used, because ALL thumbs are created as JPG. This currenly causes an issue: /// Source -> no thumbnail created -> FallbackSource (PNG) -> creates a JPG thumbnail, so Alpha-Channel of FallbackSource is lost. /// TODO: Image class and thumbnail handling should be refactored to allow more control about image formats and thumbs usage. /// </summary> /// <param name="source">Source</param> /// <param name="allowThumbs">True to allow building a thumbnail of given source</param> /// <returns>ImageSource or null</returns> protected ImageSource LoadImageSource(object source, bool allowThumbs) { if (source == null) { return(null); } bool thumbnail = allowThumbs && Thumbnail; _invalidateImageSourceOnResize = false; if (source is MediaItem) { _invalidateImageSourceOnResize = true; return(MediaItemsHelper.CreateThumbnailImageSource((MediaItem)source, (int)Math.Max(Width, Height))); } if (source is IResourceLocator) { IResourceLocator resourceLocator = (IResourceLocator)source; IResourceAccessor ra = resourceLocator.CreateAccessor(); IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor; if (fsra == null) { ra.Dispose(); } else { return(new ResourceAccessorTextureImageSource(fsra, RightAngledRotation.Zero)); } } ImageSource result = source as ImageSource; if (result != null) { return(result); } string uriSource = source as string; if (!string.IsNullOrEmpty(uriSource)) { // Remember to adapt list of supported extensions for image player plugin... if (IsValidSource(uriSource)) { BitmapImageSource bmi = new BitmapImageSource { UriSource = uriSource, Thumbnail = thumbnail }; if (thumbnail) { // Set the requested thumbnail dimension, to use the best matching format. bmi.ThumbnailDimension = (int)Math.Max(Width, Height); } return(bmi); } // TODO: More image types } string warnSource = source.ToString(); if (_formerWarnURI != warnSource) { ServiceRegistration.Get <ILogger>().Warn("Image: Image source '{0}' is not supported", warnSource); // Remember if we already wrote a warning to the log to avoid log flooding _formerWarnURI = uriSource; } return(null); }
public void Dispose() { _resourceAccessor.Dispose(); _resourceAccessor = null; }
/// <summary> /// Returns all child directories of the given directory. /// </summary> /// <remarks> /// This will return all native child directories of the given directory together with all virtual child /// directories. The native child directories are taken directly from the given <paramref name="directoryAccessor"/>, /// the virtual child directories are obtained by taking the root directories of each chained resource provider applied /// to the child files of the given directory. /// If, for example, the given <paramref name="directoryAccessor"/> contains a child directory "A" and a child /// archive file "B" which can work as input for an installed archive provider, providing the root directory "C" /// of that archive, this method will return the resource accessors for directories "A" and "C". /// </remarks> /// <param name="directoryAccessor">Directory resource accessor to get all child directories for.</param> /// <param name="showSystemResources">If set to <c>true</c>, system resources like the virtual drives and directories of the /// <see cref="IResourceMountingService"/> will also be returned, else removed from the result value.</param> /// <returns>Collection of directory accessors for all native and virtual child directories or <c>null</c>, /// if the given <paramref name="directoryAccessor"/> is not a <see cref="IFileSystemResourceAccessor"/> and /// if there is no chained resource provider to unfold the given directory.</returns> public static ICollection <IFileSystemResourceAccessor> GetChildDirectories(IResourceAccessor directoryAccessor, bool showSystemResources) { IResourceMountingService resourceMountingService = ServiceRegistration.Get <IResourceMountingService>(); IResourceAccessor chainedResourceAccesor; // Needed in multiple source locations, that's why we declare it here if (directoryAccessor is IFileSystemResourceAccessor) { IFileSystemResourceAccessor dirFsra = (IFileSystemResourceAccessor)directoryAccessor; ICollection <IFileSystemResourceAccessor> childDirectories = dirFsra.GetChildDirectories(); ICollection <IFileSystemResourceAccessor> result = new List <IFileSystemResourceAccessor>(); if (childDirectories != null) { // Directories are maybe filtered and then just added foreach (IFileSystemResourceAccessor childDirectoryAccessor in childDirectories) { if (!showSystemResources && resourceMountingService.IsVirtualResource(childDirectoryAccessor.CanonicalLocalResourcePath)) { childDirectoryAccessor.Dispose(); continue; } result.Add(childDirectoryAccessor); } } ICollection <IFileSystemResourceAccessor> files = dirFsra.GetFiles(); if (files != null) { // For files, we try to chain up chained resource providers foreach (IFileSystemResourceAccessor fileAccessor in files) { if (!showSystemResources && resourceMountingService.IsVirtualResource(fileAccessor.CanonicalLocalResourcePath)) { fileAccessor.Dispose(); continue; } if (TryUnfold(fileAccessor, out chainedResourceAccesor)) { IFileSystemResourceAccessor chainedFsra = chainedResourceAccesor as IFileSystemResourceAccessor; if (chainedFsra != null) { result.Add(chainedFsra); } else { chainedResourceAccesor.Dispose(); } } else { fileAccessor.Dispose(); } } } return(result); } // Try to unfold simple resource IResourceAccessor dra = directoryAccessor.Clone(); try { if (TryUnfold(dra, out chainedResourceAccesor)) { IFileSystemResourceAccessor chainedFsra = chainedResourceAccesor as IFileSystemResourceAccessor; if (chainedFsra != null) { return(new List <IFileSystemResourceAccessor>(new IFileSystemResourceAccessor[] { chainedFsra })); } chainedResourceAccesor.Dispose(); } else { dra.Dispose(); } } catch { dra.Dispose(); throw; } return(null); }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { try { VideoResult result = null; IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor; if (fsra != null && fsra.IsDirectory && fsra.ResourceExists("VIDEO_TS")) { IFileSystemResourceAccessor fsraVideoTs = fsra.GetResource("VIDEO_TS"); if (fsraVideoTs != null && fsraVideoTs.ResourceExists("VIDEO_TS.IFO")) { // Video DVD using (MediaInfoWrapper videoTsInfo = ReadMediaInfo(fsraVideoTs.GetResource("VIDEO_TS.IFO"))) { if (!videoTsInfo.IsValid || videoTsInfo.GetVideoCount() == 0) { return(false); // Invalid video_ts.ifo file } result = VideoResult.CreateDVDInfo(fsra.ResourceName, videoTsInfo); } // Iterate over all video files; MediaInfo finds different audio/video metadata for each .ifo file ICollection <IFileSystemResourceAccessor> files = fsraVideoTs.GetFiles(); if (files != null) { foreach (IFileSystemResourceAccessor file in files) { string lowerPath = (file.ResourcePathName ?? string.Empty).ToLowerInvariant(); if (!lowerPath.EndsWith(".ifo") || lowerPath.EndsWith("video_ts.ifo")) { continue; } using (MediaInfoWrapper mediaInfo = ReadMediaInfo(file)) { // Before we start evaluating the file, check if it is a video at all if (mediaInfo.IsValid && mediaInfo.GetVideoCount() == 0) { continue; } result.AddMediaInfo(mediaInfo); } } } } } else if (mediaItemAccessor.IsFile) { string filePath = mediaItemAccessor.ResourcePathName; if (!HasVideoExtension(filePath)) { return(false); } using (MediaInfoWrapper fileInfo = ReadMediaInfo(mediaItemAccessor)) { // Before we start evaluating the file, check if it is a video at all if (!fileInfo.IsValid || (fileInfo.GetVideoCount() == 0 && !IsWorkaroundRequired(filePath))) { return(false); } string mediaTitle = DosPathHelper.GetFileNameWithoutExtension(mediaItemAccessor.ResourceName); result = VideoResult.CreateFileInfo(mediaTitle, fileInfo); } using (Stream stream = mediaItemAccessor.OpenRead()) result.MimeType = MimeTypeDetector.GetMimeType(stream); } if (result != null) { result.UpdateMetadata(extractedAspectData); ILocalFsResourceAccessor disposeLfsra = null; try { ILocalFsResourceAccessor lfsra = mediaItemAccessor as ILocalFsResourceAccessor; if (lfsra == null && !forceQuickMode) { // In case forceQuickMode, we only want local browsing IResourceAccessor ra = mediaItemAccessor.Clone(); try { lfsra = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(ra); disposeLfsra = lfsra; // Remember to dispose the extra resource accessor instance } catch (Exception) { ra.Dispose(); } } if (lfsra != null) { string localFsPath = lfsra.LocalFileSystemPath; ExtractMatroskaTags(localFsPath, extractedAspectData, forceQuickMode); ExtractThumbnailData(localFsPath, extractedAspectData, forceQuickMode); } } finally { if (disposeLfsra != null) { disposeLfsra.Dispose(); } } return(true); } } catch (Exception e) { // Only log at the info level here - And simply return false. This lets the caller know that we // couldn't perform our task here. ServiceRegistration.Get <ILogger>().Info("VideoMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message); } return(false); }
/// <summary> /// Returns a resource accessor instance of interface <see cref="ILocalFsResourceAccessor"/>. This instance will return the /// given <paramref name="baseResourceAccessor"/>, casted to <see cref="ILocalFsResourceAccessor"/> if possible, or /// a new instance of <see cref="StreamedResourceToLocalFsAccessBridge"/> to provide the <see cref="ILocalFsResourceAccessor"/> /// instance. /// </summary> /// <remarks> /// The ownership of the given <paramref name="baseResourceAccessor"/> is transferred from the caller to the returned /// result value. That means, if this method succeeds, the caller must dispose the result value, it must not dispose /// the given <paramref name="baseResourceAccessor"/> any more. /// </remarks> /// <param name="baseResourceAccessor">Resource accessor which is used to provide the resource contents.</param> /// <param name="path">Relative path based on the given baseResourceAccessor.</param> /// <returns>Resource accessor which implements <see cref="ILocalFsResourceAccessor"/>.</returns> public static ILocalFsResourceAccessor GetLocalFsResourceAccessor(IResourceAccessor baseResourceAccessor, string path) { // Try to get an ILocalFsResourceAccessor ILocalFsResourceAccessor result = baseResourceAccessor as ILocalFsResourceAccessor; if (result != null) // Simple case: The media item is located in the local file system or the resource provider returns // an ILocalFsResourceAccessor from elsewhere - simply return it return result; // Set up a resource bridge mapping the remote or complex resource to a local file or directory string key = baseResourceAccessor.CanonicalLocalResourcePath.Serialize(); MountingDataProxy md; bool dispose = false; lock (_syncObj) { if (_activeMounts.TryGetValue(key, out md)) // Base accessor not needed - we use our cached accessor dispose = true; else _activeMounts.Add(key, md = CreateMountingDataProxy(key, baseResourceAccessor)); } if (dispose) baseResourceAccessor.Dispose(); return new StreamedResourceToLocalFsAccessBridge(md, path); }
public async Task <MetadataContainer> ParseMediaItemAsync(MediaItem media, int?editionId = null, bool cache = true) { try { if (media.IsStub) { return(null); } string category = null; MetadataContainer info = null; //Check for live items if (media.Aspects.ContainsKey(AudioAspect.ASPECT_ID)) { category = AUDIO_CATEGORY; if (media.IsLiveRadioItem() && media is LiveTvMediaItem ltmi) { info = await ParseSlimTvItemAsync(ltmi).ConfigureAwait(false); if (info != null) { info.Metadata[Editions.DEFAULT_EDITION].Live = true; info.Metadata[Editions.DEFAULT_EDITION].Size = 0; } return(info); } } else if (media.Aspects.ContainsKey(VideoAspect.ASPECT_ID)) { category = VIDEO_CATEGORY; if (media.IsLiveTvItem() && media is LiveTvMediaItem ltmi) { info = await ParseSlimTvItemAsync(ltmi).ConfigureAwait(false); if (info != null) { info.Metadata[Editions.DEFAULT_EDITION].Live = true; info.Metadata[Editions.DEFAULT_EDITION].Size = 0; } return(info); } } else if (media.Aspects.ContainsKey(ImageAspect.ASPECT_ID)) { category = IMAGE_CATEGORY; } info = await LoadAnalysisAsync(media, category, media.MediaItemId); if (info != null) { return(info); } IList <MultipleMediaItemAspect> providerAspects; if (!MediaItemAspect.TryGetAspects(media.Aspects, ProviderResourceAspect.Metadata, out providerAspects)) { return(null); } IDictionary <int, ResourceLocator> resources = null; if (media.HasEditions) { IEnumerable <int> praIdxs = null; if (editionId.HasValue) { praIdxs = media.Editions.First(e => e.Key == editionId.Value).Value.PrimaryResourceIndexes; } else { praIdxs = media.Editions.SelectMany(e => e.Value.PrimaryResourceIndexes).Distinct(); } resources = providerAspects.Where(pra => praIdxs.Contains(pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX))). ToDictionary(pra => pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX), pra => new ResourceLocator(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_SYSTEM_ID), ResourcePath.Deserialize(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH)))); } else { resources = providerAspects.Where(pra => pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_PRIMARY). ToDictionary(pra => pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX), pra => new ResourceLocator(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_SYSTEM_ID), ResourcePath.Deserialize(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH)))); } //Process media resources Dictionary <int, Dictionary <int, IResourceAccessor> > editions = new Dictionary <int, Dictionary <int, IResourceAccessor> >(); foreach (var res in resources) { int edition = Editions.DEFAULT_EDITION; if (media.HasEditions) { edition = media.Editions.FirstOrDefault(e => e.Value.PrimaryResourceIndexes.Contains(res.Key)).Value.SetNo; } if (!editions.ContainsKey(edition)) { editions.Add(edition, new Dictionary <int, IResourceAccessor>()); } IResourceAccessor mia = res.Value.CreateAccessor(); if (mia is IFileSystemResourceAccessor fileRes && !fileRes.IsFile) { if (fileRes.ResourceExists("VIDEO_TS")) { using (IFileSystemResourceAccessor fsraVideoTs = fileRes.GetResource("VIDEO_TS")) { if (fsraVideoTs != null && fsraVideoTs.ResourceExists("VIDEO_TS.IFO")) { //Find all titles and add each of them var titles = GetDvdTitleFiles(fsraVideoTs); foreach (var title in titles) { int fileNo = 0; foreach (var file in title.Value) { fileNo++; int titleKey = MetadataContainer.GetDvdResource(res.Key, title.Key, fileNo); editions[edition].Add(titleKey, file); } } } } } else if (fileRes.ResourceExists("BDMV")) { using (IFileSystemResourceAccessor fsraBDMV = fileRes.GetResource("BDMV")) { if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv") && fsraBDMV.ResourceExists("STREAM")) { using (IFileSystemResourceAccessor fsraStream = fsraBDMV.GetResource("STREAM")) { var orderedFileList = fsraStream.GetFiles().Where(f => f.ResourceName.EndsWith(".m2ts", StringComparison.InvariantCultureIgnoreCase)).OrderByDescending(f => f.Size); //Use the largest file which is probably the main stream var mainStream = orderedFileList.First(); editions[edition].Add(res.Key, mainStream); } } } } } else { editions[edition].Add(res.Key, mia); } mia.Dispose(); }
/// <summary> /// Creates a local resource provider chain for this resource path, if it is a local path /// (see <see cref="CheckValidLocalPath"/>), and returns its result in a <see cref="IResourceAccessor"/> instance. /// </summary> /// <param name="result">Returns the resource accessor to access the resource represented by this path, if the /// return value is <c>true</c>. Else, this parameter doesn't return a meaningful value.</param> /// <returns><c>true</c>, if a resource accessor could successfully be built for this path.</returns> /// <exception cref="IllegalCallException">If one of the referenced resource providers is not available in the system or /// has the wrong type.</exception> /// <exception cref="UnexpectedStateException">If this path is empty.</exception> public bool TryCreateLocalResourceAccessor(out IResourceAccessor result) { IResourceAccessor resourceAccessor = null; if (USE_RA_CACHE) { if (TryGetCloneFromCache(this, out resourceAccessor)) { result = resourceAccessor; return(true); } } IMediaAccessor mediaAccessor = ServiceRegistration.Get <IMediaAccessor>(); IEnumerator <ProviderPathSegment> enumer = _pathSegments.GetEnumerator(); if (!enumer.MoveNext()) { throw new UnexpectedStateException("Cannot build resource accessor for an empty resource path"); } try { do { ProviderPathSegment pathSegment = enumer.Current; IResourceProvider resourceProvider; if (!mediaAccessor.LocalResourceProviders.TryGetValue(pathSegment.ProviderId, out resourceProvider)) { throw new IllegalCallException("The resource provider with id '{0}' is not accessible in the current system", pathSegment.ProviderId); } if (resourceAccessor == null) { IBaseResourceProvider baseProvider = resourceProvider as IBaseResourceProvider; if (baseProvider == null) { throw new IllegalCallException("The resource provider with id '{0}' does not implement the {1} interface", pathSegment.ProviderId, typeof(IBaseResourceProvider).Name); } if (!baseProvider.TryCreateResourceAccessor(pathSegment.Path, out resourceAccessor)) { result = null; return(false); } } else { IChainedResourceProvider chainedProvider = resourceProvider as IChainedResourceProvider; if (chainedProvider == null) { throw new IllegalCallException("The resource provider with id '{0}' does not implement the {1} interface", pathSegment.ProviderId, typeof(IChainedResourceProvider).Name); } IResourceAccessor chainedRa; if (!chainedProvider.TryChainUp(resourceAccessor, pathSegment.Path, out chainedRa)) { resourceAccessor.Dispose(); result = null; return(false); } resourceAccessor = chainedRa; } } while (enumer.MoveNext()); } catch (Exception) { if (resourceAccessor != null) { resourceAccessor.Dispose(); } throw; } if (USE_RA_CACHE) { AddToCache(this, resourceAccessor); } result = resourceAccessor; return(true); }
/// <summary> /// Instantiates all the necessary DataflowBlocks for the given ImportJob /// </summary> /// <remarks> /// We first have to distinguish between two cases here: /// - BasePath points to a resource for which we can only create an IResourceAccessor - not an IFilesystemResourceAccessor /// For this case we only import that single resource and don't have to take care of directories and subdirectories /// ToDo: This still needs to be implemented /// - BasePath points to a resource for which we can create an IFilesystemResourceAccessor /// Here we first check whether the resource on the given BasePath exists. If not, we do nothing. /// If it does exist, we distinguish two cases: /// - The ImportJob was restored from disk, in which case we push the existing PendingImportResources to the respective DataflowBlocks. /// - The ImportJob was freshly created, in which case we push the BasePath to the first DataFlowBlock. /// In this case there are three subcases: /// - BasePath points to a single resource /// - BasePath points to a directory which is not a single resource and the ImportJob does not include subdirectories /// - BasePath points to a directory which is not a single resource and the ImportJob does include subdirectories /// These subcases, however, are taken care of by the DataflowBlocks - not by the ImportJobController /// </remarks> private void SetupDataflowBlocks(IEnumerable <PendingImportResourceNewGen> pendingImportResources) { // If we cannot access the BasePath at all, we just log and return IResourceAccessor ra = null; try { if (!_importJobInformation.BasePath.TryCreateLocalResourceAccessor(out ra)) { ServiceRegistration.Get <ILogger>().Warn("ImporterWorker.{0}: Unable to access resource path '{1}'.", this, _importJobInformation.BasePath); return; } } catch (Exception e) { ServiceRegistration.Get <ILogger>().Error("ImporterWorker.{0}: Error while creating ResourceAccessor for resource path '{1}'.", e, this, _importJobInformation.BasePath); if (ra != null) { ra.Dispose(); } return; } try { // As of now we have a ResourceAccessor that needs to be disposed using (ra) { // If we have a ResourceAccessor which is not an IFileSystemResourceAccessor, just import that single resource if (!(ra is IFileSystemResourceAccessor)) { // ToDo: Implement import of Non-IFilesSystemResourceAccessors return; } // Now we are sure it is an IFileSystemResourceAccessor var fsra = ra as IFileSystemResourceAccessor; // If the BasePath does not exist, we do nothing. This is necessary to avoid whole shares being removed from // the MediaLibrary when a RefreshImport is scheduled while e.g. network resources are unavailable. // If fsra is a NetworkNeighborhoddResourceAccessor and its IsServerPath() method returns true, fsra.Exists() // will always return true. If therefore the BasePath of this Import points to a whole server and this server // is not available during a RefreshImport, the whole share will be deleted from the MediaLibrary. // ToDo: Rework this in NetworkNeighborhoodResourceAccessor if (!fsra.Exists) { ServiceRegistration.Get <ILogger>().Warn("ImporterWorker.{0}: Resource '{1}' does not exists or is not available.", this, _importJobInformation.BasePath); return; } // Now we are sure that we need a DataflowBlock network // Create the blocks _dataflowBlocks.Add(new DirectoryUnfoldBlock(_cts.Token, _importJobInformation, this)); _dataflowBlocks.Add(new DirectorySaveBlock(_cts.Token, _importJobInformation, this)); _dataflowBlocks.Add(new FileUnfoldBlock(_cts.Token, _importJobInformation, this)); _dataflowBlocks.Add(new MetadataExtractorBlock(_cts.Token, _importJobInformation, this, false)); _dataflowBlocks.Add(new MediaItemSaveBlock(_cts.Token, _importJobInformation, this)); // Link the blocks for (int i = 0; i < _dataflowBlocks.Count - 1; i++) { _dataflowBlocks[i].LinkTo(_dataflowBlocks[i + 1], new DataflowLinkOptions { PropagateCompletion = true }); } _dataflowBlocks[_dataflowBlocks.Count - 1].LinkTo(DataflowBlock.NullTarget <PendingImportResourceNewGen>()); // Fill the blocks var completeFirstBlockAfterTheseTasks = new HashSet <Task>(); bool firstBlockNeedsCompletion = true; if (pendingImportResources == null) { // This ImportJob was freshly created and not persisted to disk before // Just post the BasePath as new PendingImportResource var rootImportResource = new PendingImportResourceNewGen(null, fsra.Clone() as IFileSystemResourceAccessor, DirectoryUnfoldBlock.BLOCK_NAME, this); _dataflowBlocks[0].Post(rootImportResource); firstBlockNeedsCompletion = false; } else { // This ImportJob was persisted to disk before int numberOfRestoredPendingResources = 0; foreach (var pendingImportResource in pendingImportResources) { pendingImportResource.InitializeAfterDeserialization(this); ImporterWorkerDataflowBlockBase block = _dataflowBlocks.Find(b => b.ToString() == pendingImportResource.CurrentBlock); if (block != null) { completeFirstBlockAfterTheseTasks.Add(block.SendAsync(pendingImportResource, _cts.Token)); numberOfRestoredPendingResources++; if (block == _dataflowBlocks[0]) { firstBlockNeedsCompletion = false; } } else { ServiceRegistration.Get <ILogger>().Error("ImporterWorker.{0}: Could not add {1} after deserialization. DataflowBlock with name {2} does not exist.", this, pendingImportResource, pendingImportResource.CurrentBlock); pendingImportResource.Dispose(); } } ServiceRegistration.Get <ILogger>().Debug("ImporterWorker.{0}: {1} PendingImportResources restored.", this, numberOfRestoredPendingResources); } completeFirstBlockAfterTheseTasks.Add(_firstBlockHasFinished.Task); if (firstBlockNeedsCompletion) { FirstBlockHasFinished(); } // The first DataflowBlock in the network (DirectoryUnfoldBlock) must be set to completed when // (a) The DirectoryUnfoldBlock has signaled that it is finished (by calling FirstBlockHasFinished()) and // (b) in case of an ImportJob that has been restored from disk, all restored PendingImportResources // have been put into the Dataflow network Task.WhenAll(completeFirstBlockAfterTheseTasks).ContinueWith(previousTask => _dataflowBlocks[0].Complete()); } } catch (Exception e) { ServiceRegistration.Get <ILogger>().Error("ImporterWorker.{0}: Error while setting up DataflowBlocks for resource path '{1}.", e, this, _importJobInformation.BasePath); } }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { string fileName = mediaItemAccessor.ResourceName; if (!HasImageExtension(fileName)) { return(false); } MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata); MediaItemAspect imageAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ImageAspect.Metadata); MediaItemAspect thumbnailSmallAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ThumbnailSmallAspect.Metadata); MediaItemAspect thumbnailLargeAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ThumbnailLargeAspect.Metadata); try { // Open a stream for media item to detect mimeType. using (Stream mediaStream = mediaItemAccessor.OpenRead()) { string mimeType = MimeTypeDetector.GetMimeType(mediaStream); if (mimeType != null) { mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, mimeType); } } // Extract EXIF information from media item. using (ExifMetaInfo.ExifMetaInfo exif = new ExifMetaInfo.ExifMetaInfo(mediaItemAccessor)) { mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, ProviderPathHelper.GetFileNameWithoutExtension(fileName)); mediaAspect.SetAttribute(MediaAspect.ATTR_RECORDINGTIME, exif.OriginalDate != DateTime.MinValue ? exif.OriginalDate : mediaItemAccessor.LastChanged); mediaAspect.SetAttribute(MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(exif.ImageDescription)); imageAspect.SetAttribute(ImageAspect.ATTR_WIDTH, (int)exif.PixXDim); imageAspect.SetAttribute(ImageAspect.ATTR_HEIGHT, (int)exif.PixYDim); imageAspect.SetAttribute(ImageAspect.ATTR_MAKE, StringUtils.TrimToNull(exif.EquipMake)); imageAspect.SetAttribute(ImageAspect.ATTR_MODEL, StringUtils.TrimToNull(exif.EquipModel)); imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_BIAS, ((double)exif.ExposureBias).ToString()); imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_TIME, exif.ExposureTime.ToString()); imageAspect.SetAttribute(ImageAspect.ATTR_FLASH_MODE, StringUtils.TrimToNull(exif.FlashMode)); imageAspect.SetAttribute(ImageAspect.ATTR_FNUMBER, string.Format("F {0}", (double)exif.FNumber)); imageAspect.SetAttribute(ImageAspect.ATTR_ISO_SPEED, StringUtils.TrimToNull(exif.ISOSpeed)); imageAspect.SetAttribute(ImageAspect.ATTR_ORIENTATION, (Int32)exif.Orientation); imageAspect.SetAttribute(ImageAspect.ATTR_METERING_MODE, exif.MeteringMode.ToString()); IResourceAccessor ra = mediaItemAccessor.Clone(); ILocalFsResourceAccessor lfsra; try { lfsra = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(ra); } catch { ra.Dispose(); throw; } using (lfsra) { string localFsResourcePath = lfsra.LocalFileSystemPath; if (localFsResourcePath != null) { // In quick mode only allow thumbs taken from cache. bool cachedOnly = forceQuickMode; // Thumbnail extraction IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>(); byte[] thumbData; ImageType imageType; if (generator.GetThumbnail(localFsResourcePath, 96, 96, cachedOnly, out thumbData, out imageType)) { thumbnailSmallAspect.SetAttribute(ThumbnailSmallAspect.ATTR_THUMBNAIL, thumbData); } if (generator.GetThumbnail(localFsResourcePath, 256, 256, cachedOnly, out thumbData, out imageType)) { thumbnailLargeAspect.SetAttribute(ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData); } } } } return(true); } catch (Exception e) { // Only log at the info level here - And simply return false. This makes the importer know that we // couldn't perform our task here. ServiceRegistration.Get <ILogger>().Info("ImageMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message); } return(false); }