Пример #1
0
        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;
            }
        }
Пример #2
0
 protected override void MergeData(MetadataResult <Photo> source, MetadataResult <Photo> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings)
 {
     ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
 }
Пример #3
0
        /// <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)
                    {
                    }
                }
            }
        }
Пример #4
0
        /// <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();
                }
            }
        }
Пример #5
0
 protected override void Fetch(MetadataResult <Playlist> result, string path, CancellationToken cancellationToken)
 {
     new PlaylistXmlParser(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken);
 }
Пример #6
0
        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);
            }
        }
Пример #7
0
    /// <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;
    }
Пример #8
0
        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);
        }
Пример #9
0
 protected abstract void Fetch(MetadataResult <T> result, string path, CancellationToken cancellationToken);
Пример #10
0
        /// <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;
            }
        }
Пример #11
0
        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);
                }
            }
        }
Пример #12
0
        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);
        }
Пример #13
0
        /// <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;
            }
        }
Пример #14
0
        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);
        }
Пример #16
0
        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);
                    }
                }
            }
        }
Пример #17
0
        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);
        }
Пример #18
0
        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);
        }
Пример #19
0
        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;
            }
        }
Пример #20
0
 protected override void Fetch(MetadataResult <BoxSet> result, string path, CancellationToken cancellationToken)
 {
     new BoxSetXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken);
 }
Пример #21
0
        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);
        }
Пример #23
0
        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);
        }
Пример #24
0
        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;
            }
        }
Пример #25
0
        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);
        }
Пример #26
0
        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);
        }
Пример #27
0
        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);
                }
            }
        }
Пример #28
0
        /// <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);
        }
Пример #29
0
 protected override void MergeData(MetadataResult <MusicGenre> source, MetadataResult <MusicGenre> target, List <MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
 {
     ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
 }
Пример #30
0
        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;
        }
Пример #31
0
        /// <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>());
            }
        }