public void UpdateSeries(CachedSeriesInfo si) { lock (SERIES_LOCK) { Series[si.TmdbCode] = si; } }
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."); } } }
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); }
private void EnsureUpdated(CachedSeriesInfo si) { si.Dirty = true; if (!ShowsToUpdate.Contains(si)) { ShowsToUpdate.Add(si); } }
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); } }
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); }
private void AddPlaceholderSeries(int tvdb, int tvmaze, int tmdb, string customLanguageCode) { lock (SERIES_LOCK) { Series[tmdb] = new CachedSeriesInfo(tvdb, tvmaze, tmdb, customLanguageCode) { Dirty = true }; } }
private void AddPlaceholderSeries(int tvdb, int tvmaze, int tmdb) { lock (SERIES_LOCK) { Series[tmdb] = new CachedSeriesInfo(tvdb, tvmaze, tmdb) { Dirty = true }; } }
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); }
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); } } }
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}."); } }
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); }
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); } }
private void File(CachedSeriesInfo s) { lock (SERIES_LOCK) { if (Series.ContainsKey(s.TmdbCode)) { Series[s.TmdbCode].Merge(s); } else { Series[s.TmdbCode] = s; } } }
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; } } }
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; } } } }
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); }
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); }
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); }
public static string WebsiteShowUrl([NotNull] CachedSeriesInfo si) { string?value = si.Slug; return(string.IsNullOrWhiteSpace(value) ? WebsiteShowUrl(si.TvdbCode) : WebsiteShowUrl(value)); }
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); }