private Response SonarrTest() { var sonarrSettings = this.Bind <SonarrSettings>(); var valid = this.Validate(sonarrSettings); if (!valid.IsValid) { return(Response.AsJson(valid.SendJsonError())); } try { var status = SonarrApi.SystemStatus(sonarrSettings.ApiKey, sonarrSettings.FullUri); return(status?.version != null ? Response.AsJson(new JsonResponseModel { Result = true, Message = "Connected to Sonarr successfully!" }) : Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Sonarr, please check your settings." })); } catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them. { Log.Warn("Exception thrown when attempting to get Sonarr's status: "); Log.Warn(e); var message = $"Could not connect to Sonarr, please check your settings. <strong>Exception Message:</strong> {e.Message}"; if (e.InnerException != null) { message = $"Could not connect to Sonarr, please check your settings. <strong>Exception Message:</strong> {e.InnerException.Message}"; } return(Response.AsJson(new JsonResponseModel { Result = false, Message = message })); } }
private async Task <Response> ChangeRootFolder(int id, int rootFolderId) { // Get all root folders var settings = await SonarrSettings.GetSettingsAsync(); var rootFolders = SonarrApi.GetRootFolders(settings.ApiKey, settings.FullUri); // Get Request var allRequests = await Service.GetAllAsync(); var request = allRequests.FirstOrDefault(x => x.Id == id); if (request == null) { return(Response.AsJson(new JsonResponseModel { Result = false })); } foreach (var folder in rootFolders) { if (folder.id.Equals(rootFolderId)) { request.RootFolderSelected = folder.id; break; } } await Service.UpdateRequestAsync(request); return(Response.AsJson(new JsonResponseModel { Result = true })); }
public void Queued() { var settings = SonarrSettings.GetSettings(); if (settings.Enabled) { Job.SetRunning(true, JobNames.SonarrCacher); try { var series = SonarrApi.GetSeries(settings.ApiKey, settings.FullUri); if (series != null) { Cache.Set(CacheKeys.SonarrQueued, series, CacheKeys.TimeFrameMinutes.SchedulerCaching); } } catch (System.Exception ex) { Log.Error(ex, "Failed caching queued items from Sonarr"); } finally { Job.Record(JobNames.SonarrCacher); Job.SetRunning(false, JobNames.SonarrCacher); } } }
internal async Task RequestEpisodesWithExistingSeries(RequestedModel model, Series selectedSeries, SonarrSettings sonarrSettings) { // Show Exists // Look up all episodes var ep = SonarrApi.GetEpisodes(selectedSeries.id.ToString(), sonarrSettings.ApiKey, sonarrSettings.FullUri); var episodes = ep?.ToList() ?? new List <SonarrEpisodes>(); var internalEpisodeIds = new List <int>(); var tasks = new List <Task>(); foreach (var r in model.Episodes) { // Match the episode and season number. // If the episode is monitored we might not be searching for it. var episode = episodes.FirstOrDefault( x => x.episodeNumber == r.EpisodeNumber && x.seasonNumber == r.SeasonNumber); if (episode == null) { continue; } var episodeInfo = SonarrApi.GetEpisode(episode.id.ToString(), sonarrSettings.ApiKey, sonarrSettings.FullUri); episodeInfo.monitored = true; // Set the episode to monitored tasks.Add(Task.Run(() => SonarrApi.UpdateEpisode(episodeInfo, sonarrSettings.ApiKey, sonarrSettings.FullUri))); internalEpisodeIds.Add(episode.id); } await Task.WhenAll(tasks.ToArray()); SonarrApi.SearchForEpisodes(internalEpisodeIds.ToArray(), sonarrSettings.ApiKey, sonarrSettings.FullUri); }
internal async Task RequestAllEpisodesWithExistingSeries(RequestedModel model, Series selectedSeries, SonarrSettings sonarrSettings) { // Show Exists // Look up all episodes var ep = SonarrApi.GetEpisodes(selectedSeries.id.ToString(), sonarrSettings.ApiKey, sonarrSettings.FullUri); var episodes = ep?.ToList() ?? new List <SonarrEpisodes>(); var internalEpisodeIds = new List <int>(); var tasks = new List <Task>(); foreach (var r in episodes) { if (r.monitored || r.hasFile) // If it's already montiored or has the file, there is no point in updating it { continue; } // Lookup the individual episode details var episodeInfo = SonarrApi.GetEpisode(r.id.ToString(), sonarrSettings.ApiKey, sonarrSettings.FullUri); episodeInfo.monitored = true; // Set the episode to monitored tasks.Add(Task.Run(() => SonarrApi.UpdateEpisode(episodeInfo, sonarrSettings.ApiKey, sonarrSettings.FullUri))); internalEpisodeIds.Add(r.id); } await Task.WhenAll(tasks.ToArray()); SonarrApi.SearchForEpisodes(internalEpisodeIds.ToArray(), sonarrSettings.ApiKey, sonarrSettings.FullUri); }
private async Task <string> GetRootPath(int pathId, SonarrSettings sonarrSettings) { var rootFoldersResult = await Cache.GetOrSetAsync(CacheKeys.SonarrRootFolders, async() => { return(await Task.Run(() => SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri))); }); foreach (var r in rootFoldersResult.Where(r => r.id == pathId)) { return(r.path); } int outRoot; var defaultPath = int.TryParse(sonarrSettings.RootPath, out outRoot); if (defaultPath) { // Return default path return(rootFoldersResult.FirstOrDefault(x => x.id.Equals(outRoot))?.path ?? string.Empty); } else { return(rootFoldersResult.FirstOrDefault()?.path ?? string.Empty); } }
private async Task <SonarrAddSeries> ProcessSonarrRequestSeason(SonarrSettings sonarrSettings, RequestedModel model, int qualityId, string rootFolderPath) { // Does the series exist? var series = await GetSonarrSeries(sonarrSettings, model.ProviderId); if (series == null) { //WORKS // Add the series return(AddSeries(sonarrSettings, model, rootFolderPath, qualityId)); } // Also make sure the series is now monitored otherwise we won't search for it series.monitored = true; foreach (var seasons in series.seasons) { seasons.monitored = true; } // Send the update command series = SonarrApi.UpdateSeries(series, sonarrSettings.ApiKey, sonarrSettings.FullUri); SonarrApi.SearchForSeries(series.id, sonarrSettings.ApiKey, sonarrSettings.FullUri); return(new SonarrAddSeries { title = series.title }); }
private async Task <Series> GetSonarrSeries(SonarrSettings sonarrSettings, int showId) { var task = await Task.Run(() => SonarrApi.GetSeries(sonarrSettings.ApiKey, sonarrSettings.FullUri)).ConfigureAwait(false); var selectedSeries = task.FirstOrDefault(series => series.tvdbId == showId); return(selectedSeries); }
public async Task <IEnumerable <SonarrProfile> > GetProfiles() { var settings = await SonarrSettings.GetSettingsAsync(); if (settings.Enabled) { return(await SonarrApi.GetProfiles(settings.ApiKey, settings.FullUri)); } return(null); }
private async Task <SonarrAddSeries> ProcessSonarrEpisodeRequest(SonarrSettings sonarrSettings, RequestedModel model, int qualityId, string rootFolderPath) { // Does the series exist? var series = await GetSonarrSeries(sonarrSettings, model.ProviderId); if (series == null) { var seriesToAdd = new SonarrAddSeries { seasonFolder = sonarrSettings.SeasonFolders, title = model.Title, qualityProfileId = qualityId, tvdbId = model.ProviderId, titleSlug = model.Title, seasons = new List <Season>(), rootFolderPath = rootFolderPath, monitored = true, // Montior the series images = new List <SonarrImage>(), addOptions = new AddOptions { ignoreEpisodesWithFiles = true, // We don't really care about these ignoreEpisodesWithoutFiles = true, // We do not want to grab random episodes missing searchForMissingEpisodes = false // we want don't want to search for the missing episodes either } }; for (var i = 1; i <= model.SeasonCount; i++) { var season = new Season { seasonNumber = i, monitored = false // Do not monitor any seasons }; seriesToAdd.seasons.Add(season); } // Add the series now var result = SonarrApi.AddSeries(seriesToAdd, sonarrSettings.ApiKey, sonarrSettings.FullUri); await RequestEpisodesForSonarr(model, result.id, sonarrSettings); } else { await RequestEpisodesForSonarr(model, series.id, sonarrSettings); } return(new SonarrAddSeries() { title = model.Title }); }
private async Task <string> GetRootPath(int pathId, SonarrSettings sonarrSettings) { var rootFoldersResult = await Cache.GetOrSetAsync(CacheKeys.SonarrRootFolders, async() => { return(await Task.Run(() => SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri))); }); foreach (var r in rootFoldersResult.Where(r => r.id == pathId)) { return(r.path); } return(string.Empty); }
private Response GetSonarrQualityProfiles() { var settings = this.Bind <SonarrSettings>(); var profiles = SonarrApi.GetProfiles(settings.ApiKey, settings.FullUri); // set the cache if (profiles != null) { Cache.Set(CacheKeys.SonarrQualityProfiles, profiles); } return(Response.AsJson(profiles)); }
public async Task <bool> Sonarr([FromBody] SonarrSettings settings) { try { var result = await SonarrApi.SystemStatus(settings.ApiKey, settings.FullUri); return(result.version != null); } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Sonarr"); return(false); } }
private async Task <string> GetSonarrRootPath(int pathId, SonarrSettings sonarrSettings) { var rootFoldersResult = await SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri); if (pathId == 0) { return(rootFoldersResult.FirstOrDefault().path); } foreach (var r in rootFoldersResult.Where(r => r.id == pathId)) { return(r.path); } return(string.Empty); }
public SonarrAddSeries SendToSonarr(SonarrSettings sonarrSettings, RequestedModel model, string qualityId) { int qualityProfile; if (!string.IsNullOrEmpty(qualityId) || !int.TryParse(qualityId, out qualityProfile)) // try to parse the passed in quality, otherwise use the settings default quality { int.TryParse(sonarrSettings.QualityProfile, out qualityProfile); } var result = SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile, sonarrSettings.SeasonFolders, sonarrSettings.RootPath, model.SeasonCount, model.SeasonList, sonarrSettings.ApiKey, sonarrSettings.FullUri); Log.Trace("Sonarr Add Result: "); Log.Trace(result.DumpJson()); return(result); }
internal async Task RequestAllEpisodesInASeasonWithExistingSeries(RequestedModel model, Series selectedSeries, SonarrSettings sonarrSettings) { // Show Exists // Look up all episodes var ep = SonarrApi.GetEpisodes(selectedSeries.id.ToString(), sonarrSettings.ApiKey, sonarrSettings.FullUri); var episodes = ep?.ToList() ?? new List <SonarrEpisodes>(); var internalEpisodeIds = new List <int>(); var tasks = new List <Task>(); var requestedEpisodes = model.Episodes; foreach (var r in episodes) { if (r.hasFile) // If it already has the file, there is no point in updating it { continue; } var epComparison = new EpisodesModel { EpisodeNumber = r.episodeNumber, SeasonNumber = r.seasonNumber }; // Make sure we are looking for the right episode and season if (!requestedEpisodes.Contains(epComparison)) { continue; } // Lookup the individual episode details var episodeInfo = SonarrApi.GetEpisode(r.id.ToString(), sonarrSettings.ApiKey, sonarrSettings.FullUri); // If the season is not in thr episodeInfo.monitored = true; // Set the episode to monitored tasks.Add(Task.Run(() => SonarrApi.UpdateEpisode(episodeInfo, sonarrSettings.ApiKey, sonarrSettings.FullUri))); internalEpisodeIds.Add(r.id); } await Task.WhenAll(tasks.ToArray()); SonarrApi.SearchForEpisodes(internalEpisodeIds.ToArray(), sonarrSettings.ApiKey, sonarrSettings.FullUri); }
private void CacheSonarrQualityProfiles(ICacheProvider cacheProvider) { try { var sonarrSettingsService = new SettingsServiceV2 <SonarrSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), cacheProvider)); var sonarrSettings = sonarrSettingsService.GetSettings(); if (sonarrSettings.Enabled) { Log.Info("Begin executing GetProfiles call to Sonarr for quality profiles"); SonarrApi sonarrApi = new SonarrApi(); var profiles = sonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri); cacheProvider.Set(CacheKeys.SonarrQualityProfiles, profiles); Log.Info("Finished executing GetProfiles call to Sonarr for quality profiles"); } } catch (Exception ex) { Log.Error(ex, "Failed to cache Sonarr quality profiles!"); } }
public async Task <TesterResultModel> Sonarr([FromBody] SonarrSettings settings) { try { var result = await SonarrApi.SystemStatus(settings.ApiKey, settings.FullUri); return(new TesterResultModel { IsValid = result.urlBase == settings.SubDir || string.IsNullOrEmpty(result.urlBase) && string.IsNullOrEmpty(settings.SubDir), ExpectedSubDir = result.urlBase }); } catch (Exception e) { Log.LogError(LoggingEvents.Api, e, "Could not test Sonarr"); return(new TesterResultModel { IsValid = false }); } }
private async Task SearchForRequest(ChildRequests model, IEnumerable <Episode> sonarrEpList, SonarrSeries existingSeries, SonarrSettings s, IReadOnlyCollection <Episode> episodesToUpdate) { foreach (var season in model.SeasonRequests) { var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber); var sonarrEpCount = sonarrSeason.Count(); var ourRequestCount = season.Episodes.Count; if (sonarrEpCount == ourRequestCount) { // We have the same amount of requests as all of the episodes in the season. // Do a season search await SonarrApi.SeasonSearch(existingSeries.id, season.SeasonNumber, s.ApiKey, s.FullUri); } else { // There is a miss-match, let's search the episodes indiviaully await SonarrApi.EpisodeSearch(episodesToUpdate.Select(x => x.id).ToArray(), s.ApiKey, s.FullUri); } } }
public SonarrAddSeries AddSeries(SonarrSettings sonarrSettings, RequestedModel model, string rootFolderPath, int qualityId) { //WORKS // Add the series var seriesToAdd = new SonarrAddSeries { seasonFolder = sonarrSettings.SeasonFolders, title = model.Title, qualityProfileId = qualityId, tvdbId = model.ProviderId, titleSlug = model.Title, seasons = new List <Season>(), rootFolderPath = rootFolderPath, monitored = true, // Montior the series images = new List <SonarrImage>(), addOptions = new AddOptions { ignoreEpisodesWithFiles = true, // We don't really care about these ignoreEpisodesWithoutFiles = false, // We want to get the whole season searchForMissingEpisodes = true // we want to search for missing } }; for (var i = 1; i <= model.SeasonCount; i++) { var season = new Season { seasonNumber = i, // The model.SeasonList.Lenth is 0 when this is a "request all" monitored = model.SeasonList.Length == 0 || model.SeasonList.Any(x => x == i) }; seriesToAdd.seasons.Add(season); } return(SonarrApi.AddSeries(seriesToAdd, sonarrSettings.ApiKey, sonarrSettings.FullUri)); }
private async Task <Response> GetTvShows() { var settingsTask = PrSettings.GetSettingsAsync(); var requests = await Service.GetAllAsync(); requests = requests.Where(x => x.Type == RequestType.TvShow); var dbTv = requests; var settings = await settingsTask; if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) { dbTv = dbTv.Where(x => x.UserHasRequested(Username)).ToList(); } IEnumerable <QualityModel> qualities = new List <QualityModel>(); if (IsAdmin) { try { var sonarrSettings = await SonarrSettings.GetSettingsAsync(); if (sonarrSettings.Enabled) { var result = Cache.GetOrSetAsync(CacheKeys.SonarrQualityProfiles, async() => { return(await Task.Run(() => SonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri))); }); qualities = result.Result.Select(x => new QualityModel { Id = x.id.ToString(), Name = x.name }).ToList(); } else { var sickRageSettings = await SickRageSettings.GetSettingsAsync(); if (sickRageSettings.Enabled) { qualities = sickRageSettings.Qualities.Select(x => new QualityModel { Id = x.Key, Name = x.Value }).ToList(); } } } catch (Exception e) { Log.Info(e); } } var viewModel = dbTv.Select(tv => new RequestViewModel { ProviderId = tv.ProviderId, Type = tv.Type, Status = tv.Status, ImdbId = tv.ImdbId, Id = tv.Id, PosterPath = tv.PosterPath, ReleaseDate = tv.ReleaseDate, ReleaseDateTicks = tv.ReleaseDate.Ticks, RequestedDate = tv.RequestedDate, RequestedDateTicks = DateTimeHelper.OffsetUTCDateTime(tv.RequestedDate, DateTimeOffset).Ticks, Released = DateTime.Now > tv.ReleaseDate, Approved = tv.Available || tv.Approved, Title = tv.Title, Overview = tv.Overview, RequestedUsers = IsAdmin ? tv.AllUsers.ToArray() : new string[] { }, ReleaseYear = tv.ReleaseDate.Year.ToString(), Available = tv.Available, Admin = IsAdmin, IssueId = tv.IssueId, TvSeriesRequestType = tv.SeasonsRequested, Qualities = qualities.ToArray(), Episodes = tv.Episodes.ToArray(), }).ToList(); return(Response.AsJson(viewModel)); }
/// <summary> /// Broken Way /// </summary> /// <param name="sonarrSettings"></param> /// <param name="model"></param> /// <param name="qualityId"></param> /// <returns></returns> public async Task <SonarrAddSeries> SendToSonarr(SonarrSettings sonarrSettings, RequestedModel model, string qualityId) { var qualityProfile = 0; var episodeRequest = model.Episodes.Any(); if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality { int.TryParse(qualityId, out qualityProfile); } if (qualityProfile <= 0) { int.TryParse(sonarrSettings.QualityProfile, out qualityProfile); } var series = await GetSonarrSeries(sonarrSettings, model.ProviderId); var requestAll = model.SeasonsRequested?.Equals("All", StringComparison.CurrentCultureIgnoreCase); var first = model.SeasonsRequested?.Equals("First", StringComparison.CurrentCultureIgnoreCase); var latest = model.SeasonsRequested?.Equals("Latest", StringComparison.CurrentCultureIgnoreCase); var specificSeasonRequest = model.SeasonList?.Any(); var rootFolderPath = model.RootFolderSelected <= 0 ? sonarrSettings.FullRootPath : await GetRootPath(model.RootFolderSelected, sonarrSettings); if (episodeRequest) { // Does series exist? if (series != null) { // Series Exists // Request the episodes in the existing series await RequestEpisodesWithExistingSeries(model, series, sonarrSettings); return(new SonarrAddSeries { title = series.title }); } // Series doesn't exist, need to add it as unmonitored. var addResult = await Task.Run(() => SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile, sonarrSettings.SeasonFolders, rootFolderPath, 0, new int[0], sonarrSettings.ApiKey, sonarrSettings.FullUri, false)); // Get the series that was just added series = await GetSonarrSeries(sonarrSettings, model.ProviderId); series.monitored = true; // We want to make sure we are monitoring the series // Un-monitor all seasons foreach (var season in series.seasons) { season.monitored = false; } // Update the series, Since we cannot add as un-monitored due to the following bug: https://github.com/Sonarr/Sonarr/issues/1404 SonarrApi.UpdateSeries(series, sonarrSettings.ApiKey, sonarrSettings.FullUri); // We now have the series in Sonarr, update it to request the episodes. await RequestAllEpisodesInASeasonWithExistingSeries(model, series, sonarrSettings); return(addResult); } // Series exists, don't need to add it if (series == null) { // Set the series as monitored with a season count as 0 so it doesn't search for anything SonarrApi.AddSeriesNew(model.ProviderId, model.Title, qualityProfile, sonarrSettings.SeasonFolders, rootFolderPath, new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }, sonarrSettings.ApiKey, sonarrSettings.FullUri); await Task.Delay(TimeSpan.FromSeconds(1)); series = await GetSonarrSeries(sonarrSettings, model.ProviderId); foreach (var s in series.seasons) { s.monitored = false; } SonarrApi.UpdateSeries(series, sonarrSettings.ApiKey, sonarrSettings.FullUri); } if (requestAll ?? false) { // Monitor all seasons foreach (var season in series.seasons) { season.monitored = true; } SonarrApi.UpdateSeries(series, sonarrSettings.ApiKey, sonarrSettings.FullUri); SonarrApi.SearchForSeries(series.id, sonarrSettings.ApiKey, sonarrSettings.FullUri); // Search For all episodes!" //// This is a work around for this issue: https://github.com/Sonarr/Sonarr/issues/1507 //// The above is the previous code. //SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile, // sonarrSettings.SeasonFolders, sonarrSettings.RootPath, 0, model.SeasonList, sonarrSettings.ApiKey, // sonarrSettings.FullUri, true, true); return(new SonarrAddSeries { title = series.title }); // We have updated it } if (first ?? false) { var firstSeries = (series?.seasons?.OrderBy(x => x.seasonNumber)).FirstOrDefault(x => x.seasonNumber > 0) ?? new Season(); firstSeries.monitored = true; var episodes = SonarrApi.GetEpisodes(series.id.ToString(), sonarrSettings.ApiKey, sonarrSettings.FullUri); // Need to get the episodes so we mark them as monitored var episodesToUpdate = new List <SonarrEpisodes>(); foreach (var e in episodes) { if (e.hasFile || e.seasonNumber != firstSeries.seasonNumber) { continue; } e.monitored = true; // Mark only the episodes we want as monitored episodesToUpdate.Add(e); } foreach (var sonarrEpisode in episodesToUpdate) { SonarrApi.UpdateEpisode(sonarrEpisode, sonarrSettings.ApiKey, sonarrSettings.FullUri); } SonarrApi.UpdateSeries(series, sonarrSettings.ApiKey, sonarrSettings.FullUri); SonarrApi.SearchForSeason(series.id, firstSeries.seasonNumber, sonarrSettings.ApiKey, sonarrSettings.FullUri); return(new SonarrAddSeries { title = series.title }); // We have updated it } if (latest ?? false) { var lastSeries = series?.seasons?.OrderByDescending(x => x.seasonNumber)?.FirstOrDefault() ?? new Season(); lastSeries.monitored = true; var episodes = SonarrApi.GetEpisodes(series.id.ToString(), sonarrSettings.ApiKey, sonarrSettings.FullUri); // Need to get the episodes so we mark them as monitored var episodesToUpdate = new List <SonarrEpisodes>(); foreach (var e in episodes) { if (e.hasFile || e.seasonNumber != lastSeries.seasonNumber) { continue; } e.monitored = true; // Mark only the episodes we want as monitored episodesToUpdate.Add(e); } foreach (var sonarrEpisode in episodesToUpdate) { SonarrApi.UpdateEpisode(sonarrEpisode, sonarrSettings.ApiKey, sonarrSettings.FullUri); } SonarrApi.UpdateSeries(series, sonarrSettings.ApiKey, sonarrSettings.FullUri); SonarrApi.SearchForSeason(series.id, lastSeries.seasonNumber, sonarrSettings.ApiKey, sonarrSettings.FullUri); return(new SonarrAddSeries { title = series.title }); // We have updated it } if (specificSeasonRequest ?? false) { // Monitor the seasons that we have chosen foreach (var season in series.seasons) { if (model.SeasonList.Contains(season.seasonNumber)) { season.monitored = true; SonarrApi.UpdateSeries(series, sonarrSettings.ApiKey, sonarrSettings.FullUri); SonarrApi.SearchForSeason(series.id, season.seasonNumber, sonarrSettings.ApiKey, sonarrSettings.FullUri); } } return(new SonarrAddSeries { title = series.title }); // We have updated it } return(null); }
public async Task <SonarrAddSeries> SendToSonarr(SonarrSettings sonarrSettings, RequestedModel model, string qualityId) { var qualityProfile = 0; var episodeRequest = model.Episodes.Any(); if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality { int.TryParse(qualityId, out qualityProfile); } if (qualityProfile <= 0) { int.TryParse(sonarrSettings.QualityProfile, out qualityProfile); } var series = await GetSonarrSeries(sonarrSettings, model.ProviderId); if (episodeRequest) { // Does series exist? if (series != null) { // Series Exists // Request the episodes in the existing series await RequestEpisodesWithExistingSeries(model, series, sonarrSettings); return(new SonarrAddSeries { title = series.title }); } // Series doesn't exist, need to add it as unmonitored. var addResult = await Task.Run(() => SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile, sonarrSettings.SeasonFolders, sonarrSettings.RootPath, 0, new int[0], sonarrSettings.ApiKey, sonarrSettings.FullUri, false)); // Get the series that was just added series = await GetSonarrSeries(sonarrSettings, model.ProviderId); series.monitored = true; // We want to make sure we are monitoring the series // Un-monitor all seasons foreach (var season in series.seasons) { season.monitored = false; } // Update the series, Since we cannot add as un-monitored due to the following bug: https://github.com/Sonarr/Sonarr/issues/1404 SonarrApi.UpdateSeries(series, sonarrSettings.ApiKey, sonarrSettings.FullUri); // We now have the series in Sonarr, update it to request the episodes. await RequestAllEpisodesInASeasonWithExistingSeries(model, series, sonarrSettings); return(addResult); } if (series != null) { var requestAll = model.SeasonsRequested.Equals("All", StringComparison.CurrentCultureIgnoreCase); var first = model.SeasonsRequested.Equals("First", StringComparison.CurrentCultureIgnoreCase); var latest = model.SeasonsRequested.Equals("Latest", StringComparison.CurrentCultureIgnoreCase); if (model.SeasonList.Any()) { // Monitor the seasons that we have chosen foreach (var season in series.seasons) { if (model.SeasonList.Contains(season.seasonNumber)) { season.monitored = true; } } } if (requestAll) { // Monitor all seasons foreach (var season in series.seasons) { season.monitored = true; } } if (first) { var firstSeries = series?.seasons?.OrderBy(x => x.seasonNumber)?.FirstOrDefault() ?? new Season(); firstSeries.monitored = true; } if (latest) { var lastSeries = series?.seasons?.OrderByDescending(x => x.seasonNumber)?.FirstOrDefault() ?? new Season(); lastSeries.monitored = true; } // Update the series in sonarr with the new monitored status SonarrApi.UpdateSeries(series, sonarrSettings.ApiKey, sonarrSettings.FullUri); await RequestAllEpisodesInASeasonWithExistingSeries(model, series, sonarrSettings); return(new SonarrAddSeries { title = series.title }); // We have updated it } var result = SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile, sonarrSettings.SeasonFolders, sonarrSettings.RootPath, model.SeasonCount, model.SeasonList, sonarrSettings.ApiKey, sonarrSettings.FullUri, true, true); return(result); }
public async Task <IEnumerable <SonarrRootFolder> > GetRootFolders([FromBody] SonarrSettings settings) { return(await SonarrApi.GetRootFolders(settings.ApiKey, settings.FullUri)); }
private async Task SendToSonarr(ChildRequests model, SonarrSeries result, SonarrSettings s) { var episodesToUpdate = new List <Episode>(); // Ok, now let's sort out the episodes. if (model.SeriesType == SeriesType.Anime) { result.seriesType = "anime"; await SonarrApi.UpdateSeries(result, s.ApiKey, s.FullUri); } var sonarrEpisodes = await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri); var sonarrEpList = sonarrEpisodes.ToList() ?? new List <Episode>(); while (!sonarrEpList.Any()) { // It could be that the series metadata is not ready yet. So wait sonarrEpList = (await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri)).ToList(); await Task.Delay(500); } foreach (var req in model.SeasonRequests) { foreach (var ep in req.Episodes) { var sonarrEp = sonarrEpList.FirstOrDefault(x => x.episodeNumber == ep.EpisodeNumber && x.seasonNumber == req.SeasonNumber); if (sonarrEp != null && !sonarrEp.monitored) { sonarrEp.monitored = true; episodesToUpdate.Add(sonarrEp); } } } var seriesChanges = false; foreach (var season in model.SeasonRequests) { var sonarrEpisodeList = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber).ToList(); var sonarrEpCount = sonarrEpisodeList.Count; var ourRequestCount = season.Episodes.Count; var ourEpisodes = season.Episodes.Select(x => x.EpisodeNumber).ToList(); var unairedEpisodes = sonarrEpisodeList.Where(x => x.airDateUtc > DateTime.UtcNow).Select(x => x.episodeNumber).ToList(); //// Check if we have requested all the latest episodes, if we have then monitor //// NOTE, not sure if needed since ombi ui displays future episodes anyway... //ourEpisodes.AddRange(unairedEpisodes); //var distinctEpisodes = ourEpisodes.Distinct().ToList(); //var missingEpisodes = Enumerable.Range(distinctEpisodes.Min(), distinctEpisodes.Count).Except(distinctEpisodes); var existingSeason = result.seasons.FirstOrDefault(x => x.seasonNumber == season.SeasonNumber); if (existingSeason == null) { Logger.LogError("There was no season numer {0} in Sonarr for title {1}", season.SeasonNumber, model.ParentRequest.Title); continue; } if (sonarrEpCount == ourRequestCount /*|| !missingEpisodes.Any()*/) { // We have the same amount of requests as all of the episodes in the season. if (!existingSeason.monitored) { existingSeason.monitored = true; seriesChanges = true; } } else { // Make sure this season is set to monitored if (!existingSeason.monitored) { // We need to monitor it, problem being is all episodes will now be monitored // So we need to monitor the series but unmonitor every episode // Except the episodes that are already monitored before we update the series (we do not want to unmonitored episodes that are monitored beforehand) existingSeason.monitored = true; var sea = result.seasons.FirstOrDefault(x => x.seasonNumber == existingSeason.seasonNumber); sea.monitored = true; //var previouslyMonitoredEpisodes = sonarrEpList.Where(x => // x.seasonNumber == existingSeason.seasonNumber && x.monitored).Select(x => x.episodeNumber).ToList(); // We probably don't actually care about this result = await SonarrApi.UpdateSeries(result, s.ApiKey, s.FullUri); var epToUnmonitored = new List <Episode>(); var newEpList = sonarrEpList.ConvertAll(ep => new Episode(ep)); // Clone it so we don't modify the original member foreach (var ep in newEpList.Where(x => x.seasonNumber == existingSeason.seasonNumber).ToList()) { //if (previouslyMonitoredEpisodes.Contains(ep.episodeNumber)) //{ // // This was previously monitored. // continue; //} ep.monitored = false; epToUnmonitored.Add(ep); } foreach (var epToUpdate in epToUnmonitored) { await SonarrApi.UpdateEpisode(epToUpdate, s.ApiKey, s.FullUri); } } // Now update the episodes that need updating foreach (var epToUpdate in episodesToUpdate.Where(x => x.seasonNumber == season.SeasonNumber)) { await SonarrApi.UpdateEpisode(epToUpdate, s.ApiKey, s.FullUri); } } } if (seriesChanges) { await SonarrApi.SeasonPass(s.ApiKey, s.FullUri, result); } if (!s.AddOnly) { await SearchForRequest(model, sonarrEpList, result, s, episodesToUpdate); } }
public FileHandler(SonarrApi sonarrApi_, MediaServer mServer_) { sonarrApi = sonarrApi_; mServer = mServer_; }
/// <summary> /// Send the request to Sonarr to process /// </summary> /// <param name="s"></param> /// <param name="model"></param> /// <returns></returns> public async Task <NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s) { if (string.IsNullOrEmpty(s.ApiKey)) { return(null); } int qualityToUse; string rootFolderPath; string seriesType; var profiles = await UserQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == model.RequestedUserId); if (model.SeriesType == SeriesType.Anime) { // Get the root path from the rootfolder selected. // For some reason, if we haven't got one use the first root folder in Sonarr rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPathAnime), s); int.TryParse(s.QualityProfileAnime, out qualityToUse); if (profiles != null) { if (profiles.SonarrRootPathAnime > 0) { rootFolderPath = await GetSonarrRootPath(profiles.SonarrRootPathAnime, s); } if (profiles.SonarrQualityProfileAnime > 0) { qualityToUse = profiles.SonarrQualityProfileAnime; } } seriesType = "anime"; } else { int.TryParse(s.QualityProfile, out qualityToUse); // Get the root path from the rootfolder selected. // For some reason, if we haven't got one use the first root folder in Sonarr rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s); if (profiles != null) { if (profiles.SonarrRootPath > 0) { rootFolderPath = await GetSonarrRootPath(profiles.SonarrRootPath, s); } if (profiles.SonarrQualityProfile > 0) { qualityToUse = profiles.SonarrQualityProfile; } } seriesType = "standard"; } // Overrides on the request take priority if (model.ParentRequest.QualityOverride.HasValue) { qualityToUse = model.ParentRequest.QualityOverride.Value; } // Are we using v3 sonarr? var sonarrV3 = s.V3; var languageProfileId = s.LanguageProfile; try { // Does the series actually exist? var allSeries = await SonarrApi.GetSeries(s.ApiKey, s.FullUri); var existingSeries = allSeries.FirstOrDefault(x => x.tvdbId == model.ParentRequest.TvDbId); if (existingSeries == null) { // Time to add a new one var newSeries = new NewSeries { title = model.ParentRequest.Title, imdbId = model.ParentRequest.ImdbId, tvdbId = model.ParentRequest.TvDbId, cleanTitle = model.ParentRequest.Title, monitored = true, seasonFolder = s.SeasonFolders, rootFolderPath = rootFolderPath, qualityProfileId = qualityToUse, titleSlug = model.ParentRequest.Title, seriesType = seriesType, addOptions = new AddOptions { ignoreEpisodesWithFiles = false, // There shouldn't be any episodes with files, this is a new season ignoreEpisodesWithoutFiles = false, // We want all missing searchForMissingEpisodes = false // we want dont want to search yet. We want to make sure everything is unmonitored/monitored correctly. } }; if (sonarrV3) { newSeries.languageProfileId = languageProfileId; } // Montitor the correct seasons, // If we have that season in the model then it's monitored! var seasonsToAdd = GetSeasonsToCreate(model); newSeries.seasons = seasonsToAdd; var result = await SonarrApi.AddSeries(newSeries, s.ApiKey, s.FullUri); existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri); await SendToSonarr(model, existingSeries, s); } else { await SendToSonarr(model, existingSeries, s); } return(new NewSeries { id = existingSeries.id, seasons = existingSeries.seasons.ToList(), cleanTitle = existingSeries.cleanTitle, title = existingSeries.title, tvdbId = existingSeries.tvdbId }); } catch (Exception e) { Logger.LogError(LoggingEvents.SonarrSender, e, "Exception thrown when attempting to send series over to Sonarr"); throw; } }
private async Task <Response> GetTvShows() { var requests = await Service.GetAllAsync(); requests = requests.Where(x => x.Type == RequestType.TvShow); var dbTv = requests; if (Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests) && !IsAdmin) { dbTv = dbTv.Where(x => x.UserHasRequested(Username)).ToList(); } IEnumerable <QualityModel> qualities = new List <QualityModel>(); IEnumerable <RootFolderModel> rootFolders = new List <RootFolderModel>(); var sonarrSettings = await SonarrSettings.GetSettingsAsync(); if (IsAdmin) { try { if (sonarrSettings.Enabled) { var result = await Cache.GetOrSetAsync(CacheKeys.SonarrQualityProfiles, async() => { return(await Task.Run(() => SonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri))); }); qualities = result.Select(x => new QualityModel { Id = x.id.ToString(), Name = x.name }).ToList(); var rootFoldersResult = await Cache.GetOrSetAsync(CacheKeys.SonarrRootFolders, async() => { return(await Task.Run(() => SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri))); }); rootFolders = rootFoldersResult.Select(x => new RootFolderModel { Id = x.id.ToString(), Path = x.path, FreeSpace = x.freespace }).ToList(); } else { var sickRageSettings = await SickRageSettings.GetSettingsAsync(); if (sickRageSettings.Enabled) { qualities = sickRageSettings.Qualities.Select(x => new QualityModel { Id = x.Key, Name = x.Value }).ToList(); } } } catch (Exception e) { Log.Info(e); } } var canManageRequest = Security.HasAnyPermissions(User, Permissions.Administrator, Permissions.ManageRequests); var allowViewUsers = Security.HasAnyPermissions(User, Permissions.Administrator, Permissions.ViewUsers); var viewModel = dbTv.Select(tv => new RequestViewModel { ProviderId = tv.ProviderId, Type = tv.Type, Status = tv.Status, ImdbId = tv.ImdbId, Id = tv.Id, PosterPath = tv.PosterPath?.Contains("http:") ?? false ? tv.PosterPath?.Replace("http:", "https:") : tv.PosterPath ?? string.Empty, // We make the poster path https on request, but this is just incase ReleaseDate = tv.ReleaseDate, ReleaseDateTicks = tv.ReleaseDate.Ticks, RequestedDate = tv.RequestedDate, RequestedDateTicks = DateTimeHelper.OffsetUTCDateTime(tv.RequestedDate, DateTimeOffset).Ticks, Released = DateTime.Now > tv.ReleaseDate, Approved = tv.Available || tv.Approved, Title = tv.Title, Overview = tv.Overview, RequestedUsers = canManageRequest || allowViewUsers ? tv.AllUsers.ToArray() : new string[] { }, ReleaseYear = tv.ReleaseDate.Year.ToString(), Available = tv.Available, Admin = canManageRequest, IssueId = tv.IssueId, Denied = tv.Denied, DeniedReason = tv.DeniedReason, TvSeriesRequestType = tv.SeasonsRequested, Qualities = qualities.ToArray(), Episodes = tv.Episodes.ToArray(), RootFolders = rootFolders.ToArray(), HasRootFolders = rootFolders.Any(), CurrentRootPath = sonarrSettings.Enabled ? GetRootPath(tv.RootFolderSelected, sonarrSettings).Result : null }).ToList(); return(Response.AsJson(viewModel)); }
private Response GetTvShows() // TODO: async await the API calls { var settings = PrSettings.GetSettings(); List <Task> taskList = new List <Task>(); List <RequestedModel> dbTv = new List <RequestedModel>(); taskList.Add(Task.Factory.StartNew(() => { return(Service.GetAll().Where(x => x.Type == RequestType.TvShow)); }).ContinueWith((t) => { dbTv = t.Result.ToList(); if (settings.UsersCanViewOnlyOwnRequests && !IsAdmin) { dbTv = dbTv.Where(x => x.UserHasRequested(Username)).ToList(); } })); List <QualityModel> qualities = new List <QualityModel>(); if (IsAdmin) { var sonarrSettings = SonarrSettings.GetSettings(); if (sonarrSettings.Enabled) { taskList.Add(Task.Factory.StartNew(() => { return(Cache.GetOrSet(CacheKeys.SonarrQualityProfiles, () => { return SonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri); // TODO: cache this! })); }).ContinueWith((t) => { qualities = t.Result.Select(x => new QualityModel() { Id = x.id.ToString(), Name = x.name }).ToList(); })); } else { var sickRageSettings = SickRageSettings.GetSettings(); if (sickRageSettings.Enabled) { qualities = sickRageSettings.Qualities.Select(x => new QualityModel() { Id = x.Key, Name = x.Value }).ToList(); } } } Task.WaitAll(taskList.ToArray()); var viewModel = dbTv.Select(tv => { return(new RequestViewModel { ProviderId = tv.ProviderId, Type = tv.Type, Status = tv.Status, ImdbId = tv.ImdbId, Id = tv.Id, PosterPath = tv.PosterPath, ReleaseDate = tv.ReleaseDate, ReleaseDateTicks = tv.ReleaseDate.Ticks, RequestedDate = tv.RequestedDate, RequestedDateTicks = DateTimeHelper.OffsetUTCDateTime(tv.RequestedDate, DateTimeOffset).Ticks, Released = DateTime.Now > tv.ReleaseDate, Approved = tv.Available || tv.Approved, Title = tv.Title, Overview = tv.Overview, RequestedUsers = IsAdmin ? tv.AllUsers.ToArray() : new string[] { }, ReleaseYear = tv.ReleaseDate.Year.ToString(), Available = tv.Available, Admin = IsAdmin, Issues = tv.Issues.ToString().CamelCaseToWords(), OtherMessage = tv.OtherMessage, AdminNotes = tv.AdminNote, TvSeriesRequestType = tv.SeasonsRequested, Qualities = qualities.ToArray() }); }).ToList(); return(Response.AsJson(viewModel)); }
public async Task <IEnumerable <SonarrProfile> > GetProfiles([FromBody] SonarrSettings settings) { return(await SonarrApi.GetProfiles(settings.ApiKey, settings.FullUri)); }