/// <summary> /// Creates and initializes an new instance. /// </summary> /// <param name="resourceAccessor">The resource accessor to the media item to be handled by the instance.</param> /// <returns>The new instance.</returns> public static BassMODFileInputSource Create(IFileSystemResourceAccessor resourceAccessor) { resourceAccessor.PrepareStreamAccess(); BassMODFileInputSource inputSource = new BassMODFileInputSource(resourceAccessor); inputSource.Initialize(); return inputSource; }
/// <summary> /// Creates a new instance of this class which is based on the given <paramref name="baseAccessor"/>. /// </summary> /// <param name="key">Key which is used for this instance.</param> /// <param name="baseAccessor">Filesystem resource to mound.</param> public MountingDataProxy(string key, IFileSystemResourceAccessor baseAccessor) { _key = key; _baseAccessor = baseAccessor; if (!MountResource()) throw new EnvironmentException("Cannot mount resource '{0}' to local file system", baseAccessor); }
/// <summary> /// Constructs a <see cref="ResourceAccessorTextureImageSource"/> for the given data. /// </summary> /// <param name="resourceAccessor">The resource accessor to load the texture data from.</param> /// <param name="rotation">Desired rotation for the given image.</param> public ResourceAccessorTextureImageSource(IFileSystemResourceAccessor resourceAccessor, RightAngledRotation rotation) { _key = resourceAccessor.CanonicalLocalResourcePath.Serialize(); _resourceAccessor = resourceAccessor; _stream = _resourceAccessor.OpenRead(); _rotation = rotation; }
/// <summary> /// Tries to read a valid IMDB id from additional .nfo or .txt files. /// </summary> /// <param name="fsra">FileSystemResourceAccessor</param> /// <param name="imdbId">Returns a valid IMDB or <c>null</c></param> /// <returns>true if matched</returns> public static bool TryMatchImdbId(IFileSystemResourceAccessor fsra, out string imdbId) { imdbId = null; if (fsra == null) return false; // First try to find a nfo file that has the same name as our main movie. if (fsra.IsFile) foreach (string extension in NFO_EXTENSIONS) { string metaFilePath = ResourcePathHelper.ChangeExtension(fsra.CanonicalLocalResourcePath.ToString(), extension); if (TryRead(metaFilePath, out imdbId)) return true; } // Prepare a list of paths to check: for chained resource path we will also check relative parent paths (like for DVD-ISO files) List<string> pathsToCheck = new List<string> { fsra.CanonicalLocalResourcePath.ToString() }; if (fsra.CanonicalLocalResourcePath.PathSegments.Count > 1) { string canocialPath = fsra.CanonicalLocalResourcePath.ToString(); pathsToCheck.Add(canocialPath.Substring(0, canocialPath.LastIndexOf('>'))); } // Then test for special named files, like "movie.nfo" foreach (string path in pathsToCheck) foreach (string fileName in NFO_FILENAMES) { string metaFilePath = ResourcePathHelper.GetDirectoryName(path); metaFilePath = ResourcePathHelper.Combine(metaFilePath, fileName); if (TryRead(metaFilePath, out imdbId)) return true; } // Now check siblings of movie for any IMDB id containing filename. // Morpheus_xx, 2014-01-04: disabled code because it leads to false detections if there are multiple video files in same folder. In this case the first // video with TT-number is wrongly used. // TODO: this part could be reworked based on different ideas: // - Exclude known video extensions from file name matching (this would require a reference to VideoMDE's settings for extension list) // - Only use folder lookup for chained resources, i.e. for a DVD-ISO, where any "TT000000.bla" is located next to it //IFileSystemResourceAccessor directoryFsra = null; //if (!fsra.IsFile) // directoryFsra = fsra.Clone() as IFileSystemResourceAccessor; //if (fsra.IsFile) // directoryFsra = GetContainingDirectory(fsra); //if (directoryFsra == null) // return false; //using (directoryFsra) // foreach (IFileSystemResourceAccessor file in directoryFsra.GetFiles()) // using (file) // if (ImdbIdMatcher.TryMatchImdbId(file.ResourceName, out imdbId)) // return true; return false; }
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; }
/// <summary> /// Tries to read a valid IMDB id from additional .nfo or .txt files. /// </summary> /// <param name="fsra">FileSystemResourceAccessor</param> /// <param name="imdbId">Returns a valid IMDB or <c>null</c></param> /// <returns>true if matched</returns> public static bool TryMatchImdbId(IFileSystemResourceAccessor fsra, out string imdbId) { imdbId = null; if (fsra == null) return false; // First try to find a nfo file that has the same name as our main movie. if (fsra.IsFile) foreach (string extension in NFO_EXTENSIONS) { string metaFilePath = ResourcePathHelper.ChangeExtension(fsra.CanonicalLocalResourcePath.ToString(), extension); if (TryRead(metaFilePath, out imdbId)) return true; } // Prepare a list of paths to check: for chained resource path we will also check relative parent paths (like for DVD-ISO files) List<string> pathsToCheck = new List<string> { fsra.CanonicalLocalResourcePath.ToString() }; if (fsra.CanonicalLocalResourcePath.PathSegments.Count > 1) { string canocialPath = fsra.CanonicalLocalResourcePath.ToString(); pathsToCheck.Add(canocialPath.Substring(0, canocialPath.LastIndexOf('>'))); } // Then test for special named files, like "movie.nfo" foreach (string path in pathsToCheck) foreach (string fileName in NFO_FILENAMES) { string metaFilePath = ResourcePathHelper.GetDirectoryName(path); metaFilePath = ResourcePathHelper.Combine(metaFilePath, fileName); if (TryRead(metaFilePath, out imdbId)) return true; } // Now check siblings of movie for any IMDB id containing filename. IFileSystemResourceAccessor directoryFsra = null; if (!fsra.IsFile) directoryFsra = fsra.Clone() as IFileSystemResourceAccessor; if (fsra.IsFile) directoryFsra = GetContainingDirectory(fsra); if (directoryFsra == null) return false; using (directoryFsra) foreach (IFileSystemResourceAccessor file in directoryFsra.GetFiles()) using (file) if (ImdbIdMatcher.TryMatchImdbId(file.ResourceName, out imdbId)) return true; return false; }
/// <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"/> does not point to a directory and /// if there is no chained resource provider to unfold the given file.</returns> public static ICollection<IFileSystemResourceAccessor> GetChildDirectories(IFileSystemResourceAccessor directoryAccessor, bool showSystemResources) { IResourceMountingService resourceMountingService = ServiceRegistration.Get<IResourceMountingService>(); IFileSystemResourceAccessor chainedResourceAccesor; // Needed in multiple source locations, that's why we declare it here // If directoryAccessor points to a directory, we return all actual subdirectories and the virtual subdirectories // we can create by using all available ChainedResourceProviders on all contained files. if (!directoryAccessor.IsFile) { ICollection<IFileSystemResourceAccessor> childDirectories = directoryAccessor.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 = directoryAccessor.GetFiles(); if (files != null) // For files, we try to chain up chained resource providers foreach (IFileSystemResourceAccessor fileAccessor in files) using (fileAccessor) { if (!showSystemResources && resourceMountingService.IsVirtualResource(fileAccessor.CanonicalLocalResourcePath)) continue; if (TryUnfold(fileAccessor, out chainedResourceAccesor)) if (!chainedResourceAccesor.IsFile) result.Add(chainedResourceAccesor); else chainedResourceAccesor.Dispose(); // Simply ignore files because we only want to return directories } return result; } // Try to unfold file resource if (TryUnfold(directoryAccessor, out chainedResourceAccesor)) { if (!chainedResourceAccesor.IsFile) return new List<IFileSystemResourceAccessor>(new IFileSystemResourceAccessor[] {chainedResourceAccesor}); chainedResourceAccesor.Dispose(); return new List<IFileSystemResourceAccessor>(); } return null; }
private DateTime _dateOfLastImport; // only valid for refresh imports #endregion #region Constructor public PendingImportResourceNewGen(ResourcePath parentDirectory, IFileSystemResourceAccessor resourceAccessor, String currentBlock, ImportJobController parentImportJobController, Guid? parentDirectoryId = null, Guid? mediaItemId = null) { _parentDirectoryId = parentDirectoryId; _mediaItemId = mediaItemId; _parentDirectoryResourcePathString = (parentDirectory == null) ? "" : parentDirectory.Serialize(); _resourceAccessor = resourceAccessor; _currentBlock = currentBlock; _parentImportJobController = parentImportJobController; _pendingImportResourceNumber = _parentImportJobController.GetNumberOfNextPendingImportResource(); _isValid = (_resourceAccessor != null); _parentImportJobController.RegisterPendingImportResource(this); }
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 ZipResourceProxy(string key, IFileSystemResourceAccessor zipFileAccessor) { _key = key; _zipFileResourceAccessor = zipFileAccessor; _zipFileStream = _zipFileResourceAccessor.OpenRead(); // Not sure if the ZipFile closes the stream appropriately, so we keep a reference to it try { _zipFile = new ZipFile(_zipFileStream); } catch { _zipFileStream.Dispose(); throw; } }
public IsoResourceProxy(string key, IFileSystemResourceAccessor isoFileResourceAccessor) { _key = key; _isoFileResourceAccessor = isoFileResourceAccessor; _underlayingStream = _isoFileResourceAccessor.OpenRead(); try { _diskFileSystem = GetFileSystem(_underlayingStream); } catch { _underlayingStream.Dispose(); throw; } }
public static bool ConnectFileSystem(string nativeSystemId, ResourcePath nativeResourcePath, out IFileSystemResourceAccessor result) { IRemoteResourceInformationService rris = ServiceRegistration.Get<IRemoteResourceInformationService>(); result = null; bool isFileSystemResource; bool isFile; string resourcePathName; string resourceName; long size; DateTime lastChanged; if (!rris.GetResourceInformation(nativeSystemId, nativeResourcePath, out isFileSystemResource, out isFile, out resourcePathName, out resourceName, out lastChanged, out size) || !isFileSystemResource) return false; result = new RemoteFileSystemResourceAccessor(nativeSystemId, nativeResourcePath, isFile, resourcePathName, resourceName, size, lastChanged); return true; }
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; } }
/// <summary> /// Main process method for the InnerBlock /// </summary> /// <remarks> /// - SingleResources are just passed to the next DataflowBlock /// - If it's not a SingleResource /// - it finds all the files in the current directory, /// - in case of a RefreshImport /// - it deletes all the files in the MediaLibrary that do not exist anymore in the filesystem, /// - it stores the DateOfLastImport of all the files in the <see cref="PendingImportResourceNewGen"/> /// </remarks> /// <param name="importResource"><see cref="PendingImportResourceNewGen"/> to be processed</param> /// <returns> /// a HashSet of <see cref="PendingImportResourceNewGen"/>s containing the current <see cref="PendingImportResource"/> /// after processing as well as <see cref="PendingImportResourceNewGen"/>s for all files in the current directory /// </returns> private async Task <IEnumerable <PendingImportResourceNewGen> > ProcessDirectory(PendingImportResourceNewGen importResource) { var result = new HashSet <PendingImportResourceNewGen> { importResource }; try { ICollection <IFileSystemResourceAccessor> files; ICollection <IFileSystemResourceAccessor> stubFiles = new HashSet <IFileSystemResourceAccessor>(); IDictionary <ResourcePath, DateTime> path2LastImportDate = new Dictionary <ResourcePath, DateTime>(); IDictionary <ResourcePath, Guid> path2MediaItem = new Dictionary <ResourcePath, Guid>(); IEnumerable <MediaItem> mediaItems = null; if (importResource.IsSingleResource) { files = new HashSet <IFileSystemResourceAccessor> { importResource.ResourceAccessor }; MediaItem mi = await LoadLocalItem(importResource.PendingResourcePath, PROVIDERRESOURCE_IMPORTER_MIA_ID_ENUMERATION, null).ConfigureAwait(false); if (mi != null) { mediaItems = new List <MediaItem>(new MediaItem[] { mi }); importResource.MediaItemId = mi.MediaItemId; } } else { files = FileSystemResourceNavigator.GetFiles(importResource.ResourceAccessor, false, false) ?? new HashSet <IFileSystemResourceAccessor>(); SingleMediaItemAspect directoryAspect; // ReSharper disable once PossibleInvalidOperationException // TODO: Rework this mediaItems = (await Browse(importResource.MediaItemId.Value, PROVIDERRESOURCE_IMPORTER_MIA_ID_ENUMERATION, DIRECTORY_MIA_ID_ENUMERATION).ConfigureAwait(false)) .Where(mi => !MediaItemAspect.TryGetAspect(mi.Aspects, DirectoryAspect.Metadata, out directoryAspect)); } if (mediaItems != null) { foreach (MediaItem mi in mediaItems) { //Check metadata and files: // 1. Last import date is lower than file change date => Refresh needed // 2. Media item ID is empty => Reimport/import needed // 3. Media item is dirty => Reimport/import needed IList <MultipleMediaItemAspect> providerAspects = null; if (MediaItemAspect.TryGetAspects(mi.Aspects, ProviderResourceAspect.Metadata, out providerAspects)) { foreach (var pra in providerAspects) { bool isStub = pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_STUB; ResourcePath path = ResourcePath.Deserialize(pra.GetAttributeValue <String>(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH)); if (!path2LastImportDate.ContainsKey(path) && importResource.PendingResourcePath.IsSameOrParentOf(path)) { //If last refresh is equal to added date, it has never been through the refresh cycle, so set low last change date //All media items must be added because the paths are later used to delete no longer existing media items var lastImportDate = mi.Aspects[ImporterAspect.ASPECT_ID][0].GetAttributeValue <DateTime>(ImporterAspect.ATTR_LAST_IMPORT_DATE); if (mi.Aspects[ImporterAspect.ASPECT_ID][0].GetAttributeValue <bool>(ImporterAspect.ATTR_DIRTY)) //If it is dirty, refresh is needed { path2LastImportDate.Add(path, DateTime.MinValue); } else { path2LastImportDate.Add(path, lastImportDate); } } if (!importResource.IsSingleResource && !isStub && !path2MediaItem.ContainsKey(path)) { path2MediaItem.Add(path, mi.MediaItemId); } // Stub items need their media item id because the do no have a unique path // So add them now as long as the needed info is known if (isStub) { IFileSystemResourceAccessor file = null; try { IResourceAccessor ra; if (path.TryCreateLocalResourceAccessor(out ra)) { file = ra as IFileSystemResourceAccessor; } } catch { } // Only add it if it still exists if (files.Where(f => file != null && f.CanonicalLocalResourcePath == file.CanonicalLocalResourcePath).Any()) { stubFiles.Add(file); DateTime dateTime; PendingImportResourceNewGen pir = new PendingImportResourceNewGen(importResource.ResourceAccessor.CanonicalLocalResourcePath, file, ToString(), ParentImportJobController, importResource.MediaItemId, mi.MediaItemId, true); pir.ExistingAspects = mi.Aspects; if (ImportJobInformation.JobType == ImportJobType.Refresh) { if (path2LastImportDate.TryGetValue(pir.PendingResourcePath, out dateTime)) { pir.DateOfLastImport = dateTime; } } result.Add(pir); } } } } } await DeleteNoLongerExistingFilesFromMediaLibrary(files, path2LastImportDate.Keys).ConfigureAwait(false); } //Add new stub items foreach (var file in files.Where(f => !path2LastImportDate.Keys.Contains(f.CanonicalLocalResourcePath))) { if (await IsStubResource(file).ConfigureAwait(false)) { stubFiles.Add(file); DateTime dateTime; var stubAspects = await ExtractStubItems(file).ConfigureAwait(false); if (stubAspects != null) { foreach (var aspects in stubAspects) { PendingImportResourceNewGen pir = new PendingImportResourceNewGen(importResource.ResourceAccessor.CanonicalLocalResourcePath, file, ToString(), ParentImportJobController, importResource.MediaItemId, null, true); pir.ExistingAspects = aspects; if (ImportJobInformation.JobType == ImportJobType.Refresh) { if (path2LastImportDate.TryGetValue(pir.PendingResourcePath, out dateTime)) { pir.DateOfLastImport = dateTime; } } result.Add(pir); } } } } //Remove stub files from files collection so they don't get added again foreach (IFileSystemResourceAccessor file in stubFiles) { IFileSystemResourceAccessor stub = files.Where(f => f.CanonicalLocalResourcePath == file.CanonicalLocalResourcePath).FirstOrDefault(); if (stub != null) { files.Remove(stub); } } //Add importers for files if any if (!importResource.IsSingleResource) { if (ImportJobInformation.JobType == ImportJobType.Import) { //Only import new files so only add non existing paths result.UnionWith(files.Where(f => !path2LastImportDate.Keys.Contains(f.CanonicalLocalResourcePath)). Select(f => new PendingImportResourceNewGen(importResource.ResourceAccessor.CanonicalLocalResourcePath, f, ToString(), ParentImportJobController, importResource.MediaItemId))); } else { result.UnionWith(files.Select(f => new PendingImportResourceNewGen(importResource.ResourceAccessor.CanonicalLocalResourcePath, f, ToString(), ParentImportJobController, importResource.MediaItemId, path2MediaItem.ContainsKey(f.CanonicalLocalResourcePath) ? path2MediaItem[f.CanonicalLocalResourcePath] : (Guid?)null))); } // We set the directory resource as invalid because directories have no need for further processing importResource.IsValid = false; } // If this is a RefreshImport and we found files of the current directory in the MediaLibrary, // store the DateOfLastImport in the PendingImportResource if (ImportJobInformation.JobType == ImportJobType.Refresh) { DateTime dateTime; if (path2LastImportDate != null) { foreach (var pir in result) { if (path2LastImportDate.TryGetValue(pir.PendingResourcePath, out dateTime)) { pir.DateOfLastImport = dateTime; } } } } return(result); } catch (TaskCanceledException) { return(result); } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Warn("ImporterWorker.{0}.{1}: Error while processing {2}", ex, ParentImportJobController, ToString(), importResource); importResource.IsValid = false; return(result); } }
/// <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); } IFileSystemResourceAccessor fsra = resourceAccessor as IFileSystemResourceAccessor; if (fsra == null) { throw new IllegalCallException("Cannot chain up a resource provider to resource of type {0} (Path: '{1}')", resourceAccessor.GetType(), ToString()); } IFileSystemResourceAccessor chainedRa; if (!chainedProvider.TryChainUp(fsra, 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); }
public void Dispose() { _resourceAccessor.Dispose(); _resourceAccessor = null; }
/// <summary> /// Tries to find a nfo-file for the given <param name="mediaFsra"></param> /// </summary> /// <param name="miNumber">Unique number for logging purposes</param> /// <param name="mediaFsra">FileSystemResourceAccessor for which we search a nfo-file</param> /// <param name="nfoFsra">FileSystemResourceAccessor of the nfo-file or <c>null</c> if no nfo-file was found</param> /// <returns><c>true</c> if a nfo-file was found, otherwise <c>false</c></returns> private bool TryGetNfoSResourceAccessor(long miNumber, IFileSystemResourceAccessor mediaFsra, out IFileSystemResourceAccessor nfoFsra) { nfoFsra = null; // Determine the directory, in which we look for the nfo-file // We cannot use mediaFsra.GetResource, because for ChainedResourceProviders the parent directory // may be located in the ParentResourceProvider. For details see the comments for the ResourcePathHelper class. // First get the ResourcePath of the parent directory // The parent directory is // - for an IFilesystemResourceAcessor pointing to a file: // the directory in which the file is located; // - for an IFilesystemResourceAcessor pointing to a root directory of a ChainedResourceProvider (e.g. in case of a DVD iso-file): // the directory in which the file that was unfolded by the ChainedResourceProvider is located; // - for an IFilesystemResourceAcessor pointing to any other directory (e.g. DVD directories): // the parent directory of such directory. var nfoDirectoryResourcePath = ResourcePathHelper.Combine(mediaFsra.CanonicalLocalResourcePath, "../"); _debugLogger.Info("[#{0}]: nfo-directory: '{1}'", miNumber, nfoDirectoryResourcePath); // Then try to create an IFileSystemResourceAccessor for this directory IResourceAccessor nfoDirectoryRa; nfoDirectoryResourcePath.TryCreateLocalResourceAccessor(out nfoDirectoryRa); var nfoDirectoryFsra = nfoDirectoryRa as IFileSystemResourceAccessor; if (nfoDirectoryFsra == null) { _debugLogger.Info("[#{0}]: Cannot extract metadata; nfo-directory not accessible'", miNumber, nfoDirectoryResourcePath); if (nfoDirectoryRa != null) nfoDirectoryRa.Dispose(); return false; } // Finally try to find a nfo-file in that directory using (nfoDirectoryFsra) { var nfoFileNames = GetNfoFileNames(mediaFsra); foreach (var nfoFileName in nfoFileNames) if (nfoDirectoryFsra.ResourceExists(nfoFileName)) { _debugLogger.Info("[#{0}]: nfo-file found: '{1}'", miNumber, nfoFileName); nfoFsra = nfoDirectoryFsra.GetResource(nfoFileName); return true; } else _debugLogger.Info("[#{0}]: nfo-file '{1}' not found; checking next possible file...", miNumber, nfoFileName); } _debugLogger.Info("[#{0}]: Cannot extract metadata; No nfo-file found", miNumber); return false; }
public override bool Process(MediaItem mediaItem, out ContentDirectoryMessaging.MediaItemChangeType changeType) { IContentDirectory cd = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory; bool removeFromML = IsManagedByMediaLibrary(mediaItem) && cd != null; changeType = ContentDirectoryMessaging.MediaItemChangeType.None; // Support multi-resource media items and secondary resources IList <MultipleMediaItemAspect> providerAspects; if (!MediaItemAspect.TryGetAspects(mediaItem.Aspects, ProviderResourceAspect.Metadata, out providerAspects)) { return(false); } foreach (MultipleMediaItemAspect providerAspect in providerAspects) { string systemId = (string)providerAspect[ProviderResourceAspect.ATTR_SYSTEM_ID]; string resourceAccessorPath = (string)providerAspect[ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH]; var rl = new ResourceLocator(systemId, ResourcePath.Deserialize(resourceAccessorPath)); using (var ra = rl.CreateAccessor()) { var rad = ra as IResourceDeletor; if (rad == null) { return(false); } // First try to delete the file from storage. if (!rad.Delete()) { return(false); } changeType = ContentDirectoryMessaging.MediaItemChangeType.Deleted; // If the MediaItem was loaded from ML, remove it there as well. if (removeFromML) { cd.DeleteMediaItemOrPath(rl.NativeSystemId, rl.NativeResourcePath, true); } } } // Check for special cases here: // 1) Recordings have an additional .xml attached // 2) Deleting files could lead to empty folders that should be also removed foreach (DeleteRule rule in _defaultRules.Where(r => r.IsEnabled)) { if (mediaItem.Aspects.ContainsKey(rule.HasAspectGuid)) { var tsPath = mediaItem.GetResourceLocator().NativeResourcePath.ToString(); foreach (string otherExtension in rule.DeleteOtherExtensions) { string otherFilePath = ProviderPathHelper.ChangeExtension(tsPath, otherExtension); IResourceAccessor ra; if (!ResourcePath.Deserialize(otherFilePath).TryCreateLocalResourceAccessor(out ra)) { continue; } // Delete other file. We do not check here for existance of file, the Delete needs to handle this. using (ra) { var rad = ra as IResourceDeletor; rad?.Delete(); } } if (rule.DeleteEmptyFolders) { var folderPath = ProviderPathHelper.GetDirectoryName(tsPath); IResourceAccessor ra; if (!ResourcePath.Deserialize(folderPath).TryCreateLocalResourceAccessor(out ra)) { continue; } // Delete folder if empty using (ra) { IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor; if (fsra != null) { var isEmpty = fsra.GetFiles().Count == 0 && fsra.GetChildDirectories().Count == 0; if (isEmpty) { var rad = ra as IResourceDeletor; rad?.Delete(); } } } } } } return(true); }
/// <summary> /// Gets a list of <see cref="FanArtImage"/>s for a requested <paramref name="mediaType"/>, <paramref name="fanArtType"/> and <paramref name="name"/>. /// The name can be: Series name, Actor name, Artist name depending on the <paramref name="mediaType"/>. /// </summary> /// <param name="mediaType">Requested FanArtMediaType</param> /// <param name="fanArtType">Requested FanArtType</param> /// <param name="name">Requested name of Series, Actor, Artist...</param> /// <param name="maxWidth">Maximum width for image. <c>0</c> returns image in original size.</param> /// <param name="maxHeight">Maximum height for image. <c>0</c> returns image in original size.</param> /// <param name="singleRandom">If <c>true</c> only one random image URI will be returned</param> /// <param name="result">Result if return code is <c>true</c>.</param> /// <returns><c>true</c> if at least one match was found.</returns> public bool TryGetFanArt(string mediaType, string fanArtType, string name, int maxWidth, int maxHeight, bool singleRandom, out IList <IResourceLocator> result) { result = null; Guid mediaItemId; if (mediaType != FanArtMediaTypes.Artist && mediaType != FanArtMediaTypes.Album && mediaType != FanArtMediaTypes.Audio) { return(false); } // Don't try to load "fanart" for images if (!Guid.TryParse(name, out mediaItemId)) { return(false); } IMediaLibrary mediaLibrary = ServiceRegistration.Get <IMediaLibrary>(false); if (mediaLibrary == null) { return(false); } IFilter filter = null; IList <MediaItem> items = null; List <Guid> necessaryMias = new List <Guid>(NECESSARY_MIAS); if (mediaType == FanArtMediaTypes.Artist) { necessaryMias.Add(AudioAspect.ASPECT_ID); necessaryMias.Add(RelationshipAspect.ASPECT_ID); filter = new RelationshipFilter(AudioAspect.ROLE_TRACK, PersonAspect.ROLE_ALBUMARTIST, mediaItemId); } else if (fanArtType == FanArtTypes.FanArt) { if (mediaType == FanArtMediaTypes.Album) { //Might be a request for album FanArt which doesn't exist. Artist FanArt is used instead. filter = new RelationshipFilter(AudioAspect.ROLE_TRACK, AudioAlbumAspect.ROLE_ALBUM, mediaItemId); } else if (mediaType == FanArtMediaTypes.Audio) { //Might be a request for track FanArt which doesn't exist. Artist FanArt is used instead. necessaryMias.Add(AudioAspect.ASPECT_ID); filter = new MediaItemIdFilter(mediaItemId); } } else { return(false); } MediaItemQuery mediaQuery = new MediaItemQuery(necessaryMias, filter); mediaQuery.Limit = 1; items = mediaLibrary.Search(mediaQuery, false, null, false); if (items == null || items.Count == 0) { return(false); } MediaItem mediaItem = items.First(); // Virtual resources won't have any local fanart if (mediaItem.IsVirtual) { return(false); } var mediaIteamLocator = mediaItem.GetResourceLocator(); var fanArtPaths = new List <ResourcePath>(); var files = new List <IResourceLocator>(); string artistName = null; var mediaItemPath = mediaIteamLocator.NativeResourcePath; var albumMediaItemDirectoryPath = ResourcePathHelper.Combine(mediaItemPath, "../"); var artistMediaItemyPath = ResourcePathHelper.Combine(mediaItemPath, "../../"); string album = null; if (MediaItemAspect.TryGetAttribute(mediaItem.Aspects, AudioAspect.ATTR_ALBUM, out album) && LocalFanartHelper.IsDiscFolder(album, albumMediaItemDirectoryPath.FileName)) { //Probably a CD folder so try next parent albumMediaItemDirectoryPath = ResourcePathHelper.Combine(mediaItemPath, "../../"); artistMediaItemyPath = ResourcePathHelper.Combine(mediaItemPath, "../../../"); } if (mediaType == FanArtMediaTypes.Artist && (fanArtType == FanArtTypes.Undefined || fanArtType == FanArtTypes.Thumbnail)) { SingleMediaItemAspect audioAspect; List <string> artists = new List <string>(); if (MediaItemAspect.TryGetAspect(mediaItem.Aspects, AudioAspect.Metadata, out audioAspect)) { IEnumerable <object> artistObjects = audioAspect.GetCollectionAttribute <object>(AudioAspect.ATTR_ALBUMARTISTS); if (artistObjects != null) { artists.AddRange(artistObjects.Cast <string>()); } } IList <MultipleMediaItemAspect> relationAspects; if (MediaItemAspect.TryGetAspects(mediaItem.Aspects, RelationshipAspect.Metadata, out relationAspects)) { foreach (MultipleMediaItemAspect relation in relationAspects) { if ((Guid?)relation[RelationshipAspect.ATTR_LINKED_ROLE] == PersonAspect.ROLE_ALBUMARTIST && (Guid?)relation[RelationshipAspect.ATTR_LINKED_ID] == mediaItemId) { int?index = (int?)relation[RelationshipAspect.ATTR_RELATIONSHIP_INDEX]; if (index.HasValue && artists.Count > index.Value && index.Value >= 0) { artistName = artists[index.Value]; } } } } } // File based access try { var mediaItemFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(mediaItemPath.ToString()).ToLowerInvariant(); var mediaItemExtension = ResourcePathHelper.GetExtension(mediaItemPath.ToString()); using (var directoryRa = new ResourceLocator(mediaIteamLocator.NativeSystemId, artistMediaItemyPath).CreateAccessor()) { var directoryFsra = directoryRa as IFileSystemResourceAccessor; if (directoryFsra != null) { var potentialFanArtFiles = LocalFanartHelper.GetPotentialFanArtFiles(directoryFsra); if (fanArtType == FanArtTypes.Poster || fanArtType == FanArtTypes.Thumbnail) { fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByPrefix(potentialFanArtFiles, LocalFanartHelper.ARTIST_FILENAMES)); fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByPrefix(potentialFanArtFiles, LocalFanartHelper.POSTER_FILENAMES)); fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByPrefix(potentialFanArtFiles, LocalFanartHelper.THUMB_FILENAMES)); } if (fanArtType == FanArtTypes.Banner) { fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByPrefix(potentialFanArtFiles, LocalFanartHelper.BANNER_FILENAMES)); } if (fanArtType == FanArtTypes.Logo) { fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByPrefix(potentialFanArtFiles, LocalFanartHelper.LOGO_FILENAMES)); } if (fanArtType == FanArtTypes.ClearArt) { fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByPrefix(potentialFanArtFiles, LocalFanartHelper.CLEARART_FILENAMES)); } if (fanArtType == FanArtTypes.FanArt) { fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByPrefix(potentialFanArtFiles, LocalFanartHelper.BACKDROP_FILENAMES)); if (directoryFsra.ResourceExists("ExtraFanArt/")) { using (var extraFanArtDirectoryFsra = directoryFsra.GetResource("ExtraFanArt/")) fanArtPaths.AddRange(LocalFanartHelper.GetPotentialFanArtFiles(extraFanArtDirectoryFsra)); } } files.AddRange(fanArtPaths.Select(path => new ResourceLocator(mediaIteamLocator.NativeSystemId, path))); } } if (!string.IsNullOrEmpty(artistName)) //Only one artist was found { using (var directoryRa = new ResourceLocator(mediaIteamLocator.NativeSystemId, albumMediaItemDirectoryPath).CreateAccessor()) { var directoryFsra = directoryRa as IFileSystemResourceAccessor; if (directoryFsra != null) { //Get Artists thumbs IFileSystemResourceAccessor alternateArtistMediaItemDirectory = directoryFsra.GetResource(".artists"); if (alternateArtistMediaItemDirectory != null) { var potentialArtistFanArtFiles = LocalFanartHelper.GetPotentialFanArtFiles(alternateArtistMediaItemDirectory); foreach (ResourcePath thumbPath in from potentialFanArtFile in potentialArtistFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()) where potentialFanArtFileNameWithoutExtension.StartsWith(artistName.Replace(" ", "_"), StringComparison.InvariantCultureIgnoreCase) select potentialFanArtFile) { files.Add(new ResourceLocator(mediaIteamLocator.NativeSystemId, thumbPath)); } } } } } } catch (Exception ex) { #if DEBUG ServiceRegistration.Get <ILogger>().Warn("LocalArtistFanArtProvider: Error while searching fanart of type '{0}' for '{1}'", ex, fanArtType, mediaIteamLocator); #endif } result = files; return(files.Count > 0); }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool importOnly, bool forceQuickMode) { try { if (!(mediaItemAccessor is IFileSystemResourceAccessor)) { return(false); } if (extractedAspectData.ContainsKey(VideoAspect.ASPECT_ID)) { return(false); } using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor)) { if (!rah.LocalFsResourceAccessor.IsFile && rah.LocalFsResourceAccessor.ResourceExists("BDMV")) { using (IFileSystemResourceAccessor fsraBDMV = rah.LocalFsResourceAccessor.GetResource("BDMV")) if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv")) { MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata); // Calling EnsureLocalFileSystemAccess not necessary; only string operation providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, 0); providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_PRIMARY, true); providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/bluray"); // BluRay disc providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH, mediaItemAccessor.CanonicalLocalResourcePath.Serialize()); // This line is important to keep in, if no VideoAspect is created here, the MediaItems is not detected as Video! SingleMediaItemAspect videoAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, VideoAspect.Metadata); videoAspect.SetAttribute(VideoAspect.ATTR_ISDVD, true); MultipleMediaItemAspect videoStreamAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata); videoStreamAspect.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0); videoStreamAspect.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, -1); MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata); mediaAspect.SetAttribute(MediaAspect.ATTR_ISVIRTUAL, false); using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess()) { BDInfoExt bdinfo = new BDInfoExt(rah.LocalFsResourceAccessor.LocalFileSystemPath); string title = bdinfo.GetTitle(); if (title == null) { try { title = mediaItemAccessor.ResourceName; if (title.StartsWith($"[{rah.LocalFsResourceAccessor.Path.Substring(1)}] ")) { title = title.Substring(rah.LocalFsResourceAccessor.Path.Length + 2).Trim(); } } catch { title = mediaItemAccessor.ResourceName; } } mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, title); // Check for BD disc thumbs FileInfo thumbnail = bdinfo.GetBiggestThumb(); if (thumbnail != null) { try { using (FileStream fileStream = new FileStream(thumbnail.FullName, FileMode.Open, FileAccess.Read)) using (MemoryStream resized = (MemoryStream)ImageUtilities.ResizeImage(fileStream, ImageFormat.Jpeg, MAX_COVER_WIDTH, MAX_COVER_HEIGHT)) { MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, resized.ToArray()); } } // Decoding of invalid image data can fail, but main MediaItem is correct. catch { } } } return(true); } } } 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); } }
/// <summary> /// Tries to parse one or more images from a single <see cref="XElement"/> and add them to an existing HashSet of byte[] /// </summary> /// <param name="element"><see cref="XElement"/> to read from</param> /// <param name="values">HashSet of byte[] to which new entries should be added</param> /// <param name="nfoDirectoryFsra"><see cref="IFileSystemResourceAccessor"/> pointing to the parent directory of the nfo-file</param> /// <returns>A HashSet of byte[] with the new and old images or <c>null</c> if there are neither old nor new values</returns> protected async Task <HashSet <byte[]> > ParseMultipleImagesAsync(XElement element, HashSet <byte[]> values, IFileSystemResourceAccessor nfoDirectoryFsra) { // Examples of valid elements: // 1: // <element.Name>[ImageString]</element.Name> // 2: // <element.Name> // <thumb>[ImageString]</thumb> // </element.Name> // The <element.Name> element may contain multiple <thumb> child elements // For examples of valid [ImageString] values see the comment of NfoReaderBase.ParseSimpleImageAsync if (element == null) { return(values); } var newValues = new HashSet <byte[]>(); if (!element.HasElements) { // Example 1: var value = await ParseSimpleImageAsync(element, nfoDirectoryFsra).ConfigureAwait(false); if (value != null) { newValues.Add(value); } } else { // Example 2: foreach (var childElement in element.Elements()) { if (childElement.Name == "thumb") { var value = await ParseSimpleImageAsync(childElement, nfoDirectoryFsra).ConfigureAwait(false); if (value != null) { newValues.Add(value); } } else { _debugLogger.Warn("[#{0}]: Unknown child element {1}", _miNumber, childElement); } } } if (!newValues.Any()) { return(values); } if (values == null) { values = new HashSet <byte[]>(newValues); } else { foreach (var value in newValues) { values.Add(value); } } return(values); }
/// <summary> /// Tries to read a simple image from <paramref name="element"/>.Value /// </summary> /// <param name="element"><see cref="XElement"/> to read from</param> /// <param name="nfoDirectoryFsra"><see cref="IFileSystemResourceAccessor"/> pointing to the parent directory of the nfo-file</param> /// <returns> /// <c>null</c> if /// - <see cref="_importOnly"/> is <c>true</c>; or /// - <see cref="_forceQuickMode"/> is <c>true</c>; or /// - a call to <see cref="ParseSimpleString"/> for <paramref name="element"/> returns <c>null</c> /// - <paramref name="element"/>.Value does not contain a valid and existing (absolute) http URL to an image; or /// - <paramref name="element"/>.Value does contain a valid and existing (relative) file path or <paramref name="nfoDirectoryFsra"/> is <c>null</c>; /// otherwise the image file read as byte array. /// </returns> /// <remarks> /// <paramref name="element.Value"/> can be /// - a file name: /// <example>folder.jpg</example> /// The file must then be in the same directory as the nfo-file /// - a relative file path: /// <example>extrafanart\fanart1.jpg</example> /// <example>..\thumbs\fanart.jpg</example> /// The path must be relative to the parent directory of the nfo-file /// - an absolute http URL /// <example>http://image.tmdb.org/t/p/original/1rre3m7WsI2QavNZD4aUa8LzzcK.jpg</example> /// </remarks> protected async Task <byte[]> ParseSimpleImageAsync(XElement element, IFileSystemResourceAccessor nfoDirectoryFsra) { if (_forceQuickMode) { return(null); } if (_importOnly) { return(null); } var imageFileString = ParseSimpleString(element); if (imageFileString == null) { return(null); } // First check whether it is a local file if (nfoDirectoryFsra != null) { var imageFsra = nfoDirectoryFsra.GetResource(imageFileString); if (imageFsra != null) { using (imageFsra) using (var imageStream = await imageFsra.OpenReadAsync().ConfigureAwait(false)) { var result = new byte[imageStream.Length]; await imageStream.ReadAsync(result, 0, (int)imageStream.Length).ConfigureAwait(false); return(result); } } } else { _debugLogger.Error("[#{0}]: The nfo-file's parent directory's fsra could not be created", _miNumber); } // Then check if we have a valid http URL Uri imageFileUri; if (!Uri.TryCreate(imageFileString, UriKind.Absolute, out imageFileUri) || imageFileUri.Scheme != Uri.UriSchemeHttp) { _debugLogger.Warn("[#{0}]: The following element does neither contain an exsisting file name nor a valid http URL: {1}", _miNumber, element); return(null); } // Finally try to download the image from the internet try { var response = await _httpDownloadClient.GetAsync(imageFileUri).ConfigureAwait(false); if (response.IsSuccessStatusCode) { return(await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false)); } _debugLogger.Warn("[#{0}]: Http status code {1} ({2}) when trying to download image file: {3}", _miNumber, (int)response.StatusCode, response.StatusCode, element); } catch (Exception e) { _debugLogger.Warn("[#{0}]: The following image file could not be downloaded: {1}", e, _miNumber, element); } return(null); }
/// <summary> /// Calls the appropriate <see cref="TryReadElementDelegate"/> or <see cref="TryReadElementAsyncDelegate"/>for each element of root /// </summary> /// <param name="nfoDocument"><see cref="XDocument"/> containing the respective nfo-file</param> /// <param name="nfoFsra"><see cref="IFileSystemResourceAccessor"/> to the nfo-file</param> /// <returns><c>true</c> if any usable metadata was found; else <c>false</c></returns> private async Task <bool> TryReadNfoDocumentAsync(XDocument nfoDocument, IFileSystemResourceAccessor nfoFsra) { // Checks the structure of the nfo document if (!IsValidNfoDocument(nfoDocument)) { return(false); } _stubs.Clear(); var result = false; // Create an IFileSystemResourceAccessor to the parent directory of the nfo-file var nfoDirectoryResourcePath = ResourcePathHelper.Combine(nfoFsra.CanonicalLocalResourcePath, "../"); IResourceAccessor nfoDirectoryRa; IFileSystemResourceAccessor nfoDirectoryFsra = null; if (nfoDirectoryResourcePath.TryCreateLocalResourceAccessor(out nfoDirectoryRa)) { nfoDirectoryFsra = nfoDirectoryRa as IFileSystemResourceAccessor; if (nfoDirectoryFsra == null) { nfoDirectoryRa.Dispose(); } } using (nfoDirectoryFsra) { // IsValidNfoDocument returns false if nfoRootDocument is null // ReSharper disable once PossibleNullReferenceException foreach (var itemRoot in nfoDocument.Root.Elements().Where(CanReadItemRootElementTree)) { _currentStub = new TStub(); var metadataFound = false; foreach (var element in itemRoot.Elements()) { Delegate readDelegate; if (_supportedElements.TryGetValue(element.Name, out readDelegate)) { try { if ((readDelegate is TryReadElementDelegate && (readDelegate as TryReadElementDelegate).Invoke(element)) || (readDelegate is TryReadElementAsyncDelegate && await(readDelegate as TryReadElementAsyncDelegate).Invoke(element, nfoDirectoryFsra).ConfigureAwait(false))) { metadataFound = true; } } catch (Exception e) { _debugLogger.Error("[#{0}]: Exception while reading element {1}", e, _miNumber, element); } } else { _debugLogger.Warn("[#{0}]: Unknown element {1}", _miNumber, element); } } if (metadataFound) { _stubs.Add(_currentStub); result = true; } } _currentStub = default(TStub); } return(result); }
public PendingImportResource(Guid parentDirectory, IFileSystemResourceAccessor resourceAccessor) { _parentDirectory = parentDirectory; _resourceAccessor = resourceAccessor; }
public bool IsResource(IFileSystemResourceAccessor baseResourceAccessor, string path) { string entryPath = ZipResourceAccessor.ToEntryPath(path); lock (_syncObj) { string key = baseResourceAccessor.CanonicalLocalResourcePath.Serialize(); try { ZipResourceProxy proxy; if (_zipUsages.TryGetValue(key, out proxy)) return path.Equals("/") || ZipResourceAccessor.IsResource(proxy.ZipFile, entryPath); } catch (Exception) { return false; } } using (Stream resourceStream = baseResourceAccessor.OpenRead()) // Not sure if the ZipFile will close the stream so we dispose it here try { using (ZipFile zFile = new ZipFile(resourceStream)) return path.Equals("/") || ZipResourceAccessor.IsResource(zFile, entryPath); } catch (Exception) { return false; } }
/// <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); }
protected VirtualFileSystemResource(string name, IFileSystemResourceAccessor resourceAccessor) { _name = name; _resourceAccessor = resourceAccessor; _creationTime = DateTime.Now; }
/// <summary> /// Tries to find a nfo-file for the given <param name="mediaFsra"></param> /// </summary> /// <param name="miNumber">Unique number for logging purposes</param> /// <param name="mediaFsra">FileSystemResourceAccessor for which we search a nfo-file</param> /// <param name="nfoFsra">FileSystemResourceAccessor of the nfo-file or <c>null</c> if no nfo-file was found</param> /// <returns><c>true</c> if a nfo-file was found, otherwise <c>false</c></returns> private bool TryGetNfoSResourceAccessor(long miNumber, IFileSystemResourceAccessor mediaFsra, out IFileSystemResourceAccessor nfoFsra) { nfoFsra = null; // Determine the directory, in which we look for the nfo-file // We cannot use mediaFsra.GetResource, because for ChainedResourceProviders the parent directory // may be located in the ParentResourceProvider. For details see the comments for the ResourcePathHelper class. // First get the ResourcePath of the parent directory // The parent directory is // - for an IFilesystemResourceAcessor pointing to a file: // the directory in which the file is located; // - for an IFilesystemResourceAcessor pointing to a root directory of a ChainedResourceProvider (e.g. in case of a DVD iso-file): // the directory in which the file that was unfolded by the ChainedResourceProvider is located; // - for an IFilesystemResourceAcessor pointing to any other directory (e.g. DVD directories): // the parent directory of such directory. var nfoDirectoryResourcePath = ResourcePathHelper.Combine(mediaFsra.CanonicalLocalResourcePath, "../"); _debugLogger.Info("[#{0}]: nfo-directory: '{1}'", miNumber, nfoDirectoryResourcePath); // Then try to create an IFileSystemResourceAccessor for this directory IResourceAccessor nfoDirectoryRa; nfoDirectoryResourcePath.TryCreateLocalResourceAccessor(out nfoDirectoryRa); var nfoDirectoryFsra = nfoDirectoryRa as IFileSystemResourceAccessor; if (nfoDirectoryFsra == null) { _debugLogger.Info("[#{0}]: Cannot extract metadata; nfo-directory not accessible'", miNumber, nfoDirectoryResourcePath); if (nfoDirectoryRa != null) { nfoDirectoryRa.Dispose(); } return(false); } // Finally try to find a nfo-file in that directory using (nfoDirectoryFsra) { var nfoFileNames = GetNfoFileNames(mediaFsra); foreach (var nfoFileName in nfoFileNames) { if (nfoDirectoryFsra.ResourceExists(nfoFileName)) { _debugLogger.Info("[#{0}]: nfo-file found: '{1}'", miNumber, nfoFileName); nfoFsra = nfoDirectoryFsra.GetResource(nfoFileName); return(true); } else { _debugLogger.Info("[#{0}]: nfo-file '{1}' not found; checking next possible file...", miNumber, nfoFileName); } } } _debugLogger.Info("[#{0}]: Cannot extract metadata; No nfo-file found", miNumber); return(false); }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { try { VideoResult result = null; IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor; if (fsra == null) { return(false); } if (!fsra.IsFile && 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 (fsra.IsFile) { string filePath = fsra.ResourcePathName; if (!HasVideoExtension(filePath)) { return(false); } using (MediaInfoWrapper fileInfo = ReadMediaInfo(fsra)) { // 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(fsra.ResourceName); result = VideoResult.CreateFileInfo(mediaTitle, fileInfo); } using (Stream stream = fsra.OpenRead()) result.MimeType = MimeTypeDetector.GetMimeType(stream, DEFAULT_MIMETYPE); } if (result != null) { result.UpdateMetadata(extractedAspectData); ILocalFsResourceAccessor disposeLfsra = null; try { ILocalFsResourceAccessor lfsra = fsra as ILocalFsResourceAccessor; if (lfsra == null && !forceQuickMode) { // In case forceQuickMode, we only want local browsing IFileSystemResourceAccessor localFsra = (IFileSystemResourceAccessor)fsra.Clone(); try { lfsra = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(localFsra); disposeLfsra = lfsra; // Remember to dispose the extra resource accessor instance } catch (Exception) { localFsra.Dispose(); } } if (lfsra != null) { string localFsPath = lfsra.LocalFileSystemPath; ExtractMatroskaTags(localFsPath, extractedAspectData, forceQuickMode); ExtractMp4Tags(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); }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor; if (fsra == null) { return(false); } if (!fsra.IsFile) { return(false); } string fileName = fsra.ResourceName; if (!HasAudioExtension(fileName)) { return(false); } MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata); MediaItemAspect audioAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, AudioAspect.Metadata); MediaItemAspect thumbnailSmallAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ThumbnailSmallAspect.Metadata); MediaItemAspect thumbnailLargeAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ThumbnailLargeAspect.Metadata); try { File tag; try { ByteVector.UseBrokenLatin1Behavior = true; // Otherwise we have problems retrieving non-latin1 chars tag = File.Create(new ResourceProviderFileAbstraction(fsra)); } catch (CorruptFileException) { // 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("AudioMetadataExtractor: Audio file '{0}' seems to be broken", fsra.CanonicalLocalResourcePath); return(false); } // Some file extensions like .mp4 can contain audio and video. Do not handle files with video content here. if (tag.Properties.VideoHeight > 0 && tag.Properties.VideoWidth > 0) { return(false); } fileName = ProviderPathHelper.GetFileNameWithoutExtension(fileName) ?? string.Empty; string title; string artist; uint? trackNo; GuessMetadataFromFileName(fileName, out title, out artist, out trackNo); if (!string.IsNullOrEmpty(tag.Tag.Title)) { title = tag.Tag.Title; } IEnumerable <string> artists; if (tag.Tag.Performers.Length > 0) { artists = tag.Tag.Performers; if ((tag.TagTypes & TagTypes.Id3v2) != 0) { artists = PatchID3v23Enumeration(artists); } } else { artists = artist == null ? null : new string[] { artist } }; if (tag.Tag.Track != 0) { trackNo = tag.Tag.Track; } mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, title); // FIXME Albert: tag.MimeType returns taglib/mp3 for an MP3 file. This is not what we want and collides with the // mimetype handling in the BASS player, which expects audio/xxx. //mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, tag.MimeType); audioAspect.SetCollectionAttribute(AudioAspect.ATTR_ARTISTS, ApplyAdditionalSeparator(artists)); audioAspect.SetAttribute(AudioAspect.ATTR_ALBUM, StringUtils.TrimToNull(tag.Tag.Album)); IEnumerable <string> albumArtists = tag.Tag.AlbumArtists; if ((tag.TagTypes & TagTypes.Id3v2) != 0) { albumArtists = PatchID3v23Enumeration(albumArtists); } audioAspect.SetCollectionAttribute(AudioAspect.ATTR_ALBUMARTISTS, ApplyAdditionalSeparator(albumArtists)); audioAspect.SetAttribute(AudioAspect.ATTR_BITRATE, tag.Properties.AudioBitrate); mediaAspect.SetAttribute(MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(tag.Tag.Comment)); IEnumerable <string> composers = tag.Tag.Composers; if ((tag.TagTypes & TagTypes.Id3v2) != 0) { composers = PatchID3v23Enumeration(composers); } audioAspect.SetCollectionAttribute(AudioAspect.ATTR_COMPOSERS, ApplyAdditionalSeparator(composers)); audioAspect.SetAttribute(AudioAspect.ATTR_DURATION, tag.Properties.Duration.TotalSeconds); if (tag.Tag.Genres.Length > 0) { IEnumerable <string> genres = tag.Tag.Genres; if ((tag.TagTypes & TagTypes.Id3v2) != 0) { genres = PatchID3v23Enumeration(genres); } audioAspect.SetCollectionAttribute(AudioAspect.ATTR_GENRES, ApplyAdditionalSeparator(genres)); } if (trackNo.HasValue) { audioAspect.SetAttribute(AudioAspect.ATTR_TRACK, (int)trackNo.Value); } if (tag.Tag.TrackCount != 0) { audioAspect.SetAttribute(AudioAspect.ATTR_NUMTRACKS, (int)tag.Tag.TrackCount); } int year = (int)tag.Tag.Year; if (year >= 30 && year <= 99) { year += 1900; } if (year >= 1930 && year <= 2030) { mediaAspect.SetAttribute(MediaAspect.ATTR_RECORDINGTIME, new DateTime(year, 1, 1)); } // The following code gets cover art images from file (embedded) or from windows explorer cache (supports folder.jpg). IPicture[] pics = tag.Tag.Pictures; if (pics.Length > 0) { thumbnailLargeAspect.SetAttribute(ThumbnailLargeAspect.ATTR_THUMBNAIL, pics[0].Data.Data); } else { // In quick mode only allow thumbs taken from cache. bool cachedOnly = forceQuickMode; // Thumbnail extraction fileName = mediaItemAccessor.ResourcePathName; IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>(); byte[] thumbData; ImageType imageType; if (generator.GetThumbnail(fileName, 96, 96, cachedOnly, out thumbData, out imageType)) { thumbnailSmallAspect.SetAttribute(ThumbnailSmallAspect.ATTR_THUMBNAIL, thumbData); } if (generator.GetThumbnail(fileName, 256, 256, cachedOnly, out thumbData, out imageType)) { thumbnailLargeAspect.SetAttribute(ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData); } } return(true); } catch (UnsupportedFormatException) { ServiceRegistration.Get <ILogger>().Info("AudioMetadataExtractor: Unsupported audio file '{0}'", fsra.CanonicalLocalResourcePath); return(false); } 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("AudioMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", fsra.CanonicalLocalResourcePath, e.Message); } return(false); }
public ResourceProviderFileAbstraction(IFileSystemResourceAccessor resourceAccessor) { _resourceAccessor = resourceAccessor; }
public bool TryChainUp(IFileSystemResourceAccessor potentialBaseResourceAccessor, string path, out IFileSystemResourceAccessor resultResourceAccessor) { resultResourceAccessor = null; string resourcePathName = potentialBaseResourceAccessor.ResourcePathName; if (string.IsNullOrEmpty(resourcePathName) || !potentialBaseResourceAccessor.IsFile || !".iso".Equals(DosPathHelper.GetExtension(resourcePathName), StringComparison.OrdinalIgnoreCase)) { return(false); } lock (_syncObj) { string key = potentialBaseResourceAccessor.CanonicalLocalResourcePath.Serialize(); try { IsoResourceProxy proxy; if (!_isoUsages.TryGetValue(key, out proxy)) { _isoUsages.Add(key, proxy = CreateIsoResourceProxy(key, potentialBaseResourceAccessor)); } resultResourceAccessor = new IsoResourceAccessor(this, proxy, path); } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("IsoResourceProvider: Error chaining up to '{0}'", e, potentialBaseResourceAccessor.CanonicalLocalResourcePath); return(false); } return(true); } }
/// <summary> /// Convenience method for <see cref="GetLocalFsResourceAccessor(IFileSystemResourceAccessor,string)"/> for the root path (<c>"/"</c>). /// </summary> /// <param name="baseResourceAccessor">Resource accessor which is used to provide the resource contents.</param> /// <returns>Resource accessor which implements <see cref="ILocalFsResourceAccessor"/>.</returns> public static ILocalFsResourceAccessor GetLocalFsResourceAccessor(IFileSystemResourceAccessor baseResourceAccessor) { return(GetLocalFsResourceAccessor(baseResourceAccessor, "/")); }
protected override ViewSpecification NavigateCreateViewSpecification(string systemId, IFileSystemResourceAccessor viewRa) { return(new LocalDirectoryViewSpecification(null, viewRa.CanonicalLocalResourcePath, _necessaryMIATypeIds, _optionalMIATypeIds)); }
private void ExtractFolderImages(IResourceLocator mediaItemLocater, Guid?episodeMediaItemId, Guid?seriesMediaItemId, Guid?seasonMediaItemId, EpisodeInfo episode, SeriesInfo series, SeasonInfo season, IDictionary <Guid, string> actorMediaItems) { string fileSystemPath = string.Empty; // File based access try { if (mediaItemLocater != null) { fileSystemPath = mediaItemLocater.NativeResourcePath.FileName; var mediaItemPath = mediaItemLocater.NativeResourcePath; var mediaItemFileName = ResourcePathHelper.GetFileNameWithoutExtension(mediaItemPath.ToString()).ToLowerInvariant(); var seasonMediaItemDirectoryPath = ResourcePathHelper.Combine(mediaItemPath, "../"); var seriesMediaItemDirectoryPath = ResourcePathHelper.Combine(mediaItemPath, "../../"); //Series fanart var fanArtPaths = new List <ResourcePath>(); var posterPaths = new List <ResourcePath>(); var bannerPaths = new List <ResourcePath>(); var logoPaths = new List <ResourcePath>(); var clearArtPaths = new List <ResourcePath>(); var discArtPaths = new List <ResourcePath>(); if (seriesMediaItemId.HasValue) { using (var directoryRa = new ResourceLocator(mediaItemLocater.NativeSystemId, seriesMediaItemDirectoryPath).CreateAccessor()) { var directoryFsra = directoryRa as IFileSystemResourceAccessor; if (directoryFsra != null) { if (actorMediaItems.Count > 0) { //Get Actor thumbs IFileSystemResourceAccessor actorMediaItemDirectory = directoryFsra.GetResource(".actors"); if (actorMediaItemDirectory != null) { foreach (var actor in actorMediaItems) { var potentialArtistFanArtFiles = GetPotentialFanArtFiles(actorMediaItemDirectory); foreach (ResourcePath thumbPath in from potentialFanArtFile in potentialArtistFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()) where potentialFanArtFileNameWithoutExtension.StartsWith(actor.Value.Replace(" ", "_"), StringComparison.InvariantCultureIgnoreCase) select potentialFanArtFile) { SaveFolderFile(mediaItemLocater, thumbPath, FanArtTypes.Thumbnail, actor.Key, actor.Value); } } } } var potentialFanArtFiles = GetPotentialFanArtFiles(directoryFsra); posterPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == "poster" || potentialFanArtFileNameWithoutExtension == "folder" || potentialFanArtFileNameWithoutExtension == "cover" select potentialFanArtFile); logoPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == "logo" select potentialFanArtFile); clearArtPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == "clearart" select potentialFanArtFile); discArtPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == "discart" || potentialFanArtFileNameWithoutExtension == "disc" select potentialFanArtFile); bannerPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == "banner" select potentialFanArtFile); fanArtPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == "backdrop" || potentialFanArtFileNameWithoutExtension == "fanart" select potentialFanArtFile); if (directoryFsra.ResourceExists("ExtraFanArt/")) { using (var extraFanArtDirectoryFsra = directoryFsra.GetResource("ExtraFanArt/")) fanArtPaths.AddRange(GetPotentialFanArtFiles(extraFanArtDirectoryFsra)); } } } foreach (ResourcePath posterPath in posterPaths) { SaveFolderFile(mediaItemLocater, posterPath, FanArtTypes.Poster, seriesMediaItemId.Value, series.ToString()); } foreach (ResourcePath logoPath in logoPaths) { SaveFolderFile(mediaItemLocater, logoPath, FanArtTypes.Logo, seriesMediaItemId.Value, series.ToString()); } foreach (ResourcePath clearArtPath in clearArtPaths) { SaveFolderFile(mediaItemLocater, clearArtPath, FanArtTypes.ClearArt, seriesMediaItemId.Value, series.ToString()); } foreach (ResourcePath discArtPath in discArtPaths) { SaveFolderFile(mediaItemLocater, discArtPath, FanArtTypes.DiscArt, seriesMediaItemId.Value, series.ToString()); } foreach (ResourcePath bannerPath in bannerPaths) { SaveFolderFile(mediaItemLocater, bannerPath, FanArtTypes.Banner, seriesMediaItemId.Value, series.ToString()); } foreach (ResourcePath fanartPath in fanArtPaths) { SaveFolderFile(mediaItemLocater, fanartPath, FanArtTypes.FanArt, seriesMediaItemId.Value, series.ToString()); } } //Season fanart fanArtPaths.Clear(); posterPaths.Clear(); bannerPaths.Clear(); logoPaths.Clear(); clearArtPaths.Clear(); discArtPaths.Clear(); if (seasonMediaItemId.HasValue) { using (var directoryRa = new ResourceLocator(mediaItemLocater.NativeSystemId, seasonMediaItemDirectoryPath).CreateAccessor()) { var directoryFsra = directoryRa as IFileSystemResourceAccessor; if (directoryFsra != null) { if (actorMediaItems.Count > 0) { //Get Actor thumbs IFileSystemResourceAccessor actorMediaItemDirectory = directoryFsra.GetResource(".actors"); if (actorMediaItemDirectory != null) { foreach (var actor in actorMediaItems) { var potentialArtistFanArtFiles = GetPotentialFanArtFiles(actorMediaItemDirectory); foreach (ResourcePath thumbPath in from potentialFanArtFile in potentialArtistFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()) where potentialFanArtFileNameWithoutExtension.StartsWith(actor.Value.Replace(" ", "_"), StringComparison.InvariantCultureIgnoreCase) select potentialFanArtFile) { SaveFolderFile(mediaItemLocater, thumbPath, FanArtTypes.Thumbnail, actor.Key, actor.Value); } } } } var potentialFanArtFiles = GetPotentialFanArtFiles(directoryFsra); posterPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == "poster" || potentialFanArtFileNameWithoutExtension == "folder" || potentialFanArtFileNameWithoutExtension == "cover" select potentialFanArtFile); bannerPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == "banner" select potentialFanArtFile); fanArtPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == "backdrop" || potentialFanArtFileNameWithoutExtension == "fanart" select potentialFanArtFile); if (directoryFsra.ResourceExists("ExtraFanArt/")) { using (var extraFanArtDirectoryFsra = directoryFsra.GetResource("ExtraFanArt/")) fanArtPaths.AddRange(GetPotentialFanArtFiles(extraFanArtDirectoryFsra)); } } } using (var directoryRa = new ResourceLocator(mediaItemLocater.NativeSystemId, seriesMediaItemDirectoryPath).CreateAccessor()) { var directoryFsra = directoryRa as IFileSystemResourceAccessor; if (directoryFsra != null && season.SeasonNumber.HasValue) { var potentialFanArtFiles = GetPotentialFanArtFiles(directoryFsra); List <string> prefixes = new List <string>(); prefixes.Add(string.Format("season{0:00}-", season.SeasonNumber.Value)); if (season.SeasonNumber.Value == 0) { prefixes.Add("season-specials-"); } else { prefixes.Add("season-all-"); } foreach (string prefix in prefixes) { if (posterPaths.Count == 0) { posterPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == prefix + "poster" select potentialFanArtFile); } if (logoPaths.Count == 0) { logoPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == prefix + "logo" select potentialFanArtFile); } if (clearArtPaths.Count == 0) { clearArtPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == prefix + "clearart" select potentialFanArtFile); } if (bannerPaths.Count == 0) { bannerPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == prefix + "banner" select potentialFanArtFile); } if (fanArtPaths.Count == 0) { fanArtPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == prefix + "fanart" select potentialFanArtFile); } } } } foreach (ResourcePath posterPath in posterPaths) { SaveFolderFile(mediaItemLocater, posterPath, FanArtTypes.Poster, seasonMediaItemId.Value, season.ToString()); } foreach (ResourcePath logoPath in logoPaths) { SaveFolderFile(mediaItemLocater, logoPath, FanArtTypes.Logo, seasonMediaItemId.Value, season.ToString()); } foreach (ResourcePath clearArtPath in clearArtPaths) { SaveFolderFile(mediaItemLocater, clearArtPath, FanArtTypes.ClearArt, seasonMediaItemId.Value, season.ToString()); } foreach (ResourcePath bannerPath in bannerPaths) { SaveFolderFile(mediaItemLocater, bannerPath, FanArtTypes.Banner, seasonMediaItemId.Value, season.ToString()); } foreach (ResourcePath fanartPath in fanArtPaths) { SaveFolderFile(mediaItemLocater, fanartPath, FanArtTypes.FanArt, seasonMediaItemId.Value, season.ToString()); } } //Episode fanart //Also saved by the video MDE but saved here again in case of the offline option being different var thumbPaths = new List <ResourcePath>(); if (episodeMediaItemId.HasValue) { using (var directoryRa = new ResourceLocator(mediaItemLocater.NativeSystemId, seasonMediaItemDirectoryPath).CreateAccessor()) { var directoryFsra = directoryRa as IFileSystemResourceAccessor; if (directoryFsra != null) { var potentialFanArtFiles = GetPotentialFanArtFiles(directoryFsra); thumbPaths.AddRange( from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension.StartsWith(mediaItemFileName + "-thumb") || potentialFanArtFileNameWithoutExtension == "thumb" select potentialFanArtFile); } } foreach (ResourcePath thumbPath in thumbPaths) { SaveFolderFile(mediaItemLocater, thumbPath, FanArtTypes.Thumbnail, episodeMediaItemId.Value, episode.ToString()); } } } } catch (Exception ex) { Logger.Warn("SeriesFanArtHandler: Exception while reading folder images for '{0}'", ex, fileSystemPath); } }
/// <summary> /// Sets the data of the new image to be played. /// </summary> /// <param name="locator">Resource locator of the image item.</param> /// <param name="mediaItemTitle">Title of the image item.</param> /// <param name="rotation">Rotation of the image.</param> /// <param name="flipX">Flipping in horizontal direction.</param> /// <param name="flipY">Flipping in vertical direction.</param> public void SetMediaItemData(IResourceLocator locator, string mediaItemTitle, RightAngledRotation rotation, bool flipX, bool flipY) { if (locator == null) { lock (_syncObj) { _currentLocator = null; return; } } using (IResourceAccessor ra = locator.CreateAccessor()) { IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor; if (fsra == null) { return; } using (Stream stream = fsra.OpenRead()) { string key = fsra.CanonicalLocalResourcePath.Serialize(); _texture = ContentManager.Instance.GetTexture(stream, key, true); if (_texture == null) { return; } if (!_texture.IsAllocated) { _texture.Allocate(); } if (!_texture.IsAllocated) { return; } } } lock (_syncObj) { ReloadSettings(); _state = PlayerState.Active; _currentLocator = locator; _mediaItemTitle = mediaItemTitle; _rotation = rotation; _flipX = flipX; _flipY = flipY; SurfaceDescription desc = _texture.Texture.GetLevelDescription(0); _textureMaxUV = new SizeF(_texture.Width / (float)desc.Width, _texture.Height / (float)desc.Height); // Reset animation _animator.Initialize(); if (_slideShowTimer != null) { _slideShowTimer.Change(_slideShowImageDuration, TS_INFINITE); } else { CheckTimer(); } _playbackStartTime = DateTime.Now; if (_pauseTime.HasValue) { _pauseTime = _playbackStartTime; } } }
/// <summary> /// Adds all media items which are found in the directory to the given <paramref name="directoryRA"/> or in any sub directory to /// the <paramref name="mediaItems"/> collection. /// </summary> /// <param name="directoryRA">Directory resource to be recursively examined.</param> /// <param name="mediaItems">Collection where the found media items are added.</param> /// <param name="metadataExtractorIds">Ids of the metadata extractors to be applied to the resources. /// See <see cref="IMediaAccessor.LocalMetadataExtractors"/>.</param> /// <param name="mediaAccessor">The media accessor of the system.</param> public static void AddLocalMediaItemsRecursive(IFileSystemResourceAccessor directoryRA, ICollection<MediaItem> mediaItems, IEnumerable<Guid> metadataExtractorIds, IMediaAccessor mediaAccessor) { ICollection<IFileSystemResourceAccessor> directoryRAs = FileSystemResourceNavigator.GetChildDirectories(directoryRA, false); if (directoryRAs != null) foreach (IFileSystemResourceAccessor subDirectoryRA in directoryRAs) using (subDirectoryRA) AddLocalMediaItemsRecursive(subDirectoryRA, mediaItems, metadataExtractorIds, mediaAccessor); ICollection<IFileSystemResourceAccessor> fileRAs = FileSystemResourceNavigator.GetFiles(directoryRA, false); if (fileRAs != null) foreach (IFileSystemResourceAccessor fileRA in fileRAs) using (fileRA) { MediaItem item = mediaAccessor.CreateLocalMediaItem(fileRA, metadataExtractorIds); if (item != null) mediaItems.Add(item); } }
/// <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(IFileSystemResourceAccessor directoryAccessor, bool showSystemResources) { IResourceMountingService resourceMountingService = ServiceRegistration.Get <IResourceMountingService>(); IFileSystemResourceAccessor chainedResourceAccesor; // Needed in multiple source locations, that's why we declare it here ICollection <IFileSystemResourceAccessor> childDirectories = directoryAccessor.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 = directoryAccessor.GetFiles(); if (files != null) { // For files, we try to chain up chained resource providers foreach (IFileSystemResourceAccessor fileAccessor in files) { using (fileAccessor) { if (!showSystemResources && resourceMountingService.IsVirtualResource(fileAccessor.CanonicalLocalResourcePath)) { continue; } if (TryUnfold(fileAccessor, out chainedResourceAccesor)) { if (!chainedResourceAccesor.IsFile) { result.Add(chainedResourceAccesor); } else { chainedResourceAccesor.Dispose(); } } // Simply ignore files because we only want to return directories } } } if (result.Count > 0) { return(result); } // Try to unfold simple resource if (TryUnfold(directoryAccessor, out chainedResourceAccesor)) { if (!chainedResourceAccesor.IsFile) { return(new List <IFileSystemResourceAccessor>(new IFileSystemResourceAccessor[] { chainedResourceAccesor })); } chainedResourceAccesor.Dispose(); } return(null); }
/// <summary> /// Tries to unfold the given <paramref name="fileAccessor"/> to a virtual directory. /// </summary> /// <param name="fileAccessor">File resource accessor to be used as input for a potential chained provider. /// The ownership of this resource accessor remains at the caller.</param> /// <param name="resultResourceAccessor">Chained resource accessor which was chained upon the given file resource.</param> public static bool TryUnfold(IFileSystemResourceAccessor fileAccessor, out IFileSystemResourceAccessor resultResourceAccessor) { IMediaAccessor mediaAccessor = ServiceRegistration.Get<IMediaAccessor>(); foreach (IChainedResourceProvider cmp in mediaAccessor.LocalChainedResourceProviders) if (cmp.TryChainUp(fileAccessor, "/", out resultResourceAccessor)) return true; resultResourceAccessor = null; return false; }
public bool TryChainUp(IFileSystemResourceAccessor potentialBaseResourceAccessor, string path, out IFileSystemResourceAccessor resultResourceAccessor) { resultResourceAccessor = null; string resourcePathName = potentialBaseResourceAccessor.ResourcePathName; if (string.IsNullOrEmpty(resourcePathName) || !potentialBaseResourceAccessor.IsFile || !".zip".Equals(DosPathHelper.GetExtension(resourcePathName), StringComparison.OrdinalIgnoreCase)) return false; lock (_syncObj) { string key = potentialBaseResourceAccessor.CanonicalLocalResourcePath.Serialize(); try { ZipResourceProxy proxy; if (!_zipUsages.TryGetValue(key, out proxy)) _zipUsages.Add(key, proxy = CreateZipResourceProxy(key, potentialBaseResourceAccessor)); resultResourceAccessor = new ZipResourceAccessor(this, proxy, path); } catch (Exception e) { ServiceRegistration.Get<ILogger>().Warn("ZipResourceProvider: Error chaining up to '{0}'", e, potentialBaseResourceAccessor.CanonicalLocalResourcePath); return false; } return true; } }
/// <summary> /// Method that processes the Uri. /// </summary> public override async Task Invoke(IOwinContext context) { var request = context.Request; var response = context.Response; ResourcePath resourcePath; Uri uri = request.Uri; if (!uri.AbsolutePath.StartsWith(ResourceHttpAccessUrlUtils.RESOURCE_SERVER_BASE_PATH) || !uri.AbsolutePath.Contains(ResourceHttpAccessUrlUtils.RESOURCE_ACCESS_PATH)) { await Next.Invoke(context); return; } if (!ResourceHttpAccessUrlUtils.ParseResourceURI(uri, out resourcePath)) { response.StatusCode = (int)HttpStatusCode.BadRequest; response.ReasonPhrase = string.Format("Illegal request syntax. Correct syntax is '{0}'", ResourceHttpAccessUrlUtils.SYNTAX); return; } if (!IsAllowedToAccess(resourcePath)) { ServiceRegistration.Get <ILogger>().Warn("ResourceAccessModule: Client tries to access forbidden resource '{0}'", resourcePath); response.StatusCode = (int)HttpStatusCode.Forbidden; response.ReasonPhrase = string.Format("Access of resource '{0}' not allowed", resourcePath); return; } try { IFileSystemResourceAccessor fsra = GetResourceAccessor(resourcePath); using (Stream resourceStream = fsra.OpenRead()) { response.ContentType = GuessMimeType(resourceStream, resourcePath.FileName); if (!string.IsNullOrEmpty(request.Headers["If-Modified-Since"])) { DateTime lastRequest = DateTime.Parse(request.Headers["If-Modified-Since"], System.Globalization.CultureInfo.InvariantCulture); if (lastRequest.CompareTo(fsra.LastChanged) <= 0) { response.StatusCode = (int)HttpStatusCode.NotModified; } } response.Headers["Last-Modified"] = fsra.LastChanged.ToUniversalTime().ToString("r"); string byteRangesSpecifier = request.Headers["Range"]; IList <Range> ranges = ParseRanges(byteRangesSpecifier, resourceStream.Length); bool onlyHeaders = request.Method == "Headers" || response.StatusCode == (int)HttpStatusCode.NotModified; CancellationTokenSource cts = new CancellationTokenSource(); if (ranges != null && ranges.Count == 1) { // We only support one range await SendRange(response, resourceStream, ranges[0], onlyHeaders, cts.Token); } else { await SendWholeFile(response, resourceStream, onlyHeaders, cts.Token); } } } catch (FileNotFoundException ex) { response.StatusCode = (int)HttpStatusCode.InternalServerError; response.ReasonPhrase = string.Format("Failed to proccess resource '{0}': {1}", resourcePath, ex.Message); } }
internal ZipResourceProxy CreateZipResourceProxy(string key, IFileSystemResourceAccessor zipFileResourceAccessor) { ZipResourceProxy result = new ZipResourceProxy(key, zipFileResourceAccessor); result.Orphaned += OnZipResourceProxyOrphaned; return result; }
protected override ViewSpecification NavigateCreateViewSpecification(string systemId, IFileSystemResourceAccessor viewRA) { IServerConnectionManager serverConnectionManager = ServiceRegistration.Get<IServerConnectionManager>(); IContentDirectory cd = serverConnectionManager.ContentDirectory; if (cd == null) return null; ResourcePath directoryPath = viewRA.CanonicalLocalResourcePath; MediaItem directoryItem = cd.LoadItem(systemId, directoryPath, SystemSharesViewSpecification.DIRECTORY_MIA_ID_ENUMERATION, SystemSharesViewSpecification.EMPTY_ID_ENUMERATION); if (directoryItem == null) return null; return new MediaLibraryBrowseViewSpecification(viewRA.ResourceName, directoryItem.MediaItemId, systemId, directoryPath, _necessaryMIATypeIds, _optionalMIATypeIds); }
/// <summary> /// Determines all possible file names for the nfo-file based on the respective NfoMovieMetadataExtractorSettings /// </summary> /// <param name="mediaFsra">IFilesystemResourceAccessor to the media file for which we search an nfo-file</param> /// <returns>IEnumerable of strings containing the possible nfo-file names</returns> IEnumerable<string> GetNfoFileNames(IFileSystemResourceAccessor mediaFsra) { var result = new List<string>(); // Always consider the file or directory name of the media item string mediaFileOrDirectoryName; // If the MediaItem is a file, we simply take the filename without extension if (mediaFsra.IsFile) mediaFileOrDirectoryName = ResourcePathHelper.GetFileNameWithoutExtension(mediaFsra.CanonicalLocalResourcePath.Serialize()); else { // if the media is a directory (such as a DVD or BluRay) we start with the ResourcePath mediaFileOrDirectoryName = mediaFsra.CanonicalLocalResourcePath.Serialize(); // In case of the root path of a ChainedResourceProvider (such as for DVD- or BluRay-Iso-Files), we remove the last // ChainedResourceProvider, leaving us with the full path of the file, the ChainedResourceProvider has unfolded if (mediaFileOrDirectoryName.EndsWith(":///") && mediaFileOrDirectoryName.Contains(">")) mediaFileOrDirectoryName = mediaFileOrDirectoryName.Substring(0, mediaFileOrDirectoryName.LastIndexOf(">", StringComparison.Ordinal) - 1); // If it's a directory in a BaseResourceProvider, we just remove the last "/" so that the following // GetFileNameWithoutExtension considers the directory as a file. else mediaFileOrDirectoryName = StringUtils.RemoveSuffixIfPresent(mediaFileOrDirectoryName, "/"); // Finally we get the file name without extension mediaFileOrDirectoryName = ResourcePathHelper.GetFileNameWithoutExtension(mediaFileOrDirectoryName); } // Combine the mediaFileOrDirectoryName and potentially further MovieNfoFileNames from the settings with // the NfoFileNameExtensions from the settings foreach (var extension in _settings.NfoFileNameExtensions) { result.Add(mediaFileOrDirectoryName + extension); result.AddRange(_settings.MovieNfoFileNames.Select(movieNfoFileName => movieNfoFileName + extension)); } return result; }
/// <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(IFileSystemResourceAccessor 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 VirtualFile(string name, IFileSystemResourceAccessor resourceAccessor) : base(name, resourceAccessor) { }
public CachedResource(IFileSystemResourceAccessor resourceAccessor) { _lastTimeUsed = DateTime.Now; _resourceAccessor = resourceAccessor; }
/// <summary> /// Returns all files in the given directory. /// </summary> /// <remarks> /// This method simply returns the files files of the given <paramref name="directoryAccessor"/>, filtered /// if <paramref name="showSystemResources"/> is set to <c>true</c>. /// </remarks> /// <param name="directoryAccessor">Directory resource accessor to get all files 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 accessors for all files or <c>null</c>, /// if the given <paramref name="directoryAccessor"/> is not a <see cref="IFileSystemResourceAccessor"/>.</returns> public static ICollection<IFileSystemResourceAccessor> GetFiles(IFileSystemResourceAccessor directoryAccessor, bool showSystemResources) { IResourceMountingService resourceMountingService = ServiceRegistration.Get<IResourceMountingService>(); ICollection<IFileSystemResourceAccessor> result = new List<IFileSystemResourceAccessor>(); foreach (IFileSystemResourceAccessor fileAccessor in directoryAccessor.GetFiles()) { if (!showSystemResources && resourceMountingService.IsVirtualResource(fileAccessor.CanonicalLocalResourcePath)) { fileAccessor.Dispose(); continue; } result.Add(fileAccessor); } return result; }
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); try { if (!(mediaItemAccessor is IFileSystemResourceAccessor)) { return(false); } IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor; // Open a stream for media item to detect mimeType. using (Stream mediaStream = fsra.OpenRead()) { string mimeType = MimeTypeDetector.GetMimeType(mediaStream) ?? DEFAULT_MIMETYPE; mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, mimeType); mediaAspect.SetAttribute(MediaAspect.ATTR_SIZE, fsra.Size); } // Extract EXIF information from media item. using (ExifMetaInfo.ExifMetaInfo exif = new ExifMetaInfo.ExifMetaInfo(fsra)) { mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, ProviderPathHelper.GetFileNameWithoutExtension(fileName)); mediaAspect.SetAttribute(MediaAspect.ATTR_RECORDINGTIME, exif.OriginalDate != DateTime.MinValue ? exif.OriginalDate : fsra.LastChanged); mediaAspect.SetAttribute(MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(exif.ImageDescription)); if (exif.PixXDim.HasValue) { imageAspect.SetAttribute(ImageAspect.ATTR_WIDTH, (int)exif.PixXDim); } if (exif.PixYDim.HasValue) { 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)); if (exif.ExposureBias.HasValue) { imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_BIAS, ((double)exif.ExposureBias).ToString()); } imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_TIME, exif.ExposureTime); imageAspect.SetAttribute(ImageAspect.ATTR_FLASH_MODE, StringUtils.TrimToNull(exif.FlashMode)); if (exif.FNumber.HasValue) { 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.OrientationType ?? 0)); imageAspect.SetAttribute(ImageAspect.ATTR_METERING_MODE, exif.MeteringMode.ToString()); if (exif.Latitude.HasValue && exif.Longitude.HasValue) { imageAspect.SetAttribute(ImageAspect.ATTR_LATITUDE, exif.Latitude); imageAspect.SetAttribute(ImageAspect.ATTR_LONGITUDE, exif.Longitude); CivicAddress locationInfo; if (!forceQuickMode && GeoLocationService.Instance.TryLookup(new GeoCoordinate(exif.Latitude.Value, exif.Longitude.Value), out locationInfo)) { imageAspect.SetAttribute(ImageAspect.ATTR_CITY, locationInfo.City); imageAspect.SetAttribute(ImageAspect.ATTR_STATE, locationInfo.StateProvince); imageAspect.SetAttribute(ImageAspect.ATTR_COUNTRY, locationInfo.CountryRegion); } } using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor)) { string localFsResourcePath = rah.LocalFsResourceAccessor.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, 256, 256, cachedOnly, out thumbData, out imageType)) { MediaItemAspect.SetAttribute(extractedAspectData, 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); }
protected AbstractBassResourceInputSource(IFileSystemResourceAccessor resourceAccessor) { _accessor = resourceAccessor; }
/// <summary> /// Checks if the gived <paramref name="mediaItemAccessor"/> points to a directory and if it is considered a "single item" media source (like DVD or BD folders on hard drive). /// </summary> /// <param name="mediaItemAccessor">Local FS accessor</param> /// <returns><c>true</c> if it is a single item.</returns> protected async Task <bool> IsSingleResource(IFileSystemResourceAccessor mediaItemAccessor) { //ToDo: Replace this with a call to IsSingleResource once this method is implemented in the MetadataExtractors return(mediaItemAccessor.IsFile || await ExtractMetadata(mediaItemAccessor, null, true, true) != null); }
/// <summary> /// Creates and initializes an new instance. /// </summary> /// <param name="resourceAccessor">The resource accessor to the media item to be handled by the instance.</param> /// <returns>The new instance.</returns> public static BassAudioFileInputSource Create(IFileSystemResourceAccessor resourceAccessor) { BassAudioFileInputSource inputSource = new BassAudioFileInputSource(resourceAccessor); inputSource.Initialize(); return inputSource; }
protected internal override void ReLoadItemsAndSubViewSpecifications(out IList <MediaItem> mediaItems, out IList <ViewSpecification> subViewSpecifications) { mediaItems = new List <MediaItem>(); subViewSpecifications = new List <ViewSpecification>(); IMediaAccessor mediaAccessor = ServiceRegistration.Get <IMediaAccessor>(); IEnumerable <Guid> metadataExtractorIds = mediaAccessor.GetMetadataExtractorsForMIATypes(_necessaryMIATypeIds.Union(_optionalMIATypeIds)); IResourceAccessor baseResourceAccessor; if (!_viewPath.TryCreateLocalResourceAccessor(out baseResourceAccessor)) { ServiceRegistration.Get <ILogger>().Warn("LocalDirectoryViewSpecification.ReLoadItemsAndSubViewSpecifications: Cannot access local view path '{0}'", _viewPath); return; } using (baseResourceAccessor) { IFileSystemResourceAccessor fsra = baseResourceAccessor as IFileSystemResourceAccessor; if (fsra == null) { ServiceRegistration.Get <ILogger>().Warn("LocalDirectoryViewSpecification.ReLoadItemsAndSubViewSpecifications: Cannot access local view path '{0}' - no local file system resource", _viewPath); return; } // Add all items at the specified path ICollection <IFileSystemResourceAccessor> files = FileSystemResourceNavigator.GetFiles(fsra, false); if (files != null) { foreach (IFileSystemResourceAccessor childAccessor in files) { using (childAccessor) try { MediaItem result = mediaAccessor.CreateLocalMediaItem(childAccessor, metadataExtractorIds); if (result != null) { mediaItems.Add(result); } } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("LocalDirectoryViewSpecification: Error creating local media item for '{0}'", e, childAccessor); } } } ICollection <IFileSystemResourceAccessor> directories = FileSystemResourceNavigator.GetChildDirectories(fsra, false); if (directories != null) { foreach (IFileSystemResourceAccessor childAccessor in directories) { using (childAccessor) try { MediaItem result = mediaAccessor.CreateLocalMediaItem(childAccessor, metadataExtractorIds); if (result == null) { subViewSpecifications.Add(new LocalDirectoryViewSpecification(null, childAccessor.CanonicalLocalResourcePath, _necessaryMIATypeIds, _optionalMIATypeIds)); } else { mediaItems.Add(result); } } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("LocalDirectoryViewSpecification: Error creating media item or view specification for '{0}'", e, childAccessor); } } } } }
static internal MountingDataProxy CreateMountingDataProxy(string key, IFileSystemResourceAccessor baseResourceAccessor) { MountingDataProxy result = new MountingDataProxy(key, baseResourceAccessor); result.MountingDataOrphaned += OnMountingDataOrphaned; return result; }
protected VirtualBaseDirectory(string name, IFileSystemResourceAccessor resourceAccessor) : base(name, resourceAccessor) { }
/// <summary> /// Convenience method for <see cref="GetLocalFsResourceAccessor(IFileSystemResourceAccessor,string)"/> for the root path (<c>"/"</c>). /// </summary> /// <param name="baseResourceAccessor">Resource accessor which is used to provide the resource contents.</param> /// <returns>Resource accessor which implements <see cref="ILocalFsResourceAccessor"/>.</returns> public static ILocalFsResourceAccessor GetLocalFsResourceAccessor(IFileSystemResourceAccessor baseResourceAccessor) { return GetLocalFsResourceAccessor(baseResourceAccessor, "/"); }
/// <summary> /// Tries to read a valid IMDB id from additional .nfo or .txt files. /// </summary> /// <param name="fsra">FileSystemResourceAccessor</param> /// <param name="imdbId">Returns a valid IMDB or <c>null</c></param> /// <returns>true if matched</returns> public static bool TryMatchImdbId(IFileSystemResourceAccessor fsra, out string imdbId) { imdbId = null; if (fsra == null) { return(false); } // First try to find a nfo file that has the same name as our main movie. if (fsra.IsFile) { foreach (string extension in NFO_EXTENSIONS) { string metaFilePath = ResourcePathHelper.ChangeExtension(fsra.CanonicalLocalResourcePath.ToString(), extension); if (TryRead(metaFilePath, out imdbId)) { return(true); } } } // Prepare a list of paths to check: for chained resource path we will also check relative parent paths (like for DVD-ISO files) List <string> pathsToCheck = new List <string> { fsra.CanonicalLocalResourcePath.ToString() }; if (fsra.CanonicalLocalResourcePath.PathSegments.Count > 1) { string canocialPath = fsra.CanonicalLocalResourcePath.ToString(); pathsToCheck.Add(canocialPath.Substring(0, canocialPath.LastIndexOf('>'))); } // Then test for special named files, like "movie.nfo" foreach (string path in pathsToCheck) { foreach (string fileName in NFO_FILENAMES) { string metaFilePath = ResourcePathHelper.GetDirectoryName(path); metaFilePath = ResourcePathHelper.Combine(metaFilePath, fileName); if (TryRead(metaFilePath, out imdbId)) { return(true); } } } // Now check siblings of movie for any IMDB id containing filename. // Morpheus_xx, 2014-01-04: disabled code because it leads to false detections if there are multiple video files in same folder. In this case the first // video with TT-number is wrongly used. // TODO: this part could be reworked based on different ideas: // - Exclude known video extensions from file name matching (this would require a reference to VideoMDE's settings for extension list) // - Only use folder lookup for chained resources, i.e. for a DVD-ISO, where any "TT000000.bla" is located next to it //IFileSystemResourceAccessor directoryFsra = null; //if (!fsra.IsFile) // directoryFsra = fsra.Clone() as IFileSystemResourceAccessor; //if (fsra.IsFile) // directoryFsra = GetContainingDirectory(fsra); //if (directoryFsra == null) // return false; //using (directoryFsra) // foreach (IFileSystemResourceAccessor file in directoryFsra.GetFiles()) // using (file) // if (ImdbIdMatcher.TryMatchImdbId(file.ResourceName, out imdbId)) // return true; return(false); }
private BassMODFileInputSource(IFileSystemResourceAccessor resourceAccessor) : base(resourceAccessor) { }
/// <summary> /// Gets a list of <see cref="FanArtImage"/>s for a requested <paramref name="mediaType"/>, <paramref name="fanArtType"/> and <paramref name="name"/>. /// The name can be: Series name, Actor name, Artist name depending on the <paramref name="mediaType"/>. /// </summary> /// <param name="mediaType">Requested FanArtMediaType</param> /// <param name="fanArtType">Requested FanArtType</param> /// <param name="name">Requested name of Series, Actor, Artist...</param> /// <param name="maxWidth">Maximum width for image. <c>0</c> returns image in original size.</param> /// <param name="maxHeight">Maximum height for image. <c>0</c> returns image in original size.</param> /// <param name="singleRandom">If <c>true</c> only one random image URI will be returned</param> /// <param name="result">Result if return code is <c>true</c>.</param> /// <returns><c>true</c> if at least one match was found.</returns> public bool TryGetFanArt(string mediaType, string fanArtType, string name, int maxWidth, int maxHeight, bool singleRandom, out IList <IResourceLocator> result) { result = null; Guid mediaItemId; if (mediaType != FanArtMediaTypes.Actor || (fanArtType != FanArtTypes.Undefined && fanArtType != FanArtTypes.Thumbnail)) { return(false); } // Don't try to load "fanart" for images if (!Guid.TryParse(name, out mediaItemId)) { return(false); } IMediaLibrary mediaLibrary = ServiceRegistration.Get <IMediaLibrary>(false); if (mediaLibrary == null) { return(false); } IFilter filter = new RelationshipFilter(MovieAspect.ROLE_MOVIE, PersonAspect.ROLE_ACTOR, mediaItemId); IList <MediaItem> items = null; List <Guid> necessaryMias = new List <Guid>(NECESSARY_MIAS); MediaItemQuery mediaQuery = new MediaItemQuery(necessaryMias, filter); mediaQuery.Limit = 1; items = mediaLibrary.Search(mediaQuery, false, null, false); if (items == null || items.Count == 0) { return(false); } MediaItem mediaItem = items.First(); // Virtual resources won't have any local fanart if (mediaItem.IsVirtual) { return(false); } var mediaIteamLocator = mediaItem.GetResourceLocator(); var fanArtPaths = new List <ResourcePath>(); var files = new List <IResourceLocator>(); string actorName = null; SingleMediaItemAspect videoAspect; List <string> actors = new List <string>(); if (MediaItemAspect.TryGetAspect(mediaItem.Aspects, VideoAspect.Metadata, out videoAspect)) { IEnumerable <object> actorObjects = videoAspect.GetCollectionAttribute <object>(VideoAspect.ATTR_ACTORS); if (actorObjects != null) { actors.AddRange(actorObjects.Cast <string>()); } } IList <MultipleMediaItemAspect> relationAspects; if (MediaItemAspect.TryGetAspects(mediaItem.Aspects, RelationshipAspect.Metadata, out relationAspects)) { foreach (MultipleMediaItemAspect relation in relationAspects) { if ((Guid?)relation[RelationshipAspect.ATTR_LINKED_ROLE] == PersonAspect.ROLE_ACTOR && (Guid?)relation[RelationshipAspect.ATTR_LINKED_ID] == mediaItemId) { int?index = (int?)relation[RelationshipAspect.ATTR_RELATIONSHIP_INDEX]; if (index.HasValue && actors.Count > index.Value && index.Value >= 0) { actorName = actors[index.Value]; } } } } // File based access try { var mediaItemPath = mediaIteamLocator.NativeResourcePath; var mediaItemDirectoryPath = ResourcePathHelper.Combine(mediaItemPath, "../"); if (!string.IsNullOrEmpty(actorName)) { using (var directoryRa = new ResourceLocator(mediaIteamLocator.NativeSystemId, mediaItemDirectoryPath).CreateAccessor()) { var directoryFsra = directoryRa as IFileSystemResourceAccessor; if (directoryFsra != null) { //Get Artists thumbs IFileSystemResourceAccessor actorMediaItemDirectory = directoryFsra.GetResource(".actors"); if (actorMediaItemDirectory != null) { var potentialArtistFanArtFiles = LocalFanartHelper.GetPotentialFanArtFiles(actorMediaItemDirectory); foreach (ResourcePath thumbPath in from potentialFanArtFile in potentialArtistFanArtFiles let potentialFanArtFileNameWithoutExtension = ResourcePathHelper.GetFileNameWithoutExtension(potentialFanArtFile.ToString()) where potentialFanArtFileNameWithoutExtension.StartsWith(actorName.Replace(" ", "_"), StringComparison.InvariantCultureIgnoreCase) select potentialFanArtFile) { files.Add(new ResourceLocator(mediaIteamLocator.NativeSystemId, thumbPath)); } } } } } } catch (Exception ex) { #if DEBUG ServiceRegistration.Get <ILogger>().Warn("LocalMovieActorFanArtProvider: Error while searching fanart of type '{0}' for '{1}'", ex, fanArtType, mediaIteamLocator); #endif } result = files; return(files.Count > 0); }