예제 #1
0
 public void UpdateSeries(CachedSeriesInfo si)
 {
     lock (SERIES_LOCK)
     {
         Series[si.TmdbCode] = si;
     }
 }
예제 #2
0
        public void AddBanners(int seriesId, IEnumerable <Banner> seriesBanners)
        {
            lock (SERIES_LOCK)
            {
                if (Series.ContainsKey(seriesId))
                {
                    foreach (Banner b in seriesBanners)
                    {
                        if (!Series.ContainsKey(b.SeriesId))
                        {
                            throw new SourceConsistencyException(
                                      $"Can't find the cachedSeries to add the banner {b.BannerId} to (TheTVDB). {seriesId},{b.SeriesId}", TVDoc.ProviderType.TMDB);
                        }

                        CachedSeriesInfo ser = Series[b.SeriesId];

                        ser.AddOrUpdateBanner(b);
                    }

                    Series[seriesId].BannersLoaded = true;
                }
                else
                {
                    LOGGER.Warn($"Banners were found for cachedSeries {seriesId} - Ignoring them.");
                }
            }
        }
예제 #3
0
        private int EpisodeAccuracyCheck([NotNull] CachedSeriesInfo si, [NotNull] JToken t)
        {
            long serverUpdateTime = (long)t["lastUpdated"];
            int  epId             = (int)t["id"];

            try
            {
                Episode ep = si.GetEpisode(epId);

                if (serverUpdateTime != ep.SrvLastUpdated)
                {
                    ep.Dirty = true;
                    EnsureUpdated(si);
                    string diff = serverUpdateTime > ep.SrvLastUpdated ? "not up to date" : "in the future";
                    Issues.Add(
                        $"{si.Name} S{ep.AiredSeasonNumber}E{ep.AiredEpNum} is {diff}: Local is {DateTimeOffset.FromUnixTimeSeconds(ep.SrvLastUpdated)} ({ep.SrvLastUpdated}) server is {DateTimeOffset.FromUnixTimeSeconds(serverUpdateTime)} ({serverUpdateTime})");
                }
            }
            catch (ShowConfiguration.EpisodeNotFoundException)
            {
                Issues.Add(
                    $"{si.Name} {epId} is not found: Local is missing; server is {serverUpdateTime}");

                EnsureUpdated(si);
            }

            return(epId);
        }
예제 #4
0
 private void EnsureUpdated(CachedSeriesInfo si)
 {
     si.Dirty = true;
     if (!ShowsToUpdate.Contains(si))
     {
         ShowsToUpdate.Add(si);
     }
 }
예제 #5
0
        public bool GetUpdates(bool showErrorMsgBox, CancellationToken cts, IEnumerable <SeriesSpecifier> ss)
        {
            Say("Validating TVmaze cache");
            foreach (SeriesSpecifier downloadShow in ss.Where(downloadShow => !HasSeries(downloadShow.TvMazeSeriesId)))
            {
                AddPlaceholderSeries(downloadShow);
            }

            try
            {
                Say("Updates list from TVmaze");
                IEnumerable <KeyValuePair <string, long> > updateTimes = API.GetUpdates();

                Say("Processing updates from TVmaze");
                foreach (KeyValuePair <string, long> showUpdateTime in updateTimes)
                {
                    if (!cts.IsCancellationRequested)
                    {
                        int showId = int.Parse(showUpdateTime.Key);

                        if (showId > 0 && HasSeries(showId))
                        {
                            CachedSeriesInfo x = GetSeries(showId);
                            if (!(x is null))
                            {
                                if (x.SrvLastUpdated < showUpdateTime.Value)
                                {
                                    LOGGER.Info($"Identified that show with TVMaze Id {showId} {x.Name} should be updated as update time is now {showUpdateTime.Value} and cache has {x.SrvLastUpdated}. ie {Helpers.FromUnixTime(showUpdateTime.Value).ToLocalTime()} to {Helpers.FromUnixTime(x.SrvLastUpdated).ToLocalTime()}.");
                                    x.Dirty = true;
                                }
                            }
                        }
                    }
                    else
                    {
                        SayNothing();
                        return(true);
                    }
                }

                MarkPlaceholdersDirty();

                SayNothing();
                return(true);
            }
            catch (SourceConnectivityException conex)
            {
                LastErrorMessage = conex.Message;
                return(false);
            }
            catch (SourceConsistencyException sce)
            {
                LOGGER.Error(sce.Message);
                LastErrorMessage = sce.Message;
                return(false);
            }
        }
예제 #6
0
        private static CachedSeriesInfo ConvertSearchResult(JToken token)
        {
            double           score        = token["score"].Value <double>();
            JObject          show         = token["show"].Value <JObject>();
            CachedSeriesInfo downloadedSi = GenerateSeriesInfo(show);

            downloadedSi.Popularity         = score;
            downloadedSi.IsSearchResultOnly = true;
            return(downloadedSi);
        }
예제 #7
0
 private void AddPlaceholderSeries(int tvdb, int tvmaze, int tmdb, string customLanguageCode)
 {
     lock (SERIES_LOCK)
     {
         Series[tmdb] = new CachedSeriesInfo(tvdb, tvmaze, tmdb, customLanguageCode)
         {
             Dirty = true
         };
     }
 }
예제 #8
0
 private void AddPlaceholderSeries(int tvdb, int tvmaze, int tmdb)
 {
     lock (SERIES_LOCK)
     {
         Series[tmdb] = new CachedSeriesInfo(tvdb, tvmaze, tmdb)
         {
             Dirty = true
         };
     }
 }
예제 #9
0
        private bool EnsureSeriesUpdated(SeriesSpecifier s, bool showErrorMsgBox)
        {
            lock (SERIES_LOCK)
            {
                if (Series.ContainsKey(s.TmdbId) && !Series[s.TmdbId].Dirty)
                {
                    return(true);
                }
            }

            Say($"Series {s.Name} from TMDB");
            try
            {
                CachedSeriesInfo downloadedSi = DownloadSeriesNow(s, showErrorMsgBox);

                if (downloadedSi.TmdbCode != s.TmdbId && s.TmdbId == -1)
                {
                    lock (SERIES_LOCK)
                    {
                        Series.TryRemove(-1, out _);
                    }
                }

                if (downloadedSi.TmdbCode != s.TmdbId && s.TmdbId == 0)
                {
                    lock (SERIES_LOCK)
                    {
                        Series.TryRemove(0, out _);
                    }
                }

                lock (SERIES_LOCK)
                {
                    AddSeriesToCache(downloadedSi);
                }
            }
            catch (SourceConnectivityException conex)
            {
                LastErrorMessage = conex.Message;
                return(true);
            }
            catch (SourceConsistencyException sce)
            {
                LOGGER.Error(sce.Message);
                LastErrorMessage = sce.Message;
                return(true);
            }
            finally
            {
                SayNothing();
            }

            return(true);
        }
예제 #10
0
 private void FindOrphanEpisodes(CachedSeriesInfo si, List <long> serverEpIds)
 {
     foreach (Episode localEp in si.Episodes)
     {
         int localEpId = localEp.EpisodeId;
         if (!serverEpIds.Contains(localEpId))
         {
             Issues.Add($"{si.Name} {localEpId} should be removed: Server is missing.");
             localEp.Dirty = true;
             EnsureUpdated(si);
         }
     }
 }
예제 #11
0
        public void ServerAccuracyCheck([NotNull] CachedSeriesInfo si)
        {
            int tvdbId = si.TvdbCode;

            try
            {
                CachedSeriesInfo newSi = lc.DownloadSeriesInfo(tvdbId, "en", false);
                if (newSi.SrvLastUpdated != si.SrvLastUpdated)
                {
                    Issues.Add(
                        $"{si.Name} is not up to date: Local is {DateTimeOffset.FromUnixTimeSeconds(si.SrvLastUpdated)} ({si.SrvLastUpdated}) server is {DateTimeOffset.FromUnixTimeSeconds(newSi.SrvLastUpdated)} ({newSi.SrvLastUpdated})");

                    EnsureUpdated(si);
                }

                List <JObject> eps         = lc.GetEpisodes(tvdbId, "en");
                List <long>    serverEpIds = new List <long>();

                if (eps != null)
                {
                    foreach (JObject epJson in eps)
                    {
                        JToken episodeToUse = epJson["data"];
                        if (episodeToUse != null)
                        {
                            foreach (JToken t in episodeToUse.Children())
                            {
                                int epId = EpisodeAccuracyCheck(si, t);
                                serverEpIds.Add(epId);
                            }
                        }
                        else
                        {
                            throw new SourceConsistencyException($"Could not load 'data' from {epJson}",
                                                                 TVDoc.ProviderType.TheTVDB);
                        }
                    }
                }

                //Look for episodes that are local, but not on server
                FindOrphanEpisodes(si, serverEpIds);
            }
            catch (SourceConnectivityException)
            {
                Issues.Add($"Failed to compare {si.Name} as we could not download the cachedSeries details.");
            }
            catch (MediaNotFoundException)
            {
                Issues.Add($"Failed to compare {si.Name} as it no longer exists on TVDB {tvdbId}.");
            }
        }
예제 #12
0
        public static CachedSeriesInfo GetSeriesDetails([NotNull] SeriesSpecifier ss)
        {
            JObject results = ss.TvMazeSeriesId > 0
                ? GetSeriesDetails(ss.TvMazeSeriesId)
                : GetSeriesDetails(GetSeriesIdFromOtherCodes(ss.TvdbSeriesId, ss.ImdbCode));

            CachedSeriesInfo downloadedSi = GenerateSeriesInfo(results);
            JToken           jToken       = GetChild(results, "_embedded");

            foreach (string name in GetChild(jToken, "akas").Select(akaJson => (string)akaJson["name"]).Where(name => name != null))
            {
                downloadedSi.AddAlias(name);
            }

            List <string> writers   = GetWriters(GetChild(jToken, "crew"));
            List <string> directors = GetDirectors(GetChild(jToken, "crew"));

            foreach (JToken epJson in GetChild(jToken, "episodes"))
            {
                downloadedSi.AddEpisode(GenerateEpisode(ss.TvMazeSeriesId, writers, directors, (JObject)epJson, downloadedSi));
            }

            foreach (JToken jsonSeason in GetChild(jToken, "seasons"))
            {
                downloadedSi.AddSeason(GenerateSeason(ss.TvMazeSeriesId, jsonSeason));

                JToken imageNode = GetChild(jsonSeason, "image");
                if (imageNode.HasValues)
                {
                    string child = (string)GetChild(imageNode, "original");
                    if (child != null)
                    {
                        downloadedSi.AddOrUpdateBanner(GenerateBanner(ss.TvMazeSeriesId, (int)jsonSeason["number"], child));
                    }
                }
            }

            foreach (JToken imageJson in GetChild(jToken, "images").Where(imageJson => (string)imageJson["type"] == "background"))
            {
                downloadedSi.AddOrUpdateBanner(GenerateBanner(ss.TvMazeSeriesId, imageJson));
            }
            downloadedSi.BannersLoaded = true;

            downloadedSi.ClearActors();
            foreach (JToken jsonActor in GetChild(jToken, "cast"))
            {
                downloadedSi.AddActor(GenerateActor(ss.TvMazeSeriesId, jsonActor));
            }

            return(downloadedSi);
        }
예제 #13
0
        public void AddOrUpdateEpisode(Episode e, CachedSeriesInfo si)
        {
            lock (SERIES_LOCK)
            {
                if (!Series.ContainsKey(e.SeriesId))
                {
                    throw new SourceConsistencyException(
                              $"Can't find the cachedSeries to add the episode to. EpId:{e.EpisodeId} SeriesId:{e.SeriesId} {e.Name}", TVDoc.ProviderType.TVmaze);
                }

                CachedSeriesInfo ser = Series[e.SeriesId];
                ser.AddEpisode(e);
            }
        }
예제 #14
0
 private void File(CachedSeriesInfo s)
 {
     lock (SERIES_LOCK)
     {
         if (Series.ContainsKey(s.TmdbCode))
         {
             Series[s.TmdbCode].Merge(s);
         }
         else
         {
             Series[s.TmdbCode] = s;
         }
     }
 }
예제 #15
0
        private void AddSeriesToCache([NotNull] CachedSeriesInfo si)
        {
            int id = si.TmdbCode;

            lock (SERIES_LOCK)
            {
                if (Series.ContainsKey(id))
                {
                    Series[id].Merge(si);
                }
                else
                {
                    Series[id] = si;
                }
            }
        }
예제 #16
0
 private void MarkPlaceholdersDirty()
 {
     lock (SERIES_LOCK)
     {
         // anything with a srv_lastupdated of 0 should be marked as dirty
         // typically, this'll be placeholder cachedSeries
         foreach (KeyValuePair <int, CachedSeriesInfo> kvp in Series)
         {
             CachedSeriesInfo ser = kvp.Value;
             if (ser.SrvLastUpdated == 0 || ser.Episodes.Count == 0)
             {
                 ser.Dirty = true;
             }
         }
     }
 }
예제 #17
0
        public override bool EnsureUpdated(SeriesSpecifier s, bool bannersToo, bool showErrorMsgBox)
        {
            if (s.Provider != TVDoc.ProviderType.TVmaze)
            {
                throw new SourceConsistencyException($"Asked to update {s.Name} from TV Maze, but the Id is not for TV maze.", TVDoc.ProviderType.TVmaze);
            }

            lock (SERIES_LOCK)
            {
                if (Series.ContainsKey(s.TvMazeSeriesId) && !Series[s.TvMazeSeriesId].Dirty)
                {
                    return(true);
                }
            }

            Say($"{s.Name} from TVmaze");
            try
            {
                CachedSeriesInfo downloadedSi = API.GetSeriesDetails(s);

                if (downloadedSi.TvMazeCode != s.TvMazeSeriesId && s.TvMazeSeriesId == -1)
                {
                    lock (SERIES_LOCK)
                    {
                        Series.TryRemove(-1, out _);
                    }
                }

                lock (SERIES_LOCK)
                {
                    AddSeriesToCache(downloadedSi);
                }
            }
            catch (SourceConnectivityException conex)
            {
                LastErrorMessage = conex.Message;
                return(true);
            }
            catch (SourceConsistencyException sce)
            {
                LOGGER.Error(sce.Message);
                LastErrorMessage = sce.Message;
                return(true);
            }

            return(true);
        }
예제 #18
0
        private CachedSeriesInfo File(SearchTv result)
        {
            CachedSeriesInfo m = new CachedSeriesInfo
            {
                TmdbCode   = result.Id,
                Name       = result.Name,
                FirstAired = result.FirstAirDate,
                Overview   = result.Overview,
                //Network = result.ProductionCompanies.FirstOrDefault()?.Name,
                //Status = result.Status,
                ShowLanguage       = result.OriginalLanguage,
                SiteRating         = (float)result.VoteAverage,
                SiteRatingVotes    = result.VoteCount,
                PosterUrl          = ImageURL(result.PosterPath),
                IsSearchResultOnly = true,
                Dirty = false,
            };

            File(m);
            return(m);
        }
예제 #19
0
        private static CachedSeriesInfo GenerateSeriesInfo([NotNull] JObject r)
        {
            CachedSeriesInfo returnValue = GenerateCoreSeriesInfo(r);

            if (r.ContainsKey("genres"))
            {
                returnValue.Genres = r["genres"]?.Select(x => x.Value <string>().Trim()).Distinct().ToList() ?? new List <string>();
            }

            List <string> typesToTransferToGenres = new List <string> {
                "Animation", "Reality", "Documentary", "News", "Sports"
            };

            foreach (string conversionType in typesToTransferToGenres.Where(s => s == returnValue.Type))
            {
                returnValue.Genres.Add(conversionType);
            }

            string s1 = (string)r["name"];

            if (s1 != null)
            {
                returnValue.Name = System.Web.HttpUtility.HtmlDecode(s1).Trim();
            }

            string siteRatingString = ((string)GetChild(r, "rating")["average"])?.Trim();

            float.TryParse(siteRatingString, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.CreateSpecificCulture("en-US"), out float parsedSiteRating);
            returnValue.SiteRating = parsedSiteRating;

            string siteRatingVotesString = (string)r["weight"];

            int.TryParse(siteRatingVotesString, NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.CreateSpecificCulture("en-US"), out int parsedSiteRatingVotes);
            returnValue.SiteRatingVotes = parsedSiteRatingVotes;

            return(returnValue);
        }
예제 #20
0
        public static string WebsiteShowUrl([NotNull] CachedSeriesInfo si)
        {
            string?value = si.Slug;

            return(string.IsNullOrWhiteSpace(value) ? WebsiteShowUrl(si.TvdbCode) : WebsiteShowUrl(value));
        }
예제 #21
0
        internal CachedSeriesInfo DownloadSeriesNow(SeriesSpecifier ss, bool showErrorMsgBox)
        {
            int id = ss.TmdbId > 0 ? ss.TmdbId : GetSeriesIdFromOtherCodes(ss) ?? 0;

            TvShow?downloadedSeries = Client.GetTvShowAsync(id, TvShowMethods.ExternalIds | TvShowMethods.Images | TvShowMethods.AlternativeTitles | TvShowMethods.ContentRatings | TvShowMethods.Changes | TvShowMethods.Videos | TvShowMethods.Credits).Result;

            if (downloadedSeries is null)
            {
                throw new ShowNotFoundException(id, "TMDB no longer has this show", TVDoc.ProviderType.TMDB, TVDoc.ProviderType.TMDB);
            }
            CachedSeriesInfo m = new CachedSeriesInfo
            {
                Imdb       = downloadedSeries.ExternalIds.ImdbId,
                TmdbCode   = downloadedSeries.Id,
                TvdbCode   = downloadedSeries.ExternalIds.TvdbId.ToInt(ss.TvdbSeriesId),
                TvMazeCode = downloadedSeries.ExternalIds.TvrageId.ToInt(ss.TvMazeSeriesId),
                Name       = downloadedSeries.Name,
                //Runtime = downloadedSeries.Runtime.ToString(),
                FirstAired      = downloadedSeries.FirstAirDate,
                Genres          = downloadedSeries.Genres.Select(genre => genre.Name).ToList(),
                Overview        = downloadedSeries.Overview,
                Network         = downloadedSeries.ProductionCompanies.FirstOrDefault()?.Name,
                Status          = MapStatus(downloadedSeries.Status),
                ShowLanguage    = downloadedSeries.OriginalLanguage,
                SiteRating      = (float)downloadedSeries.VoteAverage,
                SiteRatingVotes = downloadedSeries.VoteCount,
                PosterUrl       = ImageURL(downloadedSeries.PosterPath),
                SrvLastUpdated  = DateTime.UtcNow.Date.ToUnixTime(),
                //CollectionName = downloadedSeries.BelongsToCollection?.Name,
                //CollectionId = downloadedSeries.BelongsToCollection?.Id,
                //TagLine = downloadedSeries.,
                TwitterId   = downloadedSeries.ExternalIds.TwitterId,
                InstagramId = downloadedSeries.ExternalIds.InstagramId,
                FacebookId  = downloadedSeries.ExternalIds.InstagramId,
                //FanartUrl = ImageURL(downloadedSeries.BackdropPath),
                //ContentRating = GetCertification(downloadedSeries, "AU") ?? GetCertification(downloadedSeries, "US") ?? string.Empty,// todo allow user to choose
                OfficialUrl = downloadedSeries.Homepage,
                Type        = downloadedSeries.Type,
                //TrailerUrl = GetYouTubeUrl(downloadedSeries),
                Dirty = false,
            };

            foreach (var s in downloadedSeries.AlternativeTitles.Results.Select(title => title.Title))
            {
                m.AddAlias(s);
            }
            foreach (var s in downloadedSeries.Credits.Cast)
            {
                m.AddActor(new Actor(s.Id, s.ProfilePath, s.Name, s.Character, 0, s.Order));
            }
            foreach (var s in downloadedSeries.Credits.Crew)
            {
                m.AddCrew(new Crew(s.Id, s.ProfilePath, s.Name, s.Job, s.Department, s.CreditId));
            }

            foreach (int snum in Enumerable.Range(1, downloadedSeries.NumberOfSeasons))
            {
                var downloadedSeason = Client.GetTvSeasonAsync(downloadedSeries.Id, snum, TvSeasonMethods.Images).Result;
                // TODO add language
                Season newSeason = new Season(downloadedSeason.Id ?? 0, snum, downloadedSeason.Name, downloadedSeason.Overview, String.Empty, downloadedSeason.PosterPath, downloadedSeries.Id);
                m.AddSeason(newSeason);

                foreach (var downloadedEpisode in downloadedSeason.Episodes)
                {
                    Episode newEpisode = new Episode(downloadedSeries.Id, m)
                    {
                        Name              = downloadedEpisode.Name,
                        Overview          = downloadedEpisode.Overview,
                        AirTime           = downloadedEpisode.AirDate,
                        AirStamp          = downloadedEpisode.AirDate,
                        FirstAired        = downloadedEpisode.AirDate,
                        AiredEpNum        = downloadedEpisode.EpisodeNumber,
                        AiredSeasonNumber = downloadedEpisode.SeasonNumber,
                        ProductionCode    = downloadedEpisode.ProductionCode,
                        EpisodeId         = downloadedEpisode.Id,
                        SiteRatingCount   = downloadedEpisode.VoteCount,
                        EpisodeRating     = downloadedEpisode.VoteAverage.ToString(System.Globalization.CultureInfo.InvariantCulture),
                        SeasonId          = newSeason.SeasonId,
                        Filename          = ImageURL(downloadedEpisode.StillPath, "original")
                    };
                    //todo - add cast and crew

                    m.AddEpisode(newEpisode);
                }

                if (downloadedSeason.Images != null)
                {
                    foreach (var image in downloadedSeason.Images.Posters)
                    {
                        Banner newBanner = new Banner(downloadedSeries.Id)
                        {
                            BannerPath  = image.FilePath,
                            BannerType  = "fanart",
                            Rating      = image.VoteAverage,
                            RatingCount = image.VoteCount
                        };

                        m.AddOrUpdateBanner(newBanner);
                    }
                }
            }

            m.BannersLoaded = true;

            File(m);

            return(m);
        }