protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult <Playlist> result) { var item = result.Item; switch (reader.Name) { case "OwnerUserId": { var userId = reader.ReadElementContentAsString(); if (!item.Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase))) { item.Shares.Add(new Share { UserId = userId, CanEdit = true }); } break; } case "PlaylistMediaType": { item.PlaylistMediaType = reader.ReadElementContentAsString(); break; } case "PlaylistItems": if (!reader.IsEmptyElement) { using (var subReader = reader.ReadSubtree()) { FetchFromCollectionItemsNode(subReader, item); } } else { reader.Read(); } break; case "Shares": if (!reader.IsEmptyElement) { using (var subReader = reader.ReadSubtree()) { FetchFromSharesNode(subReader, item); } } else { reader.Read(); } break; default: base.FetchDataFromXmlNode(reader, result); break; } }
protected override void MergeData(MetadataResult <Photo> source, MetadataResult <Photo> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); }
/// <summary> /// Fetches the specified item. /// </summary> /// <param name="item">The item.</param> /// <param name="metadataFile">The metadata file.</param> /// <param name="settings">The settings.</param> /// <param name="cancellationToken">The cancellation token.</param> protected virtual async Task Fetch(MetadataResult <T> item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken) { if (!SupportsUrlAfterClosingXmlTag) { using (var fileStream = FileSystem.GetFileStream(metadataFile, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read, true)) { using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { // Use XmlReader for best performance using (var reader = XmlReader.Create(streamReader, settings)) { item.ResetPeople(); await reader.MoveToContentAsync().ConfigureAwait(false); await reader.ReadAsync().ConfigureAwait(false); // Loop through each element while (!reader.EOF && reader.ReadState == ReadState.Interactive) { cancellationToken.ThrowIfCancellationRequested(); if (reader.NodeType == XmlNodeType.Element) { await FetchDataFromXmlNode(reader, item).ConfigureAwait(false); } else { await reader.ReadAsync().ConfigureAwait(false); } } } } } return; } using (var fileStream = FileSystem.GetFileStream(metadataFile, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read, true)) { using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { item.ResetPeople(); // Need to handle a url after the xml data // http://kodi.wiki/view/NFO_files/movies var xml = await streamReader.ReadToEndAsync().ConfigureAwait(false); // Find last closing Tag // Need to do this in two steps to account for random > characters after the closing xml var index = xml.LastIndexOf(@"</", StringComparison.Ordinal); // If closing tag exists, move to end of Tag if (index != -1) { index = xml.IndexOf('>', index); } if (index != -1) { var endingXml = xml.Substring(index); ParseProviderLinks(item.Item, endingXml); // If the file is just an imdb url, don't go any further if (index == 0) { return; } xml = xml.Substring(0, index + 1); } else { // If the file is just an Imdb url, handle that ParseProviderLinks(item.Item, xml); return; } // These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions try { using (var stringReader = new StringReader(xml)) { // Use XmlReader for best performance using (var reader = XmlReader.Create(stringReader, settings)) { await reader.MoveToContentAsync().ConfigureAwait(false); await reader.ReadAsync().ConfigureAwait(false); // Loop through each element while (!reader.EOF && reader.ReadState == ReadState.Interactive) { cancellationToken.ThrowIfCancellationRequested(); if (reader.NodeType == XmlNodeType.Element) { await FetchDataFromXmlNode(reader, item).ConfigureAwait(false); } else { await reader.ReadAsync().ConfigureAwait(false); } } } } } catch (XmlException) { } } } }
/// <summary> /// Processes the main info. /// </summary> /// <param name="resultItem">The result item.</param> /// <param name="settings">The settings.</param> /// <param name="preferredCountryCode">The preferred country code.</param> /// <param name="movieData">The movie data.</param> private void ProcessMainInfo(MetadataResult <T> resultItem, TmdbSettingsResult settings, string preferredCountryCode, MovieDbProvider.CompleteMovieData movieData) { var movie = resultItem.Item; movie.Name = movieData.GetTitle() ?? movie.Name; var hasOriginalTitle = movie as IHasOriginalTitle; if (hasOriginalTitle != null) { hasOriginalTitle.OriginalTitle = movieData.GetOriginalTitle(); } // Bug in Mono: WebUtility.HtmlDecode should return null if the string is null but in Mono it generate an System.ArgumentNullException. movie.Overview = movieData.overview != null?WebUtility.HtmlDecode(movieData.overview) : null; movie.Overview = movie.Overview != null?movie.Overview.Replace("\n\n", "\n") : null; movie.HomePageUrl = movieData.homepage; var hasBudget = movie as IHasBudget; if (hasBudget != null) { hasBudget.Budget = movieData.budget; hasBudget.Revenue = movieData.revenue; } if (!string.IsNullOrEmpty(movieData.tagline)) { var hasTagline = movie as IHasTaglines; if (hasTagline != null) { hasTagline.Taglines.Clear(); hasTagline.AddTagline(movieData.tagline); } } if (movieData.production_countries != null) { var hasProductionLocations = movie as IHasProductionLocations; if (hasProductionLocations != null) { hasProductionLocations.ProductionLocations = movieData .production_countries .Select(i => i.name) .ToList(); } } movie.SetProviderId(MetadataProviders.Tmdb, movieData.id.ToString(_usCulture)); movie.SetProviderId(MetadataProviders.Imdb, movieData.imdb_id); if (movieData.belongs_to_collection != null) { movie.SetProviderId(MetadataProviders.TmdbCollection, movieData.belongs_to_collection.id.ToString(CultureInfo.InvariantCulture)); var movieItem = movie as Movie; if (movieItem != null) { movieItem.CollectionName = movieData.belongs_to_collection.name; } } float rating; string voteAvg = movieData.vote_average.ToString(CultureInfo.InvariantCulture); if (float.TryParse(voteAvg, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out rating)) { movie.CommunityRating = rating; } movie.VoteCount = movieData.vote_count; //release date and certification are retrieved based on configured country and we fall back on US if not there and to minimun release date if still no match if (movieData.releases != null && movieData.releases.countries != null) { var releases = movieData.releases.countries.Where(i => !string.IsNullOrWhiteSpace(i.certification)).ToList(); var ourRelease = releases.FirstOrDefault(c => c.iso_3166_1.Equals(preferredCountryCode, StringComparison.OrdinalIgnoreCase)); var usRelease = releases.FirstOrDefault(c => c.iso_3166_1.Equals("US", StringComparison.OrdinalIgnoreCase)); var minimunRelease = releases.OrderBy(c => c.release_date).FirstOrDefault(); if (ourRelease != null) { var ratingPrefix = string.Equals(preferredCountryCode, "us", StringComparison.OrdinalIgnoreCase) ? "" : preferredCountryCode + "-"; movie.OfficialRating = ratingPrefix + ourRelease.certification; } else if (usRelease != null) { movie.OfficialRating = usRelease.certification; } else if (minimunRelease != null) { movie.OfficialRating = minimunRelease.iso_3166_1 + "-" + minimunRelease.certification; } } if (!string.IsNullOrWhiteSpace(movieData.release_date)) { DateTime r; // These dates are always in this exact format if (DateTime.TryParse(movieData.release_date, _usCulture, DateTimeStyles.None, out r)) { movie.PremiereDate = r.ToUniversalTime(); movie.ProductionYear = movie.PremiereDate.Value.Year; } } //studios if (movieData.production_companies != null) { movie.Studios.Clear(); foreach (var studio in movieData.production_companies.Select(c => c.name)) { movie.AddStudio(studio); } } // genres // Movies get this from imdb var genres = movieData.genres ?? new List <MovieDbProvider.GenreItem>(); foreach (var genre in genres.Select(g => g.name)) { movie.AddGenre(genre); } resultItem.ResetPeople(); var tmdbImageUrl = settings.images.base_url + "original"; //Actors, Directors, Writers - all in People //actors come from cast if (movieData.casts != null && movieData.casts.cast != null) { foreach (var actor in movieData.casts.cast.OrderBy(a => a.order)) { var personInfo = new PersonInfo { Name = actor.name.Trim(), Role = actor.character, Type = PersonType.Actor, SortOrder = actor.order }; if (!string.IsNullOrWhiteSpace(actor.profile_path)) { personInfo.ImageUrl = tmdbImageUrl + actor.profile_path; } if (actor.id > 0) { personInfo.SetProviderId(MetadataProviders.Tmdb, actor.id.ToString(CultureInfo.InvariantCulture)); } resultItem.AddPerson(personInfo); } } //and the rest from crew if (movieData.casts != null && movieData.casts.crew != null) { foreach (var person in movieData.casts.crew) { // Normalize this var type = person.department; if (string.Equals(type, "writing", StringComparison.OrdinalIgnoreCase)) { type = PersonType.Writer; } var personInfo = new PersonInfo { Name = person.name.Trim(), Role = person.job, Type = type }; if (!string.IsNullOrWhiteSpace(person.profile_path)) { personInfo.ImageUrl = tmdbImageUrl + person.profile_path; } if (person.id > 0) { personInfo.SetProviderId(MetadataProviders.Tmdb, person.id.ToString(CultureInfo.InvariantCulture)); } resultItem.AddPerson(personInfo); } } if (movieData.keywords != null && movieData.keywords.keywords != null) { var hasTags = movie as IHasKeywords; if (hasTags != null) { hasTags.Keywords = movieData.keywords.keywords.Select(i => i.name).ToList(); } } if (movieData.trailers != null && movieData.trailers.youtube != null && movieData.trailers.youtube.Count > 0) { var hasTrailers = movie as IHasTrailers; if (hasTrailers != null) { hasTrailers.RemoteTrailers = movieData.trailers.youtube.Select(i => new MediaUrl { Url = string.Format("http://www.youtube.com/watch?v={0}", i.source), Name = i.name, VideoSize = string.Equals("hd", i.size, StringComparison.OrdinalIgnoreCase) ? VideoSize.HighDefinition : VideoSize.StandardDefinition }).ToList(); } } }
protected override void Fetch(MetadataResult <Playlist> result, string path, CancellationToken cancellationToken) { new PlaylistXmlParser(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken); }
public static void MergeBaseItemData <T>(MetadataResult <T> sourceResult, MetadataResult <T> targetResult, List <MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings) where T : BaseItem { var source = sourceResult.Item; var target = targetResult.Item; if (source == null) { throw new ArgumentNullException("source"); } if (target == null) { throw new ArgumentNullException("target"); } if (!lockedFields.Contains(MetadataFields.Name)) { if (replaceData || string.IsNullOrEmpty(target.Name)) { // Safeguard against incoming data having an emtpy name if (!string.IsNullOrWhiteSpace(source.Name)) { target.Name = source.Name; } } } if (replaceData || string.IsNullOrEmpty(target.OriginalTitle)) { // Safeguard against incoming data having an emtpy name if (!string.IsNullOrWhiteSpace(source.OriginalTitle)) { target.OriginalTitle = source.OriginalTitle; } } if (replaceData || !target.CommunityRating.HasValue) { target.CommunityRating = source.CommunityRating; } if (replaceData || !target.EndDate.HasValue) { target.EndDate = source.EndDate; } if (!lockedFields.Contains(MetadataFields.Genres)) { if (replaceData || target.Genres.Count == 0) { target.Genres = source.Genres; } } if (replaceData || string.IsNullOrEmpty(target.HomePageUrl)) { target.HomePageUrl = source.HomePageUrl; if (!string.IsNullOrWhiteSpace(target.HomePageUrl) && target.HomePageUrl.IndexOf("http", StringComparison.OrdinalIgnoreCase) != 0) { target.HomePageUrl = "http://" + target.HomePageUrl; } } if (replaceData || !target.IndexNumber.HasValue) { target.IndexNumber = source.IndexNumber; } if (!lockedFields.Contains(MetadataFields.OfficialRating)) { if (replaceData || string.IsNullOrEmpty(target.OfficialRating)) { target.OfficialRating = source.OfficialRating; } } if (replaceData || string.IsNullOrEmpty(target.OfficialRatingDescription)) { target.OfficialRatingDescription = source.OfficialRatingDescription; } if (replaceData || string.IsNullOrEmpty(target.CustomRating)) { target.CustomRating = source.CustomRating; } if (replaceData || string.IsNullOrEmpty(target.Tagline)) { target.Tagline = source.Tagline; } if (!lockedFields.Contains(MetadataFields.Overview)) { if (replaceData || string.IsNullOrEmpty(target.Overview)) { target.Overview = source.Overview; } } if (replaceData || !target.ParentIndexNumber.HasValue) { target.ParentIndexNumber = source.ParentIndexNumber; } if (!lockedFields.Contains(MetadataFields.Cast)) { if (replaceData || targetResult.People == null || targetResult.People.Count == 0) { targetResult.People = sourceResult.People; } } if (replaceData || !target.PremiereDate.HasValue) { target.PremiereDate = source.PremiereDate; } if (replaceData || !target.ProductionYear.HasValue) { target.ProductionYear = source.ProductionYear; } if (!lockedFields.Contains(MetadataFields.Runtime)) { if (replaceData || !target.RunTimeTicks.HasValue) { if (!(target is Audio) && !(target is Video)) { target.RunTimeTicks = source.RunTimeTicks; } } } if (!lockedFields.Contains(MetadataFields.Studios)) { if (replaceData || target.Studios.Count == 0) { target.Studios = source.Studios; } } if (!lockedFields.Contains(MetadataFields.Tags)) { if (replaceData || target.Tags.Count == 0) { target.Tags = source.Tags; } } if (!lockedFields.Contains(MetadataFields.Keywords)) { if (replaceData || target.Keywords.Count == 0) { target.Keywords = source.Keywords; } } if (!lockedFields.Contains(MetadataFields.ProductionLocations)) { if (replaceData || target.ProductionLocations.Count == 0) { target.ProductionLocations = source.ProductionLocations; } } if (replaceData || !target.VoteCount.HasValue) { target.VoteCount = source.VoteCount; } foreach (var id in source.ProviderIds) { var key = id.Key; // Don't replace existing Id's. if (replaceData || !target.ProviderIds.ContainsKey(key)) { target.ProviderIds[key] = id.Value; } } MergeAlbumArtist(source, target, lockedFields, replaceData); MergeMetascore(source, target, lockedFields, replaceData); MergeCriticRating(source, target, lockedFields, replaceData); MergeAwards(source, target, lockedFields, replaceData); MergeTrailers(source, target, lockedFields, replaceData); if (mergeMetadataSettings) { MergeMetadataSettings(source, target); } }
/// <inheritdoc /> public async Task<MetadataResult<MusicVideo>> GetMetadata(MusicVideoInfo info, CancellationToken cancellationToken) { _logger.LogDebug("Get metadata result for {Name}", info.Name); var imvdbId = info.GetProviderId(ImvdbPlugin.ProviderName); var result = new MetadataResult<MusicVideo> { HasMetadata = false }; // IMVDb id not provided, find first result. if (string.IsNullOrEmpty(imvdbId)) { var searchResults = await GetSearchResults(info, cancellationToken) .ConfigureAwait(false); searchResults.FirstOrDefault()?.TryGetProviderId(ImvdbPlugin.ProviderName, out imvdbId); } // No results found, return without populating metadata. if (string.IsNullOrEmpty(imvdbId)) { return result; } // do lookup here by imvdb id var releaseResult = await _imvdbClient.GetVideoIdResultAsync(imvdbId, cancellationToken) .ConfigureAwait(false); if (releaseResult != null) { result.HasMetadata = true; // set properties from data result.Item = new MusicVideo { Name = releaseResult.SongTitle, ProductionYear = releaseResult.Year, Artists = releaseResult.Artists.Select(i => i.Name).ToArray(), ImageInfos = new[] { new ItemImageInfo { Path = releaseResult.Image?.Size1 } } }; foreach (var director in releaseResult.Directors) { result.AddPerson(new PersonInfo { Name = director.Name, ProviderIds = new Dictionary<string, string> { { ImvdbPlugin.ProviderName, director.Id.ToString(CultureInfo.InvariantCulture) }, { ImvdbPlugin.ProviderName + "_slug", director.Url }, }, Type = director.Position }); } result.Item.SetProviderId(ImvdbPlugin.ProviderName, imvdbId); if (!string.IsNullOrEmpty(releaseResult.Url)) { result.Item.SetProviderId(ImvdbPlugin.ProviderName + "_slug", releaseResult.Url); } } return result; }
public async Task Fetch <T>(MetadataResult <T> itemResult, string imdbId, string language, string country, CancellationToken cancellationToken) where T : BaseItem { if (string.IsNullOrWhiteSpace(imdbId)) { throw new ArgumentNullException(nameof(imdbId)); } var item = itemResult.Item; var result = await GetRootObject(imdbId, cancellationToken).ConfigureAwait(false); // Only take the name and rating if the user's language is set to English, since Omdb has no localization if (string.Equals(language, "en", StringComparison.OrdinalIgnoreCase) || _configurationManager.Configuration.EnableNewOmdbSupport) { item.Name = result.Title; if (string.Equals(country, "us", StringComparison.OrdinalIgnoreCase)) { item.OfficialRating = result.Rated; } } if (!string.IsNullOrEmpty(result.Year) && result.Year.Length >= 4 && int.TryParse(result.Year.AsSpan().Slice(0, 4), NumberStyles.Number, _usCulture, out var year) && year >= 0) { item.ProductionYear = year; } var tomatoScore = result.GetRottenTomatoScore(); if (tomatoScore.HasValue) { item.CriticRating = tomatoScore; } if (!string.IsNullOrEmpty(result.imdbVotes) && int.TryParse(result.imdbVotes, NumberStyles.Number, _usCulture, out var voteCount) && voteCount >= 0) { // item.VoteCount = voteCount; } if (!string.IsNullOrEmpty(result.imdbRating) && float.TryParse(result.imdbRating, NumberStyles.Any, _usCulture, out var imdbRating) && imdbRating >= 0) { item.CommunityRating = imdbRating; } if (!string.IsNullOrEmpty(result.Website)) { item.HomePageUrl = result.Website; } if (!string.IsNullOrWhiteSpace(result.imdbID)) { item.SetProviderId(MetadataProvider.Imdb, result.imdbID); } ParseAdditionalMetadata(itemResult, result); }
protected abstract void Fetch(MetadataResult <T> result, string path, CancellationToken cancellationToken);
/// <summary> /// Fetches the data from XML node. /// </summary> /// <param name="reader">The reader.</param> /// <param name="itemResult">The item result.</param> protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult <Episode> itemResult) { var item = itemResult.Item; switch (reader.Name) { case "season": { var number = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(number)) { int num; if (int.TryParse(number, out num)) { item.ParentIndexNumber = num; } } break; } case "episode": { var number = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(number)) { int num; if (int.TryParse(number, out num)) { item.IndexNumber = num; } } break; } case "episodenumberend": { var number = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(number)) { int num; if (int.TryParse(number, out num)) { item.IndexNumberEnd = num; } } break; } case "absolute_number": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { int rval; // int.TryParse is local aware, so it can be probamatic, force us culture if (int.TryParse(val, NumberStyles.Integer, UsCulture, out rval)) { item.AbsoluteEpisodeNumber = rval; } } break; } case "DVD_episodenumber": { var number = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(number)) { float num; if (float.TryParse(number, NumberStyles.Any, UsCulture, out num)) { item.DvdEpisodeNumber = num; } } break; } case "DVD_season": { var number = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(number)) { float num; if (float.TryParse(number, NumberStyles.Any, UsCulture, out num)) { item.DvdSeasonNumber = Convert.ToInt32(num); } } break; } case "airsbefore_episode": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { int rval; // int.TryParse is local aware, so it can be probamatic, force us culture if (int.TryParse(val, NumberStyles.Integer, UsCulture, out rval)) { item.AirsBeforeEpisodeNumber = rval; } } break; } case "airsafter_season": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { int rval; // int.TryParse is local aware, so it can be probamatic, force us culture if (int.TryParse(val, NumberStyles.Integer, UsCulture, out rval)) { item.AirsAfterSeasonNumber = rval; } } break; } case "airsbefore_season": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { int rval; // int.TryParse is local aware, so it can be probamatic, force us culture if (int.TryParse(val, NumberStyles.Integer, UsCulture, out rval)) { item.AirsBeforeSeasonNumber = rval; } } break; } default: base.FetchDataFromXmlNode(reader, itemResult); break; } }
private void ProcessMainInfo(MetadataResult <Series> seriesResult, RootObject seriesInfo, string preferredCountryCode, TmdbSettingsResult settings) { var series = seriesResult.Item; series.Name = seriesInfo.name; series.SetProviderId(MetadataProviders.Tmdb, seriesInfo.id.ToString(_usCulture)); //series.VoteCount = seriesInfo.vote_count; string voteAvg = seriesInfo.vote_average.ToString(CultureInfo.InvariantCulture); if (float.TryParse(voteAvg, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out float rating)) { series.CommunityRating = rating; } series.Overview = seriesInfo.overview; if (seriesInfo.networks != null) { series.Studios = seriesInfo.networks.Select(i => i.name).ToArray(); } if (seriesInfo.genres != null) { series.Genres = seriesInfo.genres.Select(i => i.name).ToArray(); } //series.HomePageUrl = seriesInfo.homepage; series.RunTimeTicks = seriesInfo.episode_run_time.Select(i => TimeSpan.FromMinutes(i).Ticks).FirstOrDefault(); if (string.Equals(seriesInfo.status, "Ended", StringComparison.OrdinalIgnoreCase)) { series.Status = SeriesStatus.Ended; series.EndDate = seriesInfo.last_air_date; } else { series.Status = SeriesStatus.Continuing; } series.PremiereDate = seriesInfo.first_air_date; var ids = seriesInfo.external_ids; if (ids != null) { if (!string.IsNullOrWhiteSpace(ids.imdb_id)) { series.SetProviderId(MetadataProviders.Imdb, ids.imdb_id); } if (ids.tvrage_id > 0) { series.SetProviderId(MetadataProviders.TvRage, ids.tvrage_id.ToString(_usCulture)); } if (ids.tvdb_id > 0) { series.SetProviderId(MetadataProviders.Tvdb, ids.tvdb_id.ToString(_usCulture)); } } var contentRatings = (seriesInfo.content_ratings ?? new ContentRatings()).results ?? new List <ContentRating>(); var ourRelease = contentRatings.FirstOrDefault(c => string.Equals(c.iso_3166_1, preferredCountryCode, StringComparison.OrdinalIgnoreCase)); var usRelease = contentRatings.FirstOrDefault(c => string.Equals(c.iso_3166_1, "US", StringComparison.OrdinalIgnoreCase)); var minimumRelease = contentRatings.FirstOrDefault(); if (ourRelease != null) { series.OfficialRating = ourRelease.rating; } else if (usRelease != null) { series.OfficialRating = usRelease.rating; } else if (minimumRelease != null) { series.OfficialRating = minimumRelease.rating; } if (seriesInfo.videos != null && seriesInfo.videos.results != null) { foreach (var video in seriesInfo.videos.results) { if ((video.type.Equals("trailer", StringComparison.OrdinalIgnoreCase) || video.type.Equals("clip", StringComparison.OrdinalIgnoreCase)) && video.site.Equals("youtube", StringComparison.OrdinalIgnoreCase)) { series.AddTrailerUrl($"http://www.youtube.com/watch?v={video.key}"); } } } seriesResult.ResetPeople(); var tmdbImageUrl = settings.images.GetImageUrl("original"); if (seriesInfo.credits != null && seriesInfo.credits.cast != null) { foreach (var actor in seriesInfo.credits.cast.OrderBy(a => a.order)) { var personInfo = new PersonInfo { Name = actor.name.Trim(), Role = actor.character, Type = PersonType.Actor, SortOrder = actor.order }; if (!string.IsNullOrWhiteSpace(actor.profile_path)) { personInfo.ImageUrl = tmdbImageUrl + actor.profile_path; } if (actor.id > 0) { personInfo.SetProviderId(MetadataProviders.Tmdb, actor.id.ToString(CultureInfo.InvariantCulture)); } seriesResult.AddPerson(personInfo); } } }
public async Task <MetadataResult <Series> > GetMetadata(SeriesInfo info, CancellationToken cancellationToken) { var result = new MetadataResult <Series>(); result.QueriedById = true; var tmdbId = info.GetProviderId(MetadataProviders.Tmdb); if (string.IsNullOrEmpty(tmdbId)) { var imdbId = info.GetProviderId(MetadataProviders.Imdb); if (!string.IsNullOrEmpty(imdbId)) { var searchResult = await FindByExternalId(imdbId, "imdb_id", cancellationToken).ConfigureAwait(false); if (searchResult != null) { tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb); } } } if (string.IsNullOrEmpty(tmdbId)) { var tvdbId = info.GetProviderId(MetadataProviders.Tvdb); if (!string.IsNullOrEmpty(tvdbId)) { var searchResult = await FindByExternalId(tvdbId, "tvdb_id", cancellationToken).ConfigureAwait(false); if (searchResult != null) { tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb); } } } if (string.IsNullOrEmpty(tmdbId)) { result.QueriedById = false; var searchResults = await new MovieDbSearch(_logger, _jsonSerializer, _libraryManager).GetSearchResults(info, cancellationToken).ConfigureAwait(false); var searchResult = searchResults.FirstOrDefault(); if (searchResult != null) { tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb); } } if (!string.IsNullOrEmpty(tmdbId)) { cancellationToken.ThrowIfCancellationRequested(); result = await FetchMovieData(tmdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); result.HasMetadata = result.Item != null; } return(result); }
/// <summary> /// Fetches the data from XML node. /// </summary> /// <param name="reader">The reader.</param> /// <param name="result">The result.</param> protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult <Game> result) { var item = result.Item; switch (reader.Name) { case "GameSystem": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.GameSystem = val; } break; } case "GamesDbId": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.SetProviderId(MetadataProviders.Gamesdb, val); } break; } case "NesBox": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.SetProviderId(MetadataProviders.NesBox, val); } break; } case "NesBoxRom": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.SetProviderId(MetadataProviders.NesBoxRom, val); } break; } case "Players": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { int num; if (int.TryParse(val, NumberStyles.Integer, _usCulture, out num)) { item.PlayersSupported = num; } } break; } default: base.FetchDataFromXmlNode(reader, result); break; } }
public async Task <MetadataResult <Episode> > GetMetadata(EpisodeInfo info, CancellationToken cancellationToken) { var result = new MetadataResult <Episode>(); // Allowing this will dramatically increase scan times if (info.IsMissingEpisode || info.IsVirtualUnaired) { return(result); } string seriesTmdbId; info.SeriesProviderIds.TryGetValue(MetadataProviders.Tmdb.ToString(), out seriesTmdbId); if (string.IsNullOrEmpty(seriesTmdbId)) { return(result); } var seasonNumber = info.ParentIndexNumber; var episodeNumber = info.IndexNumber; if (!seasonNumber.HasValue || !episodeNumber.HasValue) { return(result); } try { var response = await GetEpisodeInfo(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.MetadataLanguage, cancellationToken).ConfigureAwait(false); result.HasMetadata = true; result.QueriedById = true; if (!string.IsNullOrEmpty(response.overview)) { // if overview is non-empty, we can assume that localized data was returned result.ResultLanguage = info.MetadataLanguage; } var item = new Episode(); result.Item = item; item.Name = info.Name; item.IndexNumber = info.IndexNumber; item.ParentIndexNumber = info.ParentIndexNumber; item.IndexNumberEnd = info.IndexNumberEnd; if (response.external_ids.tvdb_id > 0) { item.SetProviderId(MetadataProviders.Tvdb, response.external_ids.tvdb_id.ToString(CultureInfo.InvariantCulture)); } item.PremiereDate = response.air_date; item.ProductionYear = result.Item.PremiereDate.Value.Year; item.Name = response.name; item.Overview = response.overview; item.CommunityRating = (float)response.vote_average; //item.VoteCount = response.vote_count; if (response.videos != null && response.videos.results != null) { foreach (var video in response.videos.results) { if (video.type.Equals("trailer", System.StringComparison.OrdinalIgnoreCase) || video.type.Equals("clip", System.StringComparison.OrdinalIgnoreCase)) { if (video.site.Equals("youtube", System.StringComparison.OrdinalIgnoreCase)) { var videoUrl = string.Format("http://www.youtube.com/watch?v={0}", video.key); item.AddTrailerUrl(videoUrl, true); } } } } result.ResetPeople(); var credits = response.credits; if (credits != null) { //Actors, Directors, Writers - all in People //actors come from cast if (credits.cast != null) { foreach (var actor in credits.cast.OrderBy(a => a.order)) { result.AddPerson(new PersonInfo { Name = actor.name.Trim(), Role = actor.character, Type = PersonType.Actor, SortOrder = actor.order }); } } // guest stars if (credits.guest_stars != null) { foreach (var guest in credits.guest_stars.OrderBy(a => a.order)) { result.AddPerson(new PersonInfo { Name = guest.name.Trim(), Role = guest.character, Type = PersonType.GuestStar, SortOrder = guest.order }); } } //and the rest from crew if (credits.crew != null) { var keepTypes = new[] { PersonType.Director, //PersonType.Writer, //PersonType.Producer }; foreach (var person in credits.crew) { // Normalize this var type = person.department; if (string.Equals(type, "writing", StringComparison.OrdinalIgnoreCase)) { type = PersonType.Writer; } if (!keepTypes.Contains(type ?? string.Empty, StringComparer.OrdinalIgnoreCase) && !keepTypes.Contains(person.job ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { continue; } result.AddPerson(new PersonInfo { Name = person.name.Trim(), Role = person.job, Type = type }); } } } } catch (HttpException ex) { if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) { return(result); } throw; } return(result); }
public async Task <MetadataResult <Movie> > Update(int[] siteNum, string[] sceneID, CancellationToken cancellationToken) { var result = new MetadataResult <Movie>() { Item = new Movie(), People = new List <PersonInfo>(), }; if (sceneID == null) { return(result); } var instanceToken = await GetToken(siteNum, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(instanceToken)) { return(result); } var url = $"{Helper.GetSearchSearchURL(siteNum)}/v2/releases?type={sceneID[1]}&id={sceneID[0]}"; var sceneData = await GetDataFromAPI(url, instanceToken, cancellationToken).ConfigureAwait(false); if (sceneData == null) { return(result); } sceneData = (JObject)sceneData["result"].First; string domain = new Uri(Helper.GetSearchBaseURL(siteNum)).Host.Replace("www.", string.Empty, StringComparison.OrdinalIgnoreCase), sceneTypeURL = sceneID[1]; if (sceneTypeURL.Equals("scene", StringComparison.OrdinalIgnoreCase)) { switch (domain) { case "brazzers.com": sceneTypeURL = "video"; break; } } var sceneURL = Helper.GetSearchBaseURL(siteNum) + $"/{sceneTypeURL}/{sceneID[0]}/"; result.Item.ExternalId = sceneURL; result.Item.Name = (string)sceneData["title"]; result.Item.Overview = (string)sceneData["description"]; result.Item.AddStudio((string)sceneData["brand"]); var sceneDateObj = (DateTime)sceneData["dateReleased"]; result.Item.PremiereDate = sceneDateObj; foreach (var genreLink in sceneData["tags"]) { var genreName = (string)genreLink["name"]; result.Item.AddGenre(genreName); } foreach (var actorLink in sceneData["actors"]) { var actorPageURL = $"{Helper.GetSearchSearchURL(siteNum)}/v1/actors?id={actorLink["id"]}"; var actorData = await GetDataFromAPI(actorPageURL, instanceToken, cancellationToken).ConfigureAwait(false); if (actorData != null) { actorData = (JObject)actorData["result"].First; var actor = new PersonInfo { Name = (string)actorLink["name"], }; if (actorData["images"] != null && actorData["images"].Type == JTokenType.Object) { actor.ImageUrl = (string)actorData["images"]["profile"].First["xs"]["url"]; } result.People.Add(actor); } } return(result); }
private void ParseAdditionalMetadata <T>(MetadataResult <T> itemResult, RootObject result) where T : BaseItem { var item = itemResult.Item; var isConfiguredForEnglish = IsConfiguredForEnglish(item) || _configurationManager.Configuration.EnableNewOmdbSupport; // Grab series genres because IMDb data is better than TVDB. Leave movies alone // But only do it if English is the preferred language because this data will not be localized if (isConfiguredForEnglish && !string.IsNullOrWhiteSpace(result.Genre)) { item.Genres = Array.Empty <string>(); foreach (var genre in result.Genre .Split(',', StringSplitOptions.RemoveEmptyEntries) .Select(i => i.Trim()) .Where(i => !string.IsNullOrWhiteSpace(i))) { item.AddGenre(genre); } } if (isConfiguredForEnglish) { // Omdb is currently English only, so for other languages skip this and let secondary providers fill it in item.Overview = result.Plot; } if (!Plugin.Instance.Configuration.CastAndCrew) { return; } if (!string.IsNullOrWhiteSpace(result.Director)) { var person = new PersonInfo { Name = result.Director.Trim(), Type = PersonType.Director }; itemResult.AddPerson(person); } if (!string.IsNullOrWhiteSpace(result.Writer)) { var person = new PersonInfo { Name = result.Writer.Trim(), Type = PersonType.Writer }; itemResult.AddPerson(person); } if (!string.IsNullOrWhiteSpace(result.Actors)) { var actorList = result.Actors.Split(','); foreach (var actor in actorList) { if (!string.IsNullOrWhiteSpace(actor)) { var person = new PersonInfo { Name = actor.Trim(), Type = PersonType.Actor }; itemResult.AddPerson(person); } } } }
public async Task <MetadataResult <Season> > GetMetadata(SeasonInfo info, CancellationToken cancellationToken) { var result = new MetadataResult <Season>(); info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out string seriesTmdbId); var seasonNumber = info.IndexNumber; if (string.IsNullOrWhiteSpace(seriesTmdbId) || !seasonNumber.HasValue) { return(result); } var seasonResult = await _tmdbClientManager .GetSeasonAsync(Convert.ToInt32(seriesTmdbId, CultureInfo.InvariantCulture), seasonNumber.Value, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken) .ConfigureAwait(false); if (seasonResult == null) { return(result); } result.HasMetadata = true; result.Item = new Season { IndexNumber = seasonNumber, Overview = seasonResult?.Overview }; if (!string.IsNullOrEmpty(seasonResult.ExternalIds?.TvdbId)) { result.Item.SetProviderId(MetadataProvider.Tvdb, seasonResult.ExternalIds.TvdbId); } // TODO why was this disabled? var credits = seasonResult.Credits; if (credits?.Cast != null) { var cast = credits.Cast.OrderBy(c => c.Order).Take(TmdbUtils.MaxCastMembers).ToList(); for (var i = 0; i < cast.Count; i++) { result.AddPerson(new PersonInfo { Name = cast[i].Name.Trim(), Role = cast[i].Character, Type = PersonType.Actor, SortOrder = cast[i].Order }); } } if (credits?.Crew != null) { foreach (var person in credits.Crew) { // Normalize this var type = TmdbUtils.MapCrewToPersonType(person); if (!TmdbUtils.WantedCrewTypes.Contains(type, StringComparer.OrdinalIgnoreCase) && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { continue; } result.AddPerson(new PersonInfo { Name = person.Name.Trim(), Role = person.Job, Type = type }); } } result.Item.PremiereDate = seasonResult.AirDate; result.Item.ProductionYear = seasonResult.AirDate?.Year; return(result); }
private static MetadataResult <Episode> MapEpisodeToResult(EpisodeInfo id, EpisodeRecord episode) { var result = new MetadataResult <Episode> { HasMetadata = true, Item = new Episode { IndexNumber = id.IndexNumber, ParentIndexNumber = id.ParentIndexNumber, IndexNumberEnd = id.IndexNumberEnd, AirsBeforeEpisodeNumber = episode.AirsBeforeEpisode, AirsAfterSeasonNumber = episode.AirsAfterSeason, AirsBeforeSeasonNumber = episode.AirsBeforeSeason, Name = episode.EpisodeName, Overview = episode.Overview, CommunityRating = (float?)episode.SiteRating, } }; result.ResetPeople(); var item = result.Item; item.SetProviderId(MetadataProvider.Tvdb, episode.Id.ToString()); item.SetProviderId(MetadataProvider.Imdb, episode.ImdbId); if (string.Equals(id.SeriesDisplayOrder, "dvd", StringComparison.OrdinalIgnoreCase)) { item.IndexNumber = Convert.ToInt32(episode.DvdEpisodeNumber ?? episode.AiredEpisodeNumber); item.ParentIndexNumber = episode.DvdSeason ?? episode.AiredSeason; } else if (episode.AiredEpisodeNumber.HasValue) { item.IndexNumber = episode.AiredEpisodeNumber; } else if (episode.AiredSeason.HasValue) { item.ParentIndexNumber = episode.AiredSeason; } if (DateTime.TryParse(episode.FirstAired, out var date)) { // dates from tvdb are UTC but without offset or Z item.PremiereDate = date; item.ProductionYear = date.Year; } foreach (var director in episode.Directors) { result.AddPerson(new PersonInfo { Name = director, Type = PersonType.Director }); } // GuestStars is a weird list of names and roles // Example: // 1: Some Actor (Role1 // 2: Role2 // 3: Role3) // 4: Another Actor (Role1 // ... for (var i = 0; i < episode.GuestStars.Length; ++i) { var currentActor = episode.GuestStars[i]; var roleStartIndex = currentActor.IndexOf('('); if (roleStartIndex == -1) { result.AddPerson(new PersonInfo { Type = PersonType.GuestStar, Name = currentActor, Role = string.Empty }); continue; } var roles = new List <string> { currentActor.Substring(roleStartIndex + 1) }; // Fetch all roles for (var j = i + 1; j < episode.GuestStars.Length; ++j) { var currentRole = episode.GuestStars[j]; var roleEndIndex = currentRole.IndexOf(')'); if (roleEndIndex == -1) { roles.Add(currentRole); continue; } roles.Add(currentRole.TrimEnd(')')); // Update the outer index (keep in mind it adds 1 after the iteration) i = j; break; } result.AddPerson(new PersonInfo { Type = PersonType.GuestStar, Name = currentActor.Substring(0, roleStartIndex).Trim(), Role = string.Join(", ", roles) }); } foreach (var writer in episode.Writers) { result.AddPerson(new PersonInfo { Name = writer, Type = PersonType.Writer }); } result.ResultLanguage = episode.Language.EpisodeName; return(result); }
protected virtual void FetchDataFromXmlNode(XmlReader reader, MetadataResult <T> itemResult) { var item = itemResult.Item; switch (reader.Name) { // DateCreated case "dateadded": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { if (DateTime.TryParseExact(val, BaseNfoSaver.DateAddedFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var added)) { item.DateCreated = added.ToUniversalTime(); } else if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out added)) { item.DateCreated = added.ToUniversalTime(); } else { Logger.LogWarning("Invalid Added value found: " + val); } } break; } case "originaltitle": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrEmpty(val)) { item.OriginalTitle = val; } break; } case "title": case "localtitle": item.Name = reader.ReadElementContentAsString(); break; case "criticrating": { var text = reader.ReadElementContentAsString(); if (!string.IsNullOrEmpty(text)) { if (float.TryParse(text, NumberStyles.Any, _usCulture, out var value)) { item.CriticRating = value; } } break; } case "sorttitle": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.ForcedSortName = val; } break; } case "biography": case "plot": case "review": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.Overview = val; } break; } case "language": { var val = reader.ReadElementContentAsString(); item.PreferredMetadataLanguage = val; break; } case "countrycode": { var val = reader.ReadElementContentAsString(); item.PreferredMetadataCountryCode = val; break; } case "lockedfields": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.LockedFields = val.Split('|').Select(i => { if (Enum.TryParse(i, true, out MetadataFields field)) { return((MetadataFields?)field); } return(null); }).Where(i => i.HasValue).Select(i => i.Value).ToArray(); } break; } case "tagline": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.Tagline = val; } break; } case "country": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.ProductionLocations = val.Split('/') .Select(i => i.Trim()) .Where(i => !string.IsNullOrWhiteSpace(i)) .ToArray(); } break; } case "mpaa": { var rating = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(rating)) { item.OfficialRating = rating; } break; } case "customrating": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.CustomRating = val; } break; } case "runtime": { var text = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(text)) { if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, _usCulture, out var runtime)) { item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; } } break; } case "aspectratio": { var val = reader.ReadElementContentAsString(); var hasAspectRatio = item as IHasAspectRatio; if (!string.IsNullOrWhiteSpace(val) && hasAspectRatio != null) { hasAspectRatio.AspectRatio = val; } break; } case "lockdata": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.IsLocked = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); } break; } case "studio": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { //var parts = val.Split('/') // .Select(i => i.Trim()) // .Where(i => !string.IsNullOrWhiteSpace(i)); //foreach (var p in parts) //{ // item.AddStudio(p); //} item.AddStudio(val); } break; } case "director": { var val = reader.ReadElementContentAsString(); foreach (var p in SplitNames(val).Select(v => new PersonInfo { Name = v.Trim(), Type = PersonType.Director })) { if (string.IsNullOrWhiteSpace(p.Name)) { continue; } itemResult.AddPerson(p); } break; } case "credits": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { var parts = val.Split('/').Select(i => i.Trim()) .Where(i => !string.IsNullOrEmpty(i)); foreach (var p in parts.Select(v => new PersonInfo { Name = v.Trim(), Type = PersonType.Writer })) { if (string.IsNullOrWhiteSpace(p.Name)) { continue; } itemResult.AddPerson(p); } } break; } case "writer": { var val = reader.ReadElementContentAsString(); foreach (var p in SplitNames(val).Select(v => new PersonInfo { Name = v.Trim(), Type = PersonType.Writer })) { if (string.IsNullOrWhiteSpace(p.Name)) { continue; } itemResult.AddPerson(p); } break; } case "actor": { if (!reader.IsEmptyElement) { using (var subtree = reader.ReadSubtree()) { var person = GetPersonFromXmlNode(subtree); if (!string.IsNullOrWhiteSpace(person.Name)) { itemResult.AddPerson(person); } } } else { reader.Read(); } break; } case "trailer": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { val = val.Replace("plugin://plugin.video.youtube/?action=play_video&videoid=", BaseNfoSaver.YouTubeWatchUrl, StringComparison.OrdinalIgnoreCase); item.AddTrailerUrl(val); } break; } case "displayorder": { var val = reader.ReadElementContentAsString(); var hasDisplayOrder = item as IHasDisplayOrder; if (hasDisplayOrder != null) { if (!string.IsNullOrWhiteSpace(val)) { hasDisplayOrder.DisplayOrder = val; } } break; } case "year": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { if (int.TryParse(val, out var productionYear) && productionYear > 1850) { item.ProductionYear = productionYear; } } break; } case "rating": { var rating = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(rating)) { // All external meta is saving this as '.' for decimal I believe...but just to be sure if (float.TryParse(rating.Replace(',', '.'), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var val)) { item.CommunityRating = val; } } break; } case "aired": case "formed": case "premiered": case "releasedate": { var formatString = _config.GetNfoConfiguration().ReleaseDateFormat; var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var date) && date.Year > 1850) { item.PremiereDate = date.ToUniversalTime(); item.ProductionYear = date.Year; } } break; } case "enddate": { var formatString = _config.GetNfoConfiguration().ReleaseDateFormat; var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var date) && date.Year > 1850) { item.EndDate = date.ToUniversalTime(); } } break; } case "genre": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { var parts = val.Split('/') .Select(i => i.Trim()) .Where(i => !string.IsNullOrWhiteSpace(i)); foreach (var p in parts) { item.AddGenre(p); } } break; } case "style": case "tag": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { item.AddTag(val); } break; } case "fileinfo": { if (!reader.IsEmptyElement) { using (var subtree = reader.ReadSubtree()) { FetchFromFileInfoNode(subtree, item); } } else { reader.Read(); } break; } default: string readerName = reader.Name; if (_validProviderIds.TryGetValue(readerName, out string providerIdValue)) { var id = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(id)) { item.SetProviderId(providerIdValue, id); } } else { reader.Skip(); } break; } }
protected override void Fetch(MetadataResult <BoxSet> result, string path, CancellationToken cancellationToken) { new BoxSetXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); }
public async Task <MetadataResult <Movie> > GetMetadata(MovieInfo info, CancellationToken cancellationToken) { var tmdbId = info.GetProviderId(MetadataProvider.Tmdb); var imdbId = info.GetProviderId(MetadataProvider.Imdb); if (string.IsNullOrEmpty(tmdbId) && string.IsNullOrEmpty(imdbId)) { // ParseName is required here. // Caller provides the filename with extension stripped and NOT the parsed filename var parsedName = _libraryManager.ParseName(info.Name); var cleanedName = TmdbUtils.CleanName(parsedName.Name); var searchResults = await _tmdbClientManager.SearchMovieAsync(cleanedName, info.Year ?? parsedName.Year ?? 0, info.MetadataLanguage, cancellationToken).ConfigureAwait(false); if (searchResults.Count > 0) { tmdbId = searchResults[0].Id.ToString(CultureInfo.InvariantCulture); } } if (string.IsNullOrEmpty(tmdbId) && !string.IsNullOrEmpty(imdbId)) { var movieResultFromImdbId = await _tmdbClientManager.FindByExternalIdAsync(imdbId, FindExternalSource.Imdb, info.MetadataLanguage, cancellationToken).ConfigureAwait(false); if (movieResultFromImdbId?.MovieResults.Count > 0) { tmdbId = movieResultFromImdbId.MovieResults[0].Id.ToString(CultureInfo.InvariantCulture); } } if (string.IsNullOrEmpty(tmdbId)) { return(new MetadataResult <Movie>()); } var movieResult = await _tmdbClientManager .GetMovieAsync(Convert.ToInt32(tmdbId, CultureInfo.InvariantCulture), info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken) .ConfigureAwait(false); if (movieResult == null) { return(new MetadataResult <Movie>()); } var movie = new Movie { Name = movieResult.Title ?? movieResult.OriginalTitle, OriginalTitle = movieResult.OriginalTitle, Overview = movieResult.Overview?.Replace("\n\n", "\n", StringComparison.InvariantCulture), Tagline = movieResult.Tagline, ProductionLocations = movieResult.ProductionCountries.Select(pc => pc.Name).ToArray() }; var metadataResult = new MetadataResult <Movie> { HasMetadata = true, ResultLanguage = info.MetadataLanguage, Item = movie }; movie.SetProviderId(MetadataProvider.Tmdb, tmdbId); movie.SetProviderId(MetadataProvider.Imdb, movieResult.ImdbId); if (movieResult.BelongsToCollection != null) { movie.SetProviderId(MetadataProvider.TmdbCollection, movieResult.BelongsToCollection.Id.ToString(CultureInfo.InvariantCulture)); movie.CollectionName = movieResult.BelongsToCollection.Name; } movie.CommunityRating = Convert.ToSingle(movieResult.VoteAverage); if (movieResult.Releases?.Countries != null) { var releases = movieResult.Releases.Countries.Where(i => !string.IsNullOrWhiteSpace(i.Certification)).ToList(); var ourRelease = releases.FirstOrDefault(c => string.Equals(c.Iso_3166_1, info.MetadataCountryCode, StringComparison.OrdinalIgnoreCase)); var usRelease = releases.FirstOrDefault(c => string.Equals(c.Iso_3166_1, "US", StringComparison.OrdinalIgnoreCase)); if (ourRelease != null) { movie.OfficialRating = TmdbUtils.BuildParentalRating(ourRelease.Iso_3166_1, ourRelease.Certification); } else if (usRelease != null) { movie.OfficialRating = usRelease.Certification; } } movie.PremiereDate = movieResult.ReleaseDate; movie.ProductionYear = movieResult.ReleaseDate?.Year; if (movieResult.ProductionCompanies != null) { movie.SetStudios(movieResult.ProductionCompanies.Select(c => c.Name)); } var genres = movieResult.Genres; foreach (var genre in genres.Select(g => g.Name)) { movie.AddGenre(genre); } if (movieResult.Keywords?.Keywords != null) { for (var i = 0; i < movieResult.Keywords.Keywords.Count; i++) { movie.AddTag(movieResult.Keywords.Keywords[i].Name); } } if (movieResult.Credits?.Cast != null) { foreach (var actor in movieResult.Credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers)) { var personInfo = new PersonInfo { Name = actor.Name.Trim(), Role = actor.Character, Type = PersonType.Actor, SortOrder = actor.Order }; if (!string.IsNullOrWhiteSpace(actor.ProfilePath)) { personInfo.ImageUrl = _tmdbClientManager.GetProfileUrl(actor.ProfilePath); } if (actor.Id > 0) { personInfo.SetProviderId(MetadataProvider.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture)); } metadataResult.AddPerson(personInfo); } } if (movieResult.Credits?.Crew != null) { var keepTypes = new[] { PersonType.Director, PersonType.Writer, PersonType.Producer }; foreach (var person in movieResult.Credits.Crew) { // Normalize this var type = TmdbUtils.MapCrewToPersonType(person); if (!keepTypes.Contains(type, StringComparison.OrdinalIgnoreCase) && !keepTypes.Contains(person.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { continue; } var personInfo = new PersonInfo { Name = person.Name.Trim(), Role = person.Job, Type = type }; if (!string.IsNullOrWhiteSpace(person.ProfilePath)) { personInfo.ImageUrl = _tmdbClientManager.GetPosterUrl(person.ProfilePath); } if (person.Id > 0) { personInfo.SetProviderId(MetadataProvider.Tmdb, person.Id.ToString(CultureInfo.InvariantCulture)); } metadataResult.AddPerson(personInfo); } } if (movieResult.Videos?.Results != null) { var trailers = new List <MediaUrl>(); for (var i = 0; i < movieResult.Videos.Results.Count; i++) { var video = movieResult.Videos.Results[0]; if (!TmdbUtils.IsTrailerType(video)) { continue; } trailers.Add(new MediaUrl { Url = string.Format(CultureInfo.InvariantCulture, "https://www.youtube.com/watch?v={0}", video.Key), Name = video.Name }); } movie.RemoteTrailers = trailers; } return(metadataResult); }
public async Task <MetadataResult <Movie> > Update(int[] siteNum, string[] sceneID, CancellationToken cancellationToken) { var result = new MetadataResult <Movie>() { Item = new Movie(), People = new List <PersonInfo>(), }; if (sceneID == null) { return(result); } var sceneURL = Helper.Decode(sceneID[0]); if (!sceneURL.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { sceneURL = Helper.GetSearchBaseURL(siteNum) + sceneURL; } var sceneData = await HTML.ElementFromURL(sceneURL, cancellationToken).ConfigureAwait(false); result.Item.ExternalId = sceneURL; var javID = sceneData.SelectSingleText("//dt[text()='DVD ID:']/following-sibling::dd[1]"); if (javID.StartsWith("--", StringComparison.OrdinalIgnoreCase)) { javID = sceneData.SelectSingleText("//dt[text()='Content ID:']/following-sibling::dd[1]"); } if (javID.Contains(" ", StringComparison.OrdinalIgnoreCase)) { javID = javID.Replace(" ", "-", StringComparison.OrdinalIgnoreCase); } result.Item.OriginalTitle = javID.ToUpperInvariant(); result.Item.Name = Decensor(sceneData.SelectSingleText("//cite[@itemprop='name']")); result.Item.Overview = Decensor(sceneData.SelectSingleText("//div[@class='cmn-box-description01']").Replace("Product Description", string.Empty, StringComparison.OrdinalIgnoreCase)); var studio = sceneData.SelectSingleText("//dd[@itemprop='productionCompany']"); if (!string.IsNullOrEmpty(studio)) { result.Item.AddStudio(studio); } var date = sceneData.SelectSingleText("//dd[@itemprop='dateCreated']"); if (!string.IsNullOrEmpty(date)) { date = date .Replace(".", string.Empty, StringComparison.OrdinalIgnoreCase) .Replace(",", string.Empty, StringComparison.OrdinalIgnoreCase) .Replace("Sept", "Sep", StringComparison.OrdinalIgnoreCase) .Replace("June", "Jun", StringComparison.OrdinalIgnoreCase) .Replace("July", "Jul", StringComparison.OrdinalIgnoreCase) .Trim(); if (DateTime.TryParseExact(date, "MMM dd yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out var sceneDateObj)) { result.Item.PremiereDate = sceneDateObj; } } var genreNode = sceneData.SelectNodesSafe("//a[@itemprop='genre']"); foreach (var genreLink in genreNode) { var genreName = genreLink.InnerText; genreName = Decensor(genreName); result.Item.AddGenre(genreName); } var actorsNode = sceneData.SelectNodesSafe("//div[@itemprop='actors']//span[@itemprop='name']"); foreach (var actorLink in actorsNode) { var actorName = actorLink.InnerText; if (actorName != "----") { switch (Plugin.Instance.Configuration.JAVActorNamingStyle) { case JAVActorNamingStyle.JapaneseStyle: actorName = string.Join(" ", actorName.Split().Reverse()); break; } var actor = new PersonInfo { Name = actorName, }; var photoXpath = string.Format(CultureInfo.InvariantCulture, "//div[@id='{0}']//img[contains(@alt, '{1}')]/@src", actorName.Replace(" ", string.Empty, StringComparison.OrdinalIgnoreCase), actorName); var actorPhoto = sceneData.SelectSingleText(photoXpath); if (!actorPhoto.Contains("nowprinting.gif", StringComparison.OrdinalIgnoreCase)) { actor.ImageUrl = actorPhoto; } result.People.Add(actor); } } return(result); }
public async Task <MetadataResult <Movie> > Update(int[] siteNum, string[] sceneID, CancellationToken cancellationToken) { var result = new MetadataResult <Movie>() { Item = new Movie(), People = new List <PersonInfo>(), }; if (sceneID == null) { return(result); } var sceneURL = Helper.Decode(sceneID[0]); var sceneData = await HTML.ElementFromURL(sceneURL, cancellationToken).ConfigureAwait(false); result.Item.ExternalId = sceneURL; result.Item.Name = sceneData.SelectSingleText("//div[contains(@class, 'heading')]//h1"); result.Item.Overview = sceneData.SelectSingleText("//p[@itemprop='description']"); result.Item.AddStudio("Caribbeancom"); var movieSpecNodes = sceneData.SelectNodes("//li[@class='movie-spec' or @class='movie-detail__spec']"); if (movieSpecNodes != null) { foreach (var movieSpec in movieSpecNodes) { var movieSpecTitle = movieSpec.SelectSingleText(".//span[@class='spec-title']").Replace(":", string.Empty, StringComparison.OrdinalIgnoreCase).Trim(); switch (movieSpecTitle) { case "Release Date": var date = movieSpec.SelectSingleText(".//span[@class='spec-content']").Replace("/", "-", StringComparison.OrdinalIgnoreCase); if (DateTime.TryParseExact(date, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var sceneDateObj)) { result.Item.PremiereDate = sceneDateObj; } break; case "Tags": var genreNode = movieSpec.SelectNodes(".//span[@class='spec-content']/a"); if (genreNode != null) { foreach (var genreLink in genreNode) { var genreName = genreLink.InnerText; result.Item.AddGenre(genreName); } } break; case "Starring": var actorsNode = movieSpec.SelectNodes(".//span[@class='spec-content']/a"); if (actorsNode != null) { foreach (var actorLink in actorsNode) { var actorName = actorLink.InnerText; if (Plugin.Instance.Configuration.JAVActorNamingStyle == JAVActorNamingStyle.JapaneseStyle) { actorName = string.Join(" ", actorName.Split().Reverse()); } var actor = new PersonInfo { Name = actorName, }; result.People.Add(actor); } } break; } } } return(result); }
protected virtual async Task FetchDataFromXmlNode(XmlReader reader, MetadataResult <T> itemResult) { var item = itemResult.Item; switch (reader.Name) { // DateCreated case "dateadded": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(val)) { DateTimeOffset added; if (DateTimeOffset.TryParseExact(val, BaseNfoSaver.DateAddedFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out added)) { item.DateCreated = added.ToUniversalTime(); } else if (DateTimeOffset.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out added)) { item.DateCreated = added.ToUniversalTime(); } else { Logger.Warn("Invalid Added value found: " + val); } } break; } case "uniqueid": { // ID's from multiple scraper sites eg IMDB, TVDB, TMDB-TV Shows var type = reader.GetAttribute("type"); var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(type) && !string.IsNullOrWhiteSpace(val) && IsProviderIdValid(val)) { if (string.Equals(type, "TMDB-TV", StringComparison.OrdinalIgnoreCase)) { type = MetadataProviders.Tmdb.ToString(); } else { foreach (var enumType in Enum.GetNames(typeof(MetadataProviders))) { if (string.Equals(type, enumType.ToString(), StringComparison.OrdinalIgnoreCase)) { type = enumType.ToString(); } } } item.SetProviderId(type, val); } break; } case "originaltitle": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(val)) { item.OriginalTitle = val; } break; } case "title": case "localtitle": item.Name = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); break; case "criticrating": { var text = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(text)) { float value; if (float.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out value)) { item.CriticRating = value; } } break; } case "sorttitle": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(val)) { item.SortName = val; } break; } case "biography": case "plot": case "review": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(val)) { item.Overview = val; } break; } case "language": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); item.PreferredMetadataLanguage = val; break; } case "countrycode": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); item.PreferredMetadataCountryCode = val; break; } case "lockedfields": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(val)) { item.LockedFields = val.Split('|').Select(i => { MetadataFields field; if (Enum.TryParse <MetadataFields>(i, true, out field)) { return((MetadataFields?)field); } return(null); }).Where(i => i.HasValue).Select(i => i.Value).ToArray(); } break; } case "tagline": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(val)) { item.Tagline = val; } break; } case "placeofbirth": case "country": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(val)) { var productionLocations = val.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries) .Select(i => i.Trim()) .Where(i => !string.IsNullOrWhiteSpace(i)) .ToArray(); AddProductionLocations(item, productionLocations); } break; } case "mpaa": { var rating = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(rating)) { item.OfficialRating = rating; } break; } case "customrating": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(val)) { item.CustomRating = val; } break; } case "runtime": { var text = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(text)) { int runtime; if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out runtime)) { item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks; } } break; } case "lockdata": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); item.IsLocked = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); break; } case "studio": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(val)) { //var parts = val.Split('/') // .Select(i => i.Trim()) // .Where(i => !string.IsNullOrWhiteSpace(i)); //foreach (var p in parts) //{ // item.AddStudio(p); //} item.AddStudio(val); } break; } case "director": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); foreach (var p in SplitNames(val).Select(v => new PersonInfo { Name = v.Trim(), Type = PersonType.Director })) { if (string.IsNullOrWhiteSpace(p.Name)) { continue; } itemResult.AddPerson(p); } break; } case "credits": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(val)) { var parts = val.Split('/').Select(i => i.Trim()) .Where(i => !string.IsNullOrEmpty(i)); foreach (var p in parts.Select(v => new PersonInfo { Name = v.Trim(), Type = PersonType.Writer })) { if (string.IsNullOrWhiteSpace(p.Name)) { continue; } itemResult.AddPerson(p); } } break; } case "writer": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); foreach (var p in SplitNames(val).Select(v => new PersonInfo { Name = v.Trim(), Type = PersonType.Writer })) { if (string.IsNullOrWhiteSpace(p.Name)) { continue; } itemResult.AddPerson(p); } break; } case "actor": { if (!reader.IsEmptyElement) { using (var subtree = reader.ReadSubtree()) { var person = await GetPersonFromXmlNode(subtree).ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(person.Name)) { itemResult.AddPerson(person); } } } else { await reader.ReadAsync().ConfigureAwait(false); } break; } case "trailer": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(val)) { val = val.Replace("plugin://plugin.video.youtube/?action=play_video&videoid=", BaseNfoSaver.YouTubeWatchUrl, StringComparison.OrdinalIgnoreCase).Replace("plugin://plugin.video.youtube/play/?video_id=", BaseNfoSaver.YouTubeWatchUrl, StringComparison.OrdinalIgnoreCase); item.AddTrailerUrl(val); } break; } case "year": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(val)) { int productionYear; if (int.TryParse(val, out productionYear) && productionYear > 1850) { item.ProductionYear = productionYear; } } break; } case "rating": { var rating = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(rating)) { float val; // All external meta is saving this as '.' for decimal I believe...but just to be sure if (float.TryParse(rating.Replace(',', '.'), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out val)) { item.CommunityRating = val; } } break; } case "aired": case "formed": case "premiered": case "releasedate": { var formatString = _config.GetNfoConfiguration().ReleaseDateFormat; var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(val)) { DateTime date; if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out date) && date.Year > 1850) { item.PremiereDate = date.ToUniversalTime(); item.ProductionYear = date.Year; } } break; } case "enddate": { var formatString = _config.GetNfoConfiguration().ReleaseDateFormat; var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(val)) { DateTime date; if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out date) && date.Year > 1850) { item.EndDate = date.ToUniversalTime(); } } break; } case "genre": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrEmpty(val)) { var parts = val.Split('/') .Select(i => i.Trim()) .Where(i => !string.IsNullOrWhiteSpace(i)); foreach (var p in parts) { item.AddGenre(p); } } break; } case "style": case "tag": { var val = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(val)) { item.AddTag(val); } break; } case "fileinfo": { if (!reader.IsEmptyElement) { using (var subtree = reader.ReadSubtree()) { await FetchFromFileInfoNode(subtree, item).ConfigureAwait(false); } } else { await reader.ReadAsync().ConfigureAwait(false); } break; } case "ratings": { if (!reader.IsEmptyElement) { using (var subtree = reader.ReadSubtree()) { await FetchFromRatingsNode(subtree, item).ConfigureAwait(false); } } else { await reader.ReadAsync().ConfigureAwait(false); } break; } case "set": { var tmdbcolid = reader.GetAttribute("tmdbcolid"); var linkedItemInfo = new LinkedItemInfo(); if (!string.IsNullOrWhiteSpace(tmdbcolid)) { linkedItemInfo.SetProviderId(MetadataProviders.Tmdb, tmdbcolid); } var val = await reader.ReadInnerXmlAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(val)) { // TODO Handle this better later if (val.IndexOf('<') == -1) { linkedItemInfo.Name = val; } else { try { linkedItemInfo.Name = await ParseSetXml(val).ConfigureAwait(false); } catch (Exception ex) { Logger.ErrorException("Error parsing set node", ex); } } if (!string.IsNullOrWhiteSpace(linkedItemInfo.Name)) { item.AddCollection(linkedItemInfo); } } break; } default: string readerName = reader.Name; string providerIdValue; if (_validProviderIds.TryGetValue(readerName, out providerIdValue)) { var id = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(id) && IsProviderIdValid(id)) { item.SetProviderId(providerIdValue, id); } } else { await reader.SkipAsync().ConfigureAwait(false); } break; } }
public async Task <MetadataResult <Season> > GetMetadata(SeasonInfo info, CancellationToken cancellationToken) { var result = new MetadataResult <Season>(); info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out string seriesTmdbId); var seasonNumber = info.IndexNumber; if (!string.IsNullOrWhiteSpace(seriesTmdbId) && seasonNumber.HasValue) { try { var seasonInfo = await GetSeasonInfo(seriesTmdbId, seasonNumber.Value, info.MetadataLanguage, cancellationToken) .ConfigureAwait(false); result.HasMetadata = true; result.Item = new Season(); // Don't use moviedb season names for now until if/when we have field-level configuration // result.Item.Name = seasonInfo.name; result.Item.Name = info.Name; result.Item.IndexNumber = seasonNumber; result.Item.Overview = seasonInfo.Overview; if (seasonInfo.External_Ids.Tvdb_Id > 0) { result.Item.SetProviderId(MetadataProvider.Tvdb, seasonInfo.External_Ids.Tvdb_Id.ToString(CultureInfo.InvariantCulture)); } var credits = seasonInfo.Credits; if (credits != null) { // Actors, Directors, Writers - all in People // actors come from cast if (credits.Cast != null) { // foreach (var actor in credits.cast.OrderBy(a => a.order)) result.Item.AddPerson(new PersonInfo { Name = actor.name.Trim(), Role = actor.character, Type = PersonType.Actor, SortOrder = actor.order }); } // and the rest from crew if (credits.Crew != null) { // foreach (var person in credits.crew) result.Item.AddPerson(new PersonInfo { Name = person.name.Trim(), Role = person.job, Type = person.department }); } } result.Item.PremiereDate = seasonInfo.Air_Date; result.Item.ProductionYear = result.Item.PremiereDate.Value.Year; } catch (HttpException ex) { _logger.LogError(ex, "No metadata found for {0}", seasonNumber.Value); if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) { return(result); } throw; } } return(result); }
public async Task <MetadataResult <Person> > GetMetadata(PersonLookupInfo id, CancellationToken cancellationToken) { var tmdbId = id.GetProviderId(MetadataProviders.Tmdb); // We don't already have an Id, need to fetch it if (string.IsNullOrEmpty(tmdbId)) { tmdbId = await GetTmdbId(id, cancellationToken).ConfigureAwait(false); } var result = new MetadataResult <Person>(); if (!string.IsNullOrEmpty(tmdbId)) { try { await EnsurePersonInfo(tmdbId, cancellationToken).ConfigureAwait(false); } catch (HttpException ex) { if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) { return(result); } throw; } var dataFilePath = GetPersonDataFilePath(_configurationManager.ApplicationPaths, tmdbId); var info = _jsonSerializer.DeserializeFromFile <PersonResult>(dataFilePath); var item = new Person(); result.HasMetadata = true; // Take name from incoming info, don't rename the person // TODO: This should go in PersonMetadataService, not each person provider item.Name = id.Name; //item.HomePageUrl = info.homepage; if (!string.IsNullOrWhiteSpace(info.Place_Of_Birth)) { item.ProductionLocations = new string[] { info.Place_Of_Birth }; } item.Overview = info.Biography; if (DateTime.TryParseExact(info.Birthday, "yyyy-MM-dd", new CultureInfo("en-US"), DateTimeStyles.None, out var date)) { item.PremiereDate = date.ToUniversalTime(); } if (DateTime.TryParseExact(info.Deathday, "yyyy-MM-dd", new CultureInfo("en-US"), DateTimeStyles.None, out date)) { item.EndDate = date.ToUniversalTime(); } item.SetProviderId(MetadataProviders.Tmdb, info.Id.ToString(_usCulture)); if (!string.IsNullOrEmpty(info.Imdb_Id)) { item.SetProviderId(MetadataProviders.Imdb, info.Imdb_Id); } result.HasMetadata = true; result.Item = item; } return(result); }
private void MapSeriesToResult(MetadataResult <Series> result, TvDbSharper.Dto.Series tvdbSeries, string metadataLanguage) { Series series = result.Item; series.SetProviderId(MetadataProviders.Tvdb, tvdbSeries.Id.ToString()); series.Name = tvdbSeries.SeriesName; series.Overview = (tvdbSeries.Overview ?? string.Empty).Trim(); result.ResultLanguage = metadataLanguage; series.AirDays = TVUtils.GetAirDays(tvdbSeries.AirsDayOfWeek); series.AirTime = tvdbSeries.AirsTime; series.CommunityRating = (float?)tvdbSeries.SiteRating; series.SetProviderId(MetadataProviders.Imdb, tvdbSeries.ImdbId); series.SetProviderId(MetadataProviders.Zap2It, tvdbSeries.Zap2itId); if (Enum.TryParse(tvdbSeries.Status, true, out SeriesStatus seriesStatus)) { series.Status = seriesStatus; } if (DateTime.TryParse(tvdbSeries.FirstAired, out var date)) { // dates from tvdb are UTC but without offset or Z series.PremiereDate = date; series.ProductionYear = date.Year; } series.RunTimeTicks = TimeSpan.FromMinutes(Convert.ToDouble(tvdbSeries.Runtime)).Ticks; foreach (var genre in tvdbSeries.Genre) { series.AddGenre(genre); } if (!string.IsNullOrEmpty(tvdbSeries.Network)) { series.AddStudio(tvdbSeries.Network); } if (result.Item.Status.HasValue && result.Item.Status.Value == SeriesStatus.Ended) { try { var episodeSummary = _tvDbClientManager .GetSeriesEpisodeSummaryAsync(tvdbSeries.Id, metadataLanguage, CancellationToken.None).Result.Data; var maxSeasonNumber = episodeSummary.AiredSeasons.Select(s => Convert.ToInt32(s)).Max(); var episodeQuery = new EpisodeQuery { AiredSeason = maxSeasonNumber }; var episodesPage = _tvDbClientManager.GetEpisodesPageAsync(tvdbSeries.Id, episodeQuery, metadataLanguage, CancellationToken.None).Result.Data; result.Item.EndDate = episodesPage.Select(e => { DateTime.TryParse(e.FirstAired, out var firstAired); return(firstAired); }).Max(); } catch (TvDbServerException e) { _logger.LogError(e, "Failed to find series end date for series {TvdbId}", tvdbSeries.Id); } } }
/// <inheritdoc /> public async Task <MetadataResult <MusicAlbum> > GetMetadata(AlbumInfo id, CancellationToken cancellationToken) { var releaseId = id.GetReleaseId(); var releaseGroupId = id.GetReleaseGroupId(); var result = new MetadataResult <MusicAlbum> { Item = new MusicAlbum() }; // TODO maybe remove when artist metadata can be disabled if (!Plugin.Instance.Configuration.Enable) { return(result); } // If we have a release group Id but not a release Id... if (string.IsNullOrWhiteSpace(releaseId) && !string.IsNullOrWhiteSpace(releaseGroupId)) { releaseId = await GetReleaseIdFromReleaseGroupId(releaseGroupId, cancellationToken).ConfigureAwait(false); result.HasMetadata = true; } if (string.IsNullOrWhiteSpace(releaseId)) { var artistMusicBrainzId = id.GetMusicBrainzArtistId(); var releaseResult = await GetReleaseResult(artistMusicBrainzId, id.GetAlbumArtist(), id.Name, cancellationToken).ConfigureAwait(false); if (releaseResult != null) { if (!string.IsNullOrWhiteSpace(releaseResult.ReleaseId)) { releaseId = releaseResult.ReleaseId; result.HasMetadata = true; } if (!string.IsNullOrWhiteSpace(releaseResult.ReleaseGroupId)) { releaseGroupId = releaseResult.ReleaseGroupId; result.HasMetadata = true; } result.Item.ProductionYear = releaseResult.Year; result.Item.Overview = releaseResult.Overview; } } // If we have a release Id but not a release group Id... if (!string.IsNullOrWhiteSpace(releaseId) && string.IsNullOrWhiteSpace(releaseGroupId)) { releaseGroupId = await GetReleaseGroupFromReleaseId(releaseId, cancellationToken).ConfigureAwait(false); result.HasMetadata = true; } if (!string.IsNullOrWhiteSpace(releaseId) || !string.IsNullOrWhiteSpace(releaseGroupId)) { result.HasMetadata = true; } if (result.HasMetadata) { if (!string.IsNullOrEmpty(releaseId)) { result.Item.SetProviderId(MetadataProviders.MusicBrainzAlbum, releaseId); } if (!string.IsNullOrEmpty(releaseGroupId)) { result.Item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, releaseGroupId); } } return(result); }
protected override void MergeData(MetadataResult <MusicGenre> source, MetadataResult <MusicGenre> target, List <MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); }
public ActionResult GetMetadata(string id) { ElmcityApp.logger.LogHttpRequest(this.ControllerContext); MetadataResult r = null; try { r = new MetadataResult(id); } catch (Exception e) { GenUtils.PriorityLogMsg("exception", "GetMetadata: " + id, e.Message); } return r; }
/// <inheritdoc /> public async Task <MetadataResult <Series> > GetMetadata(SeriesInfo info, CancellationToken cancellationToken) { try { _logger.LogDebug("[GetMetadata] Starting for {name}", info.Name); var tvMazeClient = new TvMazeClient(_httpClientFactory.CreateClient(NamedClient.Default), new RetryRateLimitingStrategy()); var result = new MetadataResult <Series>(); var tvMazeId = TvHelpers.GetTvMazeId(info.ProviderIds); Show?tvMazeShow = null; if (tvMazeId.HasValue) { // Search by TVMaze id. tvMazeShow = await tvMazeClient.Shows.GetShowMainInformationAsync(tvMazeId.Value).ConfigureAwait(false); } if (tvMazeShow == null && info.ProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out var imdbId) && !string.IsNullOrEmpty(imdbId)) { // Lookup by imdb id. tvMazeShow = await tvMazeClient.Lookup.GetShowByImdbIdAsync(imdbId).ConfigureAwait(false); } if (tvMazeShow == null && info.ProviderIds.TryGetValue(MetadataProvider.TvRage.ToString(), out var tvRageId) && !string.IsNullOrEmpty(tvRageId)) { // Lookup by tv rage id. var id = Convert.ToInt32(tvRageId, CultureInfo.InvariantCulture); tvMazeShow = await tvMazeClient.Lookup.GetShowByTvRageIdAsync(id).ConfigureAwait(false); } if (tvMazeShow == null && info.ProviderIds.TryGetValue(MetadataProvider.Tvdb.ToString(), out var tvdbId) && !string.IsNullOrEmpty(tvdbId)) { var id = Convert.ToInt32(tvdbId, CultureInfo.InvariantCulture); tvMazeShow = await tvMazeClient.Lookup.GetShowByTheTvdbIdAsync(id).ConfigureAwait(false); } if (tvMazeShow == null) { // Series still not found, search by name. var parsedName = _libraryManager.ParseName(info.Name); _logger.LogDebug("[GetMetadata] No TVMaze Id, searching by parsed name: {@name}", parsedName); tvMazeShow = await GetIdentifyShow(parsedName, tvMazeClient).ConfigureAwait(false); } if (tvMazeShow == null) { // Invalid TVMaze id. _logger.LogDebug("[GetMetadata] No TVMaze result found for {name}", info.Name); return(result); } var series = new Series(); series.Name = tvMazeShow.Name; series.Genres = tvMazeShow.Genres.ToArray(); if (!string.IsNullOrWhiteSpace(tvMazeShow.Network?.Name)) { var networkName = tvMazeShow.Network.Name; if (!string.IsNullOrWhiteSpace(tvMazeShow.Network?.Country?.Code)) { networkName = $"{tvMazeShow.Network.Name} ({tvMazeShow.Network.Country.Code})"; } series.Studios = new[] { networkName }; } if (DateTime.TryParse(tvMazeShow.Premiered, out var premiereDate)) { series.PremiereDate = premiereDate; series.ProductionYear = premiereDate.Year; } if (tvMazeShow.Rating?.Average != null) { series.CommunityRating = (float?)tvMazeShow.Rating.Average; } if (tvMazeShow.Runtime.HasValue) { series.RunTimeTicks = TimeSpan.FromMinutes(tvMazeShow.Runtime.Value).Ticks; } if (string.Equals(tvMazeShow.Status, "Running", StringComparison.OrdinalIgnoreCase)) { series.Status = SeriesStatus.Continuing; } else if (string.Equals(tvMazeShow.Status, "Ended", StringComparison.OrdinalIgnoreCase)) { series.Status = SeriesStatus.Ended; } series.Overview = TvHelpers.GetStrippedHtml(tvMazeShow.Summary); series.HomePageUrl = tvMazeShow.Url; SetProviderIds(tvMazeShow, series); // Set cast. var castMembers = await tvMazeClient.Shows.GetShowCastAsync(tvMazeShow.Id).ConfigureAwait(false); foreach (var castMember in castMembers) { var personInfo = new PersonInfo(); personInfo.SetProviderId(TvMazePlugin.ProviderId, castMember.Person.Id.ToString(CultureInfo.InvariantCulture)); personInfo.Name = castMember.Person.Name; personInfo.Role = castMember.Character.Name; personInfo.Type = PersonType.Actor; personInfo.ImageUrl = castMember.Person.Image?.Original ?? castMember.Person.Image?.Medium; result.AddPerson(personInfo); } result.Item = series; result.HasMetadata = true; _logger.LogDebug("[GetMetadata] Metadata result: {@series}", tvMazeShow); return(result); } catch (Exception e) { _logger.LogWarning(e, "[GetMetadata]"); return(new MetadataResult <Series>()); } }