/// <summary> /// Gets a <see cref="FanArtPathCollection"/> containing all matching season fanart paths in the specified <see cref="ResourcePath"/>. /// </summary> /// <param name="seasonDirectory"><see cref="IFileSystemResourceAccessor"/> that points to the season directory.</param> /// <param name="seasonNumber">Season number.</param> /// <returns><see cref="FanArtPathCollection"/> containing all matching paths.</returns> protected FanArtPathCollection GetSeasonFolderFanArt(IFileSystemResourceAccessor seasonDirectory, int?seasonNumber, bool isSeriesFolder) { FanArtPathCollection paths = new FanArtPathCollection(); if (seasonDirectory == null) { return(paths); } List <ResourcePath> potentialFanArtFiles = LocalFanartHelper.GetPotentialFanArtFiles(seasonDirectory); if (!isSeriesFolder) { ExtractAllFanArtImages(potentialFanArtFiles, paths); if (!seasonNumber.HasValue || !seasonDirectory.ResourceExists("../")) { return(paths); } //Try and populate any missing fanart from the series directory using (IFileSystemResourceAccessor seriesDirectory = seasonDirectory.GetResource("../")) potentialFanArtFiles = LocalFanartHelper.GetPotentialFanArtFiles(seriesDirectory); } GetAdditionalSeasonFolderFanArt(paths, potentialFanArtFiles, seasonNumber); return(paths); }
/// <summary> /// Gets a <see cref="FanArtPathCollection"/> containing all matching fanart paths in the specified <see cref="ResourcePath"/>. /// </summary> /// <param name="albumDirectory"><see cref="IFileSystemResourceAccessor"/> that points to the album directory.</param> /// <returns><see cref="FanArtPathCollection"/> containing all matching paths.</returns> protected FanArtPathCollection GetAlbumFolderFanArt(IFileSystemResourceAccessor albumDirectory) { FanArtPathCollection paths = new FanArtPathCollection(); if (albumDirectory == null) { return(paths); } //Get all fanart in the current directory List <ResourcePath> potentialFanArtFiles = LocalFanartHelper.GetPotentialFanArtFiles(albumDirectory); ExtractAllFanArtImages(potentialFanArtFiles, paths); //Add extra backdrops in ExtraFanArt directory if (albumDirectory.ResourceExists("ExtraFanArt/")) { using (IFileSystemResourceAccessor extraFanArtDirectory = albumDirectory.GetResource("ExtraFanArt/")) paths.AddRange(FanArtTypes.FanArt, LocalFanartHelper.GetPotentialFanArtFiles(extraFanArtDirectory)); } List <ResourcePath> covers; //Albums store posters as covers so switch the fanart type if (paths.Paths.TryGetValue(FanArtTypes.Poster, out covers)) { paths.Paths.Remove(FanArtTypes.Poster); paths.AddRange(FanArtTypes.Cover, covers); } return(paths); }
private IEnumerable <ResourcePath> GetCollectionFanart(string fanArtType, IFileSystemResourceAccessor directoryFsra) { var fanArtPaths = new List <ResourcePath>(); if (directoryFsra != null) { var potentialFanArtFiles = LocalFanartHelper.GetPotentialFanArtFiles(directoryFsra); if (fanArtType == FanArtTypes.Poster || fanArtType == FanArtTypes.Thumbnail) { fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByName(potentialFanArtFiles, LocalFanartHelper.THUMB_FILENAMES.Select(f => "movieset-" + f))); fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByName(potentialFanArtFiles, LocalFanartHelper.POSTER_FILENAMES.Select(f => "movieset-" + f))); fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByName(potentialFanArtFiles, LocalFanartHelper.THUMB_FILENAMES)); fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByName(potentialFanArtFiles, LocalFanartHelper.POSTER_FILENAMES)); } if (fanArtType == FanArtTypes.Banner) { fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByName(potentialFanArtFiles, LocalFanartHelper.BANNER_FILENAMES.Select(f => "movieset-" + f))); fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByName(potentialFanArtFiles, LocalFanartHelper.BANNER_FILENAMES)); } if (fanArtType == FanArtTypes.Logo) { fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByName(potentialFanArtFiles, LocalFanartHelper.LOGO_FILENAMES.Select(f => "movieset-" + f))); fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByName(potentialFanArtFiles, LocalFanartHelper.LOGO_FILENAMES)); } if (fanArtType == FanArtTypes.ClearArt) { fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByName(potentialFanArtFiles, LocalFanartHelper.CLEARART_FILENAMES.Select(f => "movieset-" + f))); fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByName(potentialFanArtFiles, LocalFanartHelper.CLEARART_FILENAMES)); } if (fanArtType == FanArtTypes.FanArt) { fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByPrefix(potentialFanArtFiles, LocalFanartHelper.BACKDROP_FILENAMES.Select(f => "movieset-" + f))); fanArtPaths.AddRange(LocalFanartHelper.FilterPotentialFanArtFilesByPrefix(potentialFanArtFiles, LocalFanartHelper.BACKDROP_FILENAMES)); if (directoryFsra.ResourceExists("ExtraFanArt/")) { using (var extraFanArtDirectoryFsra = directoryFsra.GetResource("ExtraFanArt/")) fanArtPaths.AddRange(LocalFanartHelper.GetPotentialFanArtFiles(extraFanArtDirectoryFsra)); } } } return(fanArtPaths); }
/// <summary> /// Gets a <see cref="FanArtPathCollection"/> containing all matching series fanart paths in the specified <see cref="ResourcePath"/>. /// </summary> /// <param name="seriesDirectory"><see cref="IFileSystemResourceAccessor"/> that points to the series directory.</param> /// <returns><see cref="FanArtPathCollection"/> containing all matching paths.</returns> protected FanArtPathCollection GetSeriesFolderFanArt(IFileSystemResourceAccessor seriesDirectory) { FanArtPathCollection paths = new FanArtPathCollection(); if (seriesDirectory != null) { List <ResourcePath> potentialFanArtFiles = LocalFanartHelper.GetPotentialFanArtFiles(seriesDirectory); ExtractAllFanArtImages(potentialFanArtFiles, paths); if (seriesDirectory.ResourceExists("ExtraFanArt/")) { using (IFileSystemResourceAccessor extraFanArtDirectory = seriesDirectory.GetResource("ExtraFanArt/")) paths.AddRange(FanArtTypes.FanArt, LocalFanartHelper.GetPotentialFanArtFiles(extraFanArtDirectory)); } } return(paths); }
public bool IsDirectorySingleResource(IResourceAccessor mediaItemAccessor) { IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor; if (fsra == null) { return(false); } if (!fsra.IsFile && fsra.ResourceExists("BDMV")) { using (IFileSystemResourceAccessor fsraBDMV = fsra.GetResource("BDMV")) { if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv")) { // Video Blu-ray return(true); } } } return(false); }
/// <summary> /// Gets a <see cref="FanArtPathCollection"/> containing all matching fanart paths in the specified <see cref="ResourcePath"/>. /// </summary> /// <param name="artistDirectory"><see cref="IFileSystemResourceAccessor"/> that points to the artist directory.</param> /// <returns><see cref="FanArtPathCollection"/> containing all matching paths.</returns> protected FanArtPathCollection GetArtistFolderFanArt(IFileSystemResourceAccessor artistDirectory) { FanArtPathCollection paths = new FanArtPathCollection(); if (artistDirectory == null) { return(paths); } //Get all fanart in the current directory List <ResourcePath> potentialFanArtFiles = LocalFanartHelper.GetPotentialFanArtFiles(artistDirectory); ExtractAllFanArtImages(potentialFanArtFiles, paths); //Add extra backdrops in ExtraFanArt directory if (artistDirectory.ResourceExists("ExtraFanArt/")) { using (IFileSystemResourceAccessor extraFanArtDirectory = artistDirectory.GetResource("ExtraFanArt/")) paths.AddRange(FanArtTypes.FanArt, LocalFanartHelper.GetPotentialFanArtFiles(extraFanArtDirectory)); } return(paths); }
/// <summary> /// Gets a <see cref="FanArtPathCollection"/> containing all matching fanart paths in the specified <see cref="ResourcePath"/>. /// </summary> /// <param name="videoDirectory"><see cref="IFileSystemResourceAccessor"/> that points to the episode directory.</param> /// <param name="filename">The file name of the media item to extract images for.</param> /// <returns><see cref="FanArtPathCollection"/> containing all matching paths.</returns> protected FanArtPathCollection GetFolderFanArt(IFileSystemResourceAccessor videoDirectory, string filename, IDictionary <Guid, IList <MediaItemAspect> > aspects) { FanArtPathCollection paths = new FanArtPathCollection(); if (videoDirectory == null) { return(paths); } //Get all fanart in the current directory List <ResourcePath> potentialFanArtFiles = LocalFanartHelper.GetPotentialFanArtFiles(videoDirectory); ExtractAllFanArtImages(potentialFanArtFiles, paths, filename); //Add extra backdrops in ExtraFanArt directory if (videoDirectory.ResourceExists("ExtraFanArt/")) { using (IFileSystemResourceAccessor extraFanArtDirectory = videoDirectory.GetResource("ExtraFanArt/")) paths.AddRange(FanArtTypes.FanArt, LocalFanartHelper.GetPotentialFanArtFiles(extraFanArtDirectory)); } return(paths); }
static UPnPError OnConcatenatePaths(DvAction action, IList <object> inParams, out IList <object> outParams, CallContext context) { outParams = null; ResourcePath path = ResourcePath.Deserialize((string)inParams[0]); string relativePathStr = (string)inParams[1]; IResourceAccessor ra; if (!path.TryCreateLocalResourceAccessor(out ra)) { return(new UPnPError(600, "The given path is not accessible")); } string serializedPath = null; using (ra) { IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor; if (fsra != null) { IFileSystemResourceAccessor ra2 = fsra.GetResource(relativePathStr); if (ra2 != null) { using (ra2) serializedPath = ra2.CanonicalLocalResourcePath.Serialize(); } } else { return(new UPnPError(600, "The given paths cannot be concatenated")); } } outParams = new List <object> { serializedPath }; return(null); }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { try { VideoResult result = null; IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor; if (fsra != null && fsra.IsDirectory && fsra.ResourceExists("VIDEO_TS")) { IFileSystemResourceAccessor fsraVideoTs = fsra.GetResource("VIDEO_TS"); if (fsraVideoTs != null && fsraVideoTs.ResourceExists("VIDEO_TS.IFO")) { // Video DVD using (MediaInfoWrapper videoTsInfo = ReadMediaInfo(fsraVideoTs.GetResource("VIDEO_TS.IFO"))) { if (!videoTsInfo.IsValid || videoTsInfo.GetVideoCount() == 0) { return(false); // Invalid video_ts.ifo file } result = VideoResult.CreateDVDInfo(fsra.ResourceName, videoTsInfo); } // Iterate over all video files; MediaInfo finds different audio/video metadata for each .ifo file ICollection <IFileSystemResourceAccessor> files = fsraVideoTs.GetFiles(); if (files != null) { foreach (IFileSystemResourceAccessor file in files) { string lowerPath = (file.ResourcePathName ?? string.Empty).ToLowerInvariant(); if (!lowerPath.EndsWith(".ifo") || lowerPath.EndsWith("video_ts.ifo")) { continue; } using (MediaInfoWrapper mediaInfo = ReadMediaInfo(file)) { // Before we start evaluating the file, check if it is a video at all if (mediaInfo.IsValid && mediaInfo.GetVideoCount() == 0) { continue; } result.AddMediaInfo(mediaInfo); } } } } } else if (mediaItemAccessor.IsFile) { string filePath = mediaItemAccessor.ResourcePathName; if (!HasVideoExtension(filePath)) { return(false); } using (MediaInfoWrapper fileInfo = ReadMediaInfo(mediaItemAccessor)) { // Before we start evaluating the file, check if it is a video at all if (!fileInfo.IsValid || (fileInfo.GetVideoCount() == 0 && !IsWorkaroundRequired(filePath))) { return(false); } string mediaTitle = DosPathHelper.GetFileNameWithoutExtension(mediaItemAccessor.ResourceName); result = VideoResult.CreateFileInfo(mediaTitle, fileInfo); } using (Stream stream = mediaItemAccessor.OpenRead()) result.MimeType = MimeTypeDetector.GetMimeType(stream); } if (result != null) { result.UpdateMetadata(extractedAspectData); ILocalFsResourceAccessor disposeLfsra = null; try { ILocalFsResourceAccessor lfsra = mediaItemAccessor as ILocalFsResourceAccessor; if (lfsra == null && !forceQuickMode) { // In case forceQuickMode, we only want local browsing IResourceAccessor ra = mediaItemAccessor.Clone(); try { lfsra = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(ra); disposeLfsra = lfsra; // Remember to dispose the extra resource accessor instance } catch (Exception) { ra.Dispose(); } } if (lfsra != null) { string localFsPath = lfsra.LocalFileSystemPath; ExtractMatroskaTags(localFsPath, extractedAspectData, forceQuickMode); ExtractThumbnailData(localFsPath, extractedAspectData, forceQuickMode); } } finally { if (disposeLfsra != null) { disposeLfsra.Dispose(); } } return(true); } } catch (Exception e) { // Only log at the info level here - And simply return false. This lets the caller know that we // couldn't perform our task here. ServiceRegistration.Get <ILogger>().Info("VideoMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message); } return(false); }
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); using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor)) { ILocalFsResourceAccessor lfsra = rah.LocalFsResourceAccessor; if (lfsra != null) { MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SIZE, lfsra.Size); MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, lfsra.LastChanged); ExtractMatroskaTags(lfsra, extractedAspectData, forceQuickMode); ExtractMp4Tags(lfsra, extractedAspectData, forceQuickMode); ExtractThumbnailData(lfsra, extractedAspectData, forceQuickMode); } return(true); } } } catch (Exception e) { // Only log at the info level here - And simply return false. This lets the caller know that we // couldn't perform our task here. ServiceRegistration.Get <ILogger>().Info("VideoMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message); } return(false); }
/// <summary> /// 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); }
public async Task <MetadataContainer> ParseMediaItemAsync(MediaItem media, int?editionId = null, bool cache = true) { try { if (media.IsStub) { return(null); } string category = null; MetadataContainer info = null; //Check for live items if (media.Aspects.ContainsKey(AudioAspect.ASPECT_ID)) { category = AUDIO_CATEGORY; if (media.IsLiveRadioItem() && media is LiveTvMediaItem ltmi) { info = await ParseSlimTvItemAsync(ltmi).ConfigureAwait(false); if (info != null) { info.Metadata[Editions.DEFAULT_EDITION].Live = true; info.Metadata[Editions.DEFAULT_EDITION].Size = 0; } return(info); } } else if (media.Aspects.ContainsKey(VideoAspect.ASPECT_ID)) { category = VIDEO_CATEGORY; if (media.IsLiveTvItem() && media is LiveTvMediaItem ltmi) { info = await ParseSlimTvItemAsync(ltmi).ConfigureAwait(false); if (info != null) { info.Metadata[Editions.DEFAULT_EDITION].Live = true; info.Metadata[Editions.DEFAULT_EDITION].Size = 0; } return(info); } } else if (media.Aspects.ContainsKey(ImageAspect.ASPECT_ID)) { category = IMAGE_CATEGORY; } info = await LoadAnalysisAsync(media, category, media.MediaItemId); if (info != null) { return(info); } IList <MultipleMediaItemAspect> providerAspects; if (!MediaItemAspect.TryGetAspects(media.Aspects, ProviderResourceAspect.Metadata, out providerAspects)) { return(null); } IDictionary <int, ResourceLocator> resources = null; if (media.HasEditions) { IEnumerable <int> praIdxs = null; if (editionId.HasValue) { praIdxs = media.Editions.First(e => e.Key == editionId.Value).Value.PrimaryResourceIndexes; } else { praIdxs = media.Editions.SelectMany(e => e.Value.PrimaryResourceIndexes).Distinct(); } resources = providerAspects.Where(pra => praIdxs.Contains(pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX))). ToDictionary(pra => pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX), pra => new ResourceLocator(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_SYSTEM_ID), ResourcePath.Deserialize(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH)))); } else { resources = providerAspects.Where(pra => pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_PRIMARY). ToDictionary(pra => pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX), pra => new ResourceLocator(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_SYSTEM_ID), ResourcePath.Deserialize(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH)))); } //Process media resources Dictionary <int, Dictionary <int, IResourceAccessor> > editions = new Dictionary <int, Dictionary <int, IResourceAccessor> >(); foreach (var res in resources) { int edition = Editions.DEFAULT_EDITION; if (media.HasEditions) { edition = media.Editions.FirstOrDefault(e => e.Value.PrimaryResourceIndexes.Contains(res.Key)).Value.SetNo; } if (!editions.ContainsKey(edition)) { editions.Add(edition, new Dictionary <int, IResourceAccessor>()); } IResourceAccessor mia = res.Value.CreateAccessor(); if (mia is IFileSystemResourceAccessor fileRes && !fileRes.IsFile) { if (fileRes.ResourceExists("VIDEO_TS")) { using (IFileSystemResourceAccessor fsraVideoTs = fileRes.GetResource("VIDEO_TS")) { if (fsraVideoTs != null && fsraVideoTs.ResourceExists("VIDEO_TS.IFO")) { //Find all titles and add each of them var titles = GetDvdTitleFiles(fsraVideoTs); foreach (var title in titles) { int fileNo = 0; foreach (var file in title.Value) { fileNo++; int titleKey = MetadataContainer.GetDvdResource(res.Key, title.Key, fileNo); editions[edition].Add(titleKey, file); } } } } } else if (fileRes.ResourceExists("BDMV")) { using (IFileSystemResourceAccessor fsraBDMV = fileRes.GetResource("BDMV")) { if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv") && fsraBDMV.ResourceExists("STREAM")) { using (IFileSystemResourceAccessor fsraStream = fsraBDMV.GetResource("STREAM")) { var orderedFileList = fsraStream.GetFiles().Where(f => f.ResourceName.EndsWith(".m2ts", StringComparison.InvariantCultureIgnoreCase)).OrderByDescending(f => f.Size); //Use the largest file which is probably the main stream var mainStream = orderedFileList.First(); editions[edition].Add(res.Key, mainStream); } } } } } else { editions[edition].Add(res.Key, mia); } mia.Dispose(); }