public static async Task <string> TryMatchTmdbIdAsync(ILocalFsResourceAccessor folderOrFileLfsra) { // Calling EnsureLocalFileSystemAccess not necessary; only string operation string extensionLower = StringUtils.TrimToEmpty(Path.GetExtension(folderOrFileLfsra.LocalFileSystemPath)).ToLower(); if (!MatroskaConsts.MATROSKA_VIDEO_EXTENSIONS.Contains(extensionLower)) { return(null); } MatroskaBinaryReader mkvReader = new MatroskaBinaryReader(folderOrFileLfsra); // Add keys to be extracted to tags dictionary, matching results will returned as value Dictionary <string, IList <string> > tagsToExtract = MatroskaConsts.DefaultVideoTags; await mkvReader.ReadTagsAsync(tagsToExtract).ConfigureAwait(false); if (tagsToExtract[MatroskaConsts.TAG_MOVIE_TMDB_ID] != null) { foreach (string candidate in tagsToExtract[MatroskaConsts.TAG_MOVIE_TMDB_ID]) { if (int.TryParse(candidate, out int tmdbIdInt)) { return(tmdbIdInt.ToString()); } } } return(null); }
public void TestMatroskaBinaryStereoscopicInfo() { // Arrange MatroskaBinaryReader matroskaInfoReader = GetMatroskaBinaryFileReader(); // Act MatroskaConsts.StereoMode actualStereoMode = matroskaInfoReader.ReadStereoModeAsync().Result; // Assert Assert.AreEqual(MatroskaConsts.StereoMode.SBSLeftEyeFirst, actualStereoMode); }
public void TestMatroskaBinaryAttachmentInfo() { // Arrange MatroskaBinaryReader matroskaInfoReader = GetMatroskaBinaryFileReader(); // Act matroskaInfoReader.ReadAttachmentsAsync().Wait(); // Assert Assert.IsTrue(matroskaInfoReader.GetAttachmentByNameAsync("cover.").Result.Length > 0); Assert.IsTrue(matroskaInfoReader.GetAttachmentByNameAsync("banner.").Result.Length > 0); Assert.IsTrue(matroskaInfoReader.GetAttachmentByNameAsync("poster.").Result.Length > 0); Assert.IsTrue(matroskaInfoReader.GetAttachmentByNameAsync("fanart.").Result.Length > 0); Assert.IsTrue(matroskaInfoReader.GetAttachmentByNameAsync("clearart.").Result.Length > 0); Assert.IsTrue(matroskaInfoReader.GetAttachmentByNameAsync("clearlogo.").Result.Length > 0); }
public void TestMatroskaBinaryTagInfo() { // Arrange MatroskaBinaryReader matroskaInfoReader = GetMatroskaBinaryFileReader(); var tags = MatroskaConsts.DefaultVideoTags; // Act matroskaInfoReader.ReadTagsAsync(tags).Wait(); // Assert Assert.AreEqual("Test Title", tags[MatroskaConsts.TAG_SIMPLE_TITLE].First()); Assert.AreEqual("Doctor Who", tags[MatroskaConsts.TAG_SERIES_TITLE].First()); Assert.AreEqual("76107", tags[MatroskaConsts.TAG_SERIES_TVDB_ID].First()); Assert.IsTrue(tags[MatroskaConsts.TAG_EPISODE_SUMMARY].First().Length > 0); Assert.AreEqual("1963-11-23", tags[MatroskaConsts.TAG_EPISODE_YEAR].First()); Assert.AreEqual("Doctor Who", tags[MatroskaConsts.TAG_EPISODE_TITLE].First()); Assert.AreEqual("1", tags[MatroskaConsts.TAG_EPISODE_NUMBER].First()); Assert.AreEqual("tt0056751", tags[MatroskaConsts.TAG_MOVIE_IMDB_ID].First()); }
/// <summary> /// Reads all mkv tag images and caches them in the <see cref="IFanArtCache"/> service. /// </summary> /// <param name="lfsra"><see cref="ILocalFsResourceAccessor>"/> for the file.</param> /// <param name="mediaItemId">Id of the media item.</param> /// <param name="title">Title of the media item.</param> /// <returns><see cref="Task"/> that completes when the images have been cached.</returns> protected async Task ExtractMkvFanArt(ILocalFsResourceAccessor lfsra, Guid mediaItemId, string title) { if (lfsra == null) { return; } MatroskaBinaryReader mkvReader = new MatroskaBinaryReader(lfsra); IFanArtCache fanArtCache = ServiceRegistration.Get <IFanArtCache>(); foreach (var pattern in MKV_PATTERNS) { byte[] binaryData = await mkvReader.GetAttachmentByNameAsync(pattern.Item1).ConfigureAwait(false); if (binaryData == null) { continue; } string filename = pattern + Path.GetFileNameWithoutExtension(lfsra.LocalFileSystemPath); await fanArtCache.TrySaveFanArt(mediaItemId, title, pattern.Item2, p => TrySaveFileImage(binaryData, p, filename)).ConfigureAwait(false); } }
public bool TryGetFanArt(string mediaType, string fanArtType, string name, int maxWidth, int maxHeight, bool singleRandom, out IList <FanArtImage> result) { result = null; Guid mediaItemId; if (!Guid.TryParse(name, out mediaItemId)) { return(false); } IMediaLibrary mediaLibrary = ServiceRegistration.Get <IMediaLibrary>(false); if (mediaLibrary == null) { return(false); } IFilter filter = new MediaItemIdFilter(mediaItemId); IList <MediaItem> items = mediaLibrary.Search(new MediaItemQuery(NECESSARY_MIAS, filter), false, null, true); 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 resourceLocator = mediaItem.GetResourceLocator(); string fileSystemPath = string.Empty; IList <string> patterns = new List <string>(); switch (fanArtType) { case FanArtTypes.Banner: patterns.Add("banner."); break; case FanArtTypes.ClearArt: patterns.Add("clearart."); break; case FanArtTypes.Poster: case FanArtTypes.Thumbnail: patterns.Add("cover."); patterns.Add("poster."); patterns.Add("folder."); break; case FanArtTypes.FanArt: patterns.Add("backdrop."); patterns.Add("fanart."); break; case FanArtTypes.Logo: patterns.Add("clearlogo."); break; default: return(false); } // File based access try { using (var accessor = resourceLocator?.CreateAccessor()) { ILocalFsResourceAccessor fsra = accessor as ILocalFsResourceAccessor; if (fsra != null) { var ext = Path.GetExtension(fsra.LocalFileSystemPath); if (!SUPPORTED_EXTENSIONS.Contains(ext)) { return(false); } MatroskaBinaryReader mkvReader = new MatroskaBinaryReader(fsra); foreach (string pattern in patterns) { byte[] binaryData = mkvReader.GetAttachmentByNameAsync(pattern).Result; if (binaryData != null) { result = new List <FanArtImage> { new FanArtImage(name, binaryData) }; return(true); } } } } } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Warn("MkvAttachmentsProvider: Exception while reading mkv attachment of type '{0}' from '{1}'", ex, fanArtType, fileSystemPath); } return(false); }
public static async Task <bool> ExtractFromTagsAsync(ILocalFsResourceAccessor folderOrFileLfsra, MovieInfo movieInfo) { // Calling EnsureLocalFileSystemAccess not necessary; only string operation string extensionLower = StringUtils.TrimToEmpty(Path.GetExtension(folderOrFileLfsra.LocalFileSystemPath)).ToLower(); if (!MatroskaConsts.MATROSKA_VIDEO_EXTENSIONS.Contains(extensionLower)) { return(false); } // Try to get extended information out of matroska files) MatroskaBinaryReader mkvReader = new MatroskaBinaryReader(folderOrFileLfsra); // Add keys to be extracted to tags dictionary, matching results will returned as value Dictionary <string, IList <string> > tagsToExtract = MatroskaConsts.DefaultVideoTags; await mkvReader.ReadTagsAsync(tagsToExtract).ConfigureAwait(false); // Read plot IList <string> tags = tagsToExtract[MatroskaConsts.TAG_EPISODE_SUMMARY]; string plot = tags != null?tags.FirstOrDefault() : string.Empty; if (!string.IsNullOrEmpty(plot)) { movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateString(ref movieInfo.Summary, plot, true); } // Read genre tags = tagsToExtract[MatroskaConsts.TAG_SERIES_GENRE]; if (tags != null) { List <GenreInfo> genreList = tags.Where(s => !string.IsNullOrEmpty(s?.Trim())).Select(s => new GenreInfo { Name = s.Trim() }).ToList(); movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateList(movieInfo.Genres, genreList, movieInfo.Genres.Count == 0); } // Read actors tags = tagsToExtract[MatroskaConsts.TAG_ACTORS]; if (tags != null) { movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateList(movieInfo.Actors, tags.Select(t => new PersonInfo() { Name = t, Occupation = PersonAspect.OCCUPATION_ACTOR, MediaName = movieInfo.MovieName.Text }).ToList(), false); } tags = tagsToExtract[MatroskaConsts.TAG_DIRECTORS]; if (tags != null) { movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateList(movieInfo.Directors, tags.Select(t => new PersonInfo() { Name = t, Occupation = PersonAspect.OCCUPATION_DIRECTOR, MediaName = movieInfo.MovieName.Text }).ToList(), false); } tags = tagsToExtract[MatroskaConsts.TAG_WRITTEN_BY]; if (tags != null) { movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateList(movieInfo.Writers, tags.Select(t => new PersonInfo() { Name = t, Occupation = PersonAspect.OCCUPATION_WRITER, MediaName = movieInfo.MovieName.Text }).ToList(), false); } if (tagsToExtract[MatroskaConsts.TAG_MOVIE_IMDB_ID] != null) { string imdbId; foreach (string candidate in tagsToExtract[MatroskaConsts.TAG_MOVIE_IMDB_ID]) { if (ImdbIdMatcher.TryMatchImdbId(candidate, out imdbId)) { movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateId(ref movieInfo.ImdbId, imdbId); break; } } } if (tagsToExtract[MatroskaConsts.TAG_MOVIE_TMDB_ID] != null) { int tmp; foreach (string candidate in tagsToExtract[MatroskaConsts.TAG_MOVIE_TMDB_ID]) { if (int.TryParse(candidate, out tmp) == true) { movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateId(ref movieInfo.MovieDbId, tmp); break; } } } return(true); }
/// <summary> /// Tries to match series by reading matroska tags from <paramref name="folderOrFileLfsra"/>. /// </summary> /// <param name="folderOrFileLfsra"><see cref="ILocalFsResourceAccessor"/> to file or folder</param> /// <param name="episodeInfo">Returns the parsed EpisodeInfo</param> /// <param name="extractedAspectData">Dictionary containing a mapping of media item aspect ids to /// already present media item aspects, this metadata extractor should edit. If a media item aspect is not present /// in this dictionary but found by this metadata extractor, it will add it to the dictionary.</param> /// <returns><c>true</c> if successful.</returns> public async Task <bool> MatchSeriesAsync(ILocalFsResourceAccessor folderOrFileLfsra, EpisodeInfo episodeInfo) { // Calling EnsureLocalFileSystemAccess not necessary; only string operation string extensionLower = StringUtils.TrimToEmpty(Path.GetExtension(folderOrFileLfsra.LocalFileSystemPath)).ToLower(); if (!MatroskaConsts.MATROSKA_VIDEO_EXTENSIONS.Contains(extensionLower)) { return(false); } MatroskaBinaryReader mkvReader = new MatroskaBinaryReader(folderOrFileLfsra); // Add keys to be extracted to tags dictionary, matching results will returned as value Dictionary <string, IList <string> > tagsToExtract = MatroskaConsts.DefaultVideoTags; await mkvReader.ReadTagsAsync(tagsToExtract).ConfigureAwait(false); IList <string> tags = tagsToExtract[MatroskaConsts.TAG_EPISODE_SUMMARY]; string plot = tags != null?tags.FirstOrDefault() : string.Empty; if (!string.IsNullOrEmpty(plot)) { episodeInfo.HasChanged |= MetadataUpdater.SetOrUpdateString(ref episodeInfo.Summary, plot, true); } // Series and episode handling. Prefer information from tags. if (tagsToExtract[MatroskaConsts.TAG_EPISODE_TITLE] != null) { string title = tagsToExtract[MatroskaConsts.TAG_EPISODE_TITLE].FirstOrDefault(); if (!string.IsNullOrEmpty(title)) { title = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(title); episodeInfo.HasChanged |= MetadataUpdater.SetOrUpdateString(ref episodeInfo.EpisodeName, title, true); } } if (tagsToExtract[MatroskaConsts.TAG_SERIES_TITLE] != null) { string title = tagsToExtract[MatroskaConsts.TAG_SERIES_TITLE].FirstOrDefault(); if (!string.IsNullOrEmpty(title)) { title = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(title); episodeInfo.HasChanged |= MetadataUpdater.SetOrUpdateString(ref episodeInfo.SeriesName, title, true); } } if (tagsToExtract[MatroskaConsts.TAG_SERIES_IMDB_ID] != null) { string imdbId; foreach (string candidate in tagsToExtract[MatroskaConsts.TAG_SERIES_IMDB_ID]) { if (ImdbIdMatcher.TryMatchImdbId(candidate, out imdbId)) { episodeInfo.HasChanged |= MetadataUpdater.SetOrUpdateId(ref episodeInfo.SeriesImdbId, imdbId); break; } } } if (tagsToExtract[MatroskaConsts.TAG_SERIES_ACTORS] != null) { episodeInfo.HasChanged |= MetadataUpdater.SetOrUpdateList(episodeInfo.Actors, tagsToExtract[MatroskaConsts.TAG_SERIES_ACTORS].Select(t => new PersonInfo() { Name = t, Occupation = PersonAspect.OCCUPATION_ACTOR, MediaName = episodeInfo.EpisodeName.Text, ParentMediaName = episodeInfo.SeriesName.Text }).ToList(), false); } // On Series, the counting tag is "TVDB" if (tagsToExtract[MatroskaConsts.TAG_SERIES_TVDB_ID] != null) { int tmp; foreach (string candidate in tagsToExtract[MatroskaConsts.TAG_SERIES_TVDB_ID]) { if (int.TryParse(candidate, out tmp) == true) { episodeInfo.HasChanged |= MetadataUpdater.SetOrUpdateId(ref episodeInfo.SeriesTvdbId, tmp); break; } } } int tmpInt; if (tagsToExtract[MatroskaConsts.TAG_SEASON_NUMBER] != null && int.TryParse(tagsToExtract[MatroskaConsts.TAG_SEASON_NUMBER].FirstOrDefault(), out tmpInt)) { episodeInfo.HasChanged |= MetadataUpdater.SetOrUpdateValue(ref episodeInfo.SeasonNumber, tmpInt); } if (tagsToExtract[MatroskaConsts.TAG_EPISODE_NUMBER] != null) { int episodeNum; foreach (string s in tagsToExtract[MatroskaConsts.TAG_EPISODE_NUMBER]) { if (int.TryParse(s, out episodeNum)) { if (!episodeInfo.EpisodeNumbers.Contains(episodeNum)) { episodeInfo.EpisodeNumbers.Add(episodeNum); } } } } return(true); }