public async Task <IEnumerable <SearchTvShowViewModel> > Search(string searchTerm) { var searchResult = await TvMazeApi.Search(searchTerm); if (searchResult != null) { var retVal = new List <SearchTvShowViewModel>(); foreach (var tvMazeSearch in searchResult) { if (tvMazeSearch.show.externals == null || !(tvMazeSearch.show.externals?.thetvdb.HasValue ?? false)) { continue; } var mappedResult = await ProcessResult(tvMazeSearch, false); if (mappedResult == null) { continue; } retVal.Add(mappedResult); } return(retVal); } return(null); }
new public async Task <IEnumerable <SearchTvShowViewModel> > Search(string search) { var searchResult = await TvMazeApi.Search(search); for (var i = 0; i < searchResult.Count; i++) { if (!_demoLists.TvShows.Contains(searchResult[i].show?.externals?.thetvdb ?? 0)) { searchResult.RemoveAt(i); } } if (searchResult != null) { var retVal = new List <SearchTvShowViewModel>(); foreach (var tvMazeSearch in searchResult) { if (tvMazeSearch.show.externals == null || !(tvMazeSearch.show.externals?.thetvdb.HasValue ?? false)) { continue; } retVal.Add(await ProcessResult(tvMazeSearch, false)); } return(retVal); } return(null); }
public async Task <SearchTvShowViewModel> GetShowInformation(string tvdbid, CancellationToken token) { var show = await Cache.GetOrAdd(nameof(GetShowInformation) + tvdbid, async() => await TvMazeApi.ShowLookupByTheTvDbId(int.Parse(tvdbid)), DateTime.Now.AddHours(12)); if (show == null) { // We don't have enough information return(null); } var episodes = await Cache.GetOrAdd("TvMazeEpisodeLookup" + show.id, async() => await TvMazeApi.EpisodeLookup(show.id), DateTime.Now.AddHours(12)); if (episodes == null || !episodes.Any()) { // We don't have enough information return(null); } var mapped = Mapper.Map <SearchTvShowViewModel>(show); foreach (var e in episodes) { var season = mapped.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == e.season); if (season == null) { var newSeason = new SeasonRequests { SeasonNumber = e.season, Episodes = new List <EpisodeRequests>() }; newSeason.Episodes.Add(new EpisodeRequests { Url = e.url.ToHttpsUrl(), Title = e.name, AirDate = e.airstamp.HasValue() ? DateTime.Parse(e.airstamp) : DateTime.MinValue, EpisodeNumber = e.number, }); mapped.SeasonRequests.Add(newSeason); } else { // We already have the season, so just add the episode season.Episodes.Add(new EpisodeRequests { Url = e.url.ToHttpsUrl(), Title = e.name, AirDate = e.airstamp.HasValue() ? DateTime.Parse(e.airstamp) : DateTime.MinValue, EpisodeNumber = e.number, }); } } return(await ProcessResult(mapped, false)); }
private Response GetSeasons() { var tv = new TvMazeApi(); var seriesId = (int)Request.Query.tvId; var show = tv.ShowLookupByTheTvDbId(seriesId); var seasons = tv.GetSeasons(show.id); var model = seasons.Select(x => x.number); return(Response.AsJson(model)); }
public async Task <IEnumerable <SearchTvShowViewModel> > Search(string searchTerm) { var searchResult = await TvMazeApi.Search(searchTerm); if (searchResult != null) { return(await ProcessResults(searchResult)); } return(null); }
public async Task <SearchTvShowViewModel> GetShowInformation(int tvdbid) { var show = await TvMazeApi.ShowLookupByTheTvDbId(tvdbid); if (show == null) { // We don't have enough information return(null); } var episodes = await TvMazeApi.EpisodeLookup(show.id); if (episodes == null || !episodes.Any()) { // We don't have enough information return(null); } var mapped = Mapper.Map <SearchTvShowViewModel>(show); foreach (var e in episodes) { var season = mapped.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == e.season); if (season == null) { var newSeason = new SeasonRequests { SeasonNumber = e.season, Episodes = new List <EpisodeRequests>() }; newSeason.Episodes.Add(new EpisodeRequests { Url = e.url, Title = e.name, AirDate = e.airstamp.HasValue() ? DateTime.Parse(e.airstamp) : DateTime.MinValue, EpisodeNumber = e.number, }); mapped.SeasonRequests.Add(newSeason); } else { // We already have the season, so just add the episode season.Episodes.Add(new EpisodeRequests { Url = e.url, Title = e.name, AirDate = e.airstamp.HasValue() ? DateTime.Parse(e.airstamp) : DateTime.MinValue, EpisodeNumber = e.number, }); } } return(await ProcessResult(mapped)); }
private void ProcessMissingInformation(List <RequestQueue> requests) { if (!requests.Any()) { return; } var sonarrSettings = SonarrSettings.GetSettings(); var sickrageSettings = SickrageSettings.GetSettings(); var tv = requests.Where(x => x.Type == RequestType.TvShow); // TV var tvApi = new TvMazeApi(); foreach (var t in tv) { var providerId = int.Parse(t.PrimaryIdentifier); var showInfo = tvApi.ShowLookup(providerId); if (showInfo.externals?.thetvdb != null) { // We now have the info var tvModel = ByteConverterHelper.ReturnObject <RequestedModel>(t.Content); tvModel.ProviderId = showInfo.externals.thetvdb.Value; var result = ProcessTvShow(tvModel, sonarrSettings, sickrageSettings); if (!result) { // we now have the info but couldn't add it, so add it back into the queue but with a different fault t.Content = ByteConverterHelper.ReturnBytes(tvModel); t.FaultType = FaultType.RequestFault; t.LastRetry = DateTime.UtcNow; Repo.Update(t); } else { // Make sure it's been requested var existingRequests = RequestService.GetAll(); var thisItem = existingRequests.Any(x => x.Title.Equals(tvModel.Title)); if (!thisItem) { tvModel.Approved = true; RequestService.AddRequest(tvModel); } // Successful, remove from the fault queue Repo.Delete(t); } } } }
public PlexRecentlyAddedNewsletter(IPlexApi api, ISettingsService <PlexSettings> plexSettings, ISettingsService <EmailNotificationSettings> email, ISettingsService <NewletterSettings> newsletter, IRepository <RecentlyAddedLog> log, IRepository <PlexContent> embyContent, IRepository <PlexEpisodes> episodes) { Api = api; PlexSettings = plexSettings; EmailSettings = email; NewsletterSettings = newsletter; Content = embyContent; MovieApi = new TheMovieDbApi(); TvApi = new TvMazeApi(); Episodes = episodes; RecentlyAddedLog = log; }
public async Task IntegratieTest() { var client = new HttpClient(); var storage = new Storage(); var api = new TvMazeApi(client, storage); await api.StoreShows(); var query = new GetShowsQuery() { Page = 1 }; var shows = await storage.GetShows(query); Assert.NotNull(shows); Assert.True(shows.Shows.Length == 10); }
public void CheckForUpdates() { this._logger.LogDebug(message: "Checking tv maze updates.."); var api = new TvMazeApi(settings: this._settings); // in each iteration begin with getting the timestamps of all tvshows in the db. // https://www.tvmaze.com/api#updates var result = api.GetUpdates(); // Then consider rate limiting // https://www.tvmaze.com/api#rate-limiting // Instead of rate limiting directly the execute function of TvMazeApi class, we use rate limiting here to avoid redis timeout failure because of the Parallel foreach. // redis repository could be implemented to work with bench operations, just didn't want to postpone the actual operation. // Rate limit is currently 20 calls in 10 seconds, the RateGate component is chosen because it uses SemaphoreSlim to optimize the call rate with the execution time. using (var rateGate = new RateGate(occurrences: this._settings.RateLimitOccurrences, timeUnit: TimeSpan.FromSeconds(value: this._settings.RateLimitSeconds))) { // Run a loop for every update in the tv maze database // we dont need more thread to start, then wait in the semaphore queue. So we use MaxDegreeOfParallelism property. Parallel.ForEach(source: result, parallelOptions: new ParallelOptions { MaxDegreeOfParallelism = this._settings.RateLimitOccurrences }, body: currentElement => { // Wait for the rate limit... rateGate.WaitToProceed(); // check for the timestamp recently obtained matches the value in the redis cache. var isValid = this._repository.IsConcurrencyValueValid(value: currentElement); if (!isValid) { // if not, get the show details from api, // https://www.tvmaze.com/api#shows var updated = api.GetShowDetail(showId: currentElement.Key); // Create Integration Event to be published through the Event Bus var showUpdatedEvent = new ShowUpdatedIntegrationEvent(payload: updated); // Publish the event so the other projects may know about this change. this._eventBus.Publish(@event: showUpdatedEvent); } }); } }
public async Task <IEnumerable <SearchTvShowViewModel> > NowPlayingMovies() { var rand = new Random(); var responses = new List <SearchTvShowViewModel>(); for (int i = 0; i < 10; i++) { var item = rand.Next(_demoLists.TvShows.Length); var tv = _demoLists.TvShows[item]; if (responses.Any(x => x.Id == tv)) { i--; continue; } var movieResult = await TvMazeApi.ShowLookup(tv); responses.Add(await ProcessResult(movieResult, false)); } return(responses); }
/// <summary> /// Requests the tv show. /// </summary> /// <param name="showId">The show identifier.</param> /// <param name="seasons">The seasons.</param> /// <param name="notify">if set to <c>true</c> [notify].</param> /// <returns></returns> private Response RequestTvShow(int showId, string seasons) { var tvApi = new TvMazeApi(); var showInfo = tvApi.ShowLookupByTheTvDbId(showId); DateTime firstAir; DateTime.TryParse(showInfo.premiered, out firstAir); string fullShowName = $"{showInfo.name} ({firstAir.Year})"; //#if !DEBUG var settings = PrService.GetSettings(); // check if the show has already been requested Log.Info("Requesting tv show with id {0}", showId); var existingRequest = RequestService.CheckRequest(showId); if (existingRequest != null) { // check if the current user is already marked as a requester for this show, if not, add them if (!existingRequest.UserHasRequested(Username)) { existingRequest.RequestedUsers.Add(Username); RequestService.UpdateRequest(existingRequest); } return(Response.AsJson(new JsonResponseModel { Result = true, Message = settings.UsersCanViewOnlyOwnRequests ? $"{fullShowName} was successfully added!" : $"{fullShowName} has already been requested!" })); } try { var shows = Checker.GetPlexTvShows(); if (Checker.IsTvShowAvailable(shows.ToArray(), showInfo.name, showInfo.premiered?.Substring(0, 4))) { return(Response.AsJson(new JsonResponseModel { Result = false, Message = $"{fullShowName} is already in Plex!" })); } } catch (ApplicationSettingsException) { return(Response.AsJson(new JsonResponseModel { Result = false, Message = $"We could not check if {fullShowName} is in Plex, are you sure it's correctly setup?" })); } //#endif var model = new RequestedModel { ProviderId = showInfo.externals?.thetvdb ?? 0, Type = RequestType.TvShow, Overview = showInfo.summary.RemoveHtml(), PosterPath = showInfo.image?.medium, Title = showInfo.name, ReleaseDate = firstAir, Status = showInfo.status, RequestedDate = DateTime.UtcNow, Approved = false, RequestedUsers = new List <string> { Username }, Issues = IssueState.None, ImdbId = showInfo.externals?.imdb ?? string.Empty, SeasonCount = showInfo.seasonCount }; var seasonsList = new List <int>(); switch (seasons) { case "first": seasonsList.Add(1); model.SeasonsRequested = "First"; break; case "latest": seasonsList.Add(model.SeasonCount); model.SeasonsRequested = "Latest"; break; case "all": model.SeasonsRequested = "All"; break; default: var split = seasons.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var seasonsCount = new int[split.Length]; for (var i = 0; i < split.Length; i++) { int tryInt; int.TryParse(split[i], out tryInt); seasonsCount[i] = tryInt; } seasonsList.AddRange(seasonsCount); break; } model.SeasonList = seasonsList.ToArray(); if (ShouldAutoApprove(RequestType.TvShow, settings)) { var sonarrSettings = SonarrService.GetSettings(); var sender = new TvSender(SonarrApi, SickrageApi); if (sonarrSettings.Enabled) { var result = sender.SendToSonarr(sonarrSettings, model); if (result != null && !string.IsNullOrEmpty(result.title)) { model.Approved = true; Log.Debug("Adding tv to database requests (No approval required & Sonarr)"); RequestService.AddRequest(model); if (ShouldSendNotification()) { var notify1 = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; NotificationService.Publish(notify1); } return(Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullShowName} was successfully added!" })); } return(Response.AsJson(ValidationHelper.SendSonarrError(result?.ErrorMessages))); } var srSettings = SickRageService.GetSettings(); if (srSettings.Enabled) { var result = sender.SendToSickRage(srSettings, model); if (result?.result == "success") { model.Approved = true; Log.Debug("Adding tv to database requests (No approval required & SickRage)"); RequestService.AddRequest(model); if (ShouldSendNotification()) { var notify2 = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; NotificationService.Publish(notify2); } return(Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullShowName} was successfully added!" })); } return(Response.AsJson(new JsonResponseModel { Result = false, Message = result?.message != null ? "<b>Message From SickRage: </b>" + result.message : "Something went wrong adding the movie to SickRage! Please check your settings." })); } return(Response.AsJson(new JsonResponseModel { Result = false, Message = "The request of TV Shows is not correctly set up. Please contact your admin." })); } RequestService.AddRequest(model); var notificationModel = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; NotificationService.Publish(notificationModel); return(Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullShowName} was successfully added!" })); }
private async Task <Response> ReportNonRequestIssue(int providerId, string type, IssueState issue, string comment) { var currentIssues = await IssuesService.GetAllAsync(); var notifyModel = new NotificationModel { User = Username, NotificationType = NotificationType.Issue, DateTime = DateTime.Now, Body = issue == IssueState.Other ? comment : issue.ToString().ToCamelCaseWords() }; var model = new IssueModel { Issue = issue, UserReported = Username, UserNote = !string.IsNullOrEmpty(comment) ? $"{Username} - {comment}" : string.Empty, }; var existing = currentIssues.FirstOrDefault(x => x.ProviderId == providerId && !x.Deleted && x.IssueStatus == IssueStatus.PendingIssue); if (existing != null) { existing.Issues.Add(model); await IssuesService.UpdateIssueAsync(existing); return(Response.AsJson(new JsonResponseModel { Result = true })); } if (type == "movie") { var movieApi = new TheMovieDbApi(); var result = await movieApi.GetMovieInformation(providerId); if (result != null) { notifyModel.Title = result.Title; // New issue var issues = new IssuesModel { Title = result.Title, PosterUrl = "https://image.tmdb.org/t/p/w150/" + result.PosterPath, ProviderId = providerId, Type = RequestType.Movie, IssueStatus = IssueStatus.PendingIssue }; issues.Issues.Add(model); var issueId = await IssuesService.AddIssueAsync(issues); await NotificationService.Publish(notifyModel); return(Response.AsJson(new JsonResponseModel { Result = true })); } } if (type == "tv") { var tv = new TvMazeApi(); var result = tv.ShowLookupByTheTvDbId(providerId); if (result != null) { var banner = result.image?.medium; if (!string.IsNullOrEmpty(banner)) { banner = banner.Replace("http", "https"); } notifyModel.Title = result.name; // New issue var issues = new IssuesModel { Title = result.name, PosterUrl = banner, ProviderId = providerId, Type = RequestType.TvShow, IssueStatus = IssueStatus.PendingIssue }; issues.Issues.Add(model); var issueId = await IssuesService.AddIssueAsync(issues); await NotificationService.Publish(notifyModel); return(Response.AsJson(new JsonResponseModel { Result = true })); } } return(Response.AsJson(new JsonResponseModel { Result = false, Message = "Album Reports are not supported yet!" })); }
private void MigrateDbFrom1300() // TODO: Remove in v1.7 { var result = new List <long>(); RequestedModel[] requestedModels; var repo = new GenericRepository <RequestedModel>(Db, new MemoryCacheProvider()); try { var records = repo.GetAll(); requestedModels = records as RequestedModel[] ?? records.ToArray(); } catch (SqliteException) { // There is no requested table so they do not have an old version of the DB return; } if (!requestedModels.Any()) { return; } var jsonRepo = new JsonRequestService(new RequestJsonRepository(Db, new MemoryCacheProvider())); var api = new TvMazeApi(); foreach (var r in requestedModels.Where(x => x.Type == RequestType.TvShow)) { var show = api.ShowLookupByTheTvDbId(r.ProviderId); var model = new RequestedModel { Title = show.name, PosterPath = show.image?.medium, Type = RequestType.TvShow, ProviderId = show.externals.thetvdb ?? 0, ReleaseDate = r.ReleaseDate, AdminNote = r.AdminNote, Approved = r.Approved, Available = r.Available, ImdbId = show.externals.imdb, Issues = r.Issues, OtherMessage = r.OtherMessage, Overview = show.summary.RemoveHtml(), RequestedUsers = r.AllUsers, // should pull in the RequestedBy property and merge with RequestedUsers RequestedDate = r.ReleaseDate, Status = show.status }; var id = jsonRepo.AddRequest(model); result.Add(id); } foreach (var source in requestedModels.Where(x => x.Type == RequestType.Movie)) { var id = jsonRepo.AddRequest(source); result.Add(id); } if (result.Any(x => x == -1)) { throw new SqliteException("Could not migrate the DB!"); } if (result.Count != requestedModels.Length) { throw new SqliteException("Could not migrate the DB! count is different"); } // Now delete the old requests foreach (var oldRequest in requestedModels) { repo.Delete(oldRequest); } }