mirror of https://github.com/Ombi-app/Ombi
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
581 lines
25 KiB
581 lines
25 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging;
|
|
using Ombi.Api.DogNzb;
|
|
using Ombi.Api.DogNzb.Models;
|
|
using Ombi.Api.SickRage;
|
|
using Ombi.Api.SickRage.Models;
|
|
using Ombi.Api.Sonarr;
|
|
using Ombi.Api.Sonarr.Models;
|
|
using Ombi.Core.Settings;
|
|
using Ombi.Helpers;
|
|
using Ombi.Settings.Settings.Models.External;
|
|
using Ombi.Store.Entities;
|
|
using Ombi.Store.Entities.Requests;
|
|
using Ombi.Store.Repository;
|
|
|
|
namespace Ombi.Core.Senders
|
|
{
|
|
public class TvSender : ITvSender
|
|
{
|
|
public TvSender(ISonarrApi sonarrApi, ISonarrV3Api sonarrV3Api, ILogger<TvSender> log, ISettingsService<SonarrSettings> sonarrSettings,
|
|
ISettingsService<DogNzbSettings> dog, IDogNzbApi dogApi, ISettingsService<SickRageSettings> srSettings,
|
|
ISickRageApi srApi, IRepository<UserQualityProfiles> userProfiles, IRepository<RequestQueue> requestQueue, INotificationHelper notify)
|
|
{
|
|
SonarrApi = sonarrApi;
|
|
SonarrV3Api = sonarrV3Api;
|
|
Logger = log;
|
|
SonarrSettings = sonarrSettings;
|
|
DogNzbSettings = dog;
|
|
DogNzbApi = dogApi;
|
|
SickRageSettings = srSettings;
|
|
SickRageApi = srApi;
|
|
UserQualityProfiles = userProfiles;
|
|
_requestQueueRepository = requestQueue;
|
|
_notificationHelper = notify;
|
|
}
|
|
|
|
private ISonarrApi SonarrApi { get; }
|
|
private ISonarrV3Api SonarrV3Api { get; }
|
|
private IDogNzbApi DogNzbApi { get; }
|
|
private ISickRageApi SickRageApi { get; }
|
|
private ILogger<TvSender> Logger { get; }
|
|
private ISettingsService<SonarrSettings> SonarrSettings { get; }
|
|
private ISettingsService<DogNzbSettings> DogNzbSettings { get; }
|
|
private ISettingsService<SickRageSettings> SickRageSettings { get; }
|
|
private IRepository<UserQualityProfiles> UserQualityProfiles { get; }
|
|
private readonly IRepository<RequestQueue> _requestQueueRepository;
|
|
private readonly INotificationHelper _notificationHelper;
|
|
|
|
public async Task<SenderResult> Send(ChildRequests model)
|
|
{
|
|
try
|
|
{
|
|
var sonarr = await SonarrSettings.GetSettingsAsync();
|
|
if (sonarr.Enabled)
|
|
{
|
|
var result = await SendToSonarr(model, sonarr);
|
|
if (result != null)
|
|
{
|
|
return new SenderResult
|
|
{
|
|
Sent = true,
|
|
Success = true
|
|
};
|
|
}
|
|
}
|
|
var dog = await DogNzbSettings.GetSettingsAsync();
|
|
if (dog.Enabled)
|
|
{
|
|
var result = await SendToDogNzb(model, dog);
|
|
if (!result.Failure)
|
|
{
|
|
return new SenderResult
|
|
{
|
|
Sent = true,
|
|
Success = true
|
|
};
|
|
}
|
|
return new SenderResult
|
|
{
|
|
Message = result.ErrorMessage
|
|
};
|
|
}
|
|
var sr = await SickRageSettings.GetSettingsAsync();
|
|
if (sr.Enabled)
|
|
{
|
|
var result = await SendToSickRage(model, sr);
|
|
if (result)
|
|
{
|
|
return new SenderResult
|
|
{
|
|
Sent = true,
|
|
Success = true
|
|
};
|
|
}
|
|
return new SenderResult
|
|
{
|
|
Message = "Could not send to SickRage!"
|
|
};
|
|
}
|
|
return new SenderResult
|
|
{
|
|
Success = true
|
|
};
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.LogError(e, "Exception thrown when sending a movie to DVR app, added to the request queue");
|
|
// Check if already in request queue
|
|
var existingQueue = await _requestQueueRepository.FirstOrDefaultAsync(x => x.RequestId == model.Id);
|
|
if (existingQueue != null)
|
|
{
|
|
existingQueue.RetryCount++;
|
|
existingQueue.Error = e.Message;
|
|
await _requestQueueRepository.SaveChangesAsync();
|
|
}
|
|
else
|
|
{
|
|
await _requestQueueRepository.Add(new RequestQueue
|
|
{
|
|
Dts = DateTime.UtcNow,
|
|
Error = e.Message,
|
|
RequestId = model.Id,
|
|
Type = RequestType.TvShow,
|
|
RetryCount = 0
|
|
});
|
|
await _notificationHelper.Notify(model, NotificationType.ItemAddedToFaultQueue);
|
|
}
|
|
}
|
|
|
|
return new SenderResult
|
|
{
|
|
Success = false,
|
|
Message = "Something went wrong!"
|
|
};
|
|
}
|
|
|
|
private async Task<DogNzbAddResult> SendToDogNzb(ChildRequests model, DogNzbSettings settings)
|
|
{
|
|
var id = model.ParentRequest.ExternalProviderId;
|
|
return await DogNzbApi.AddTvShow(settings.ApiKey, id.ToString());
|
|
}
|
|
|
|
/// <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;
|
|
var sonarrV3 = s.V3;
|
|
var languageProfileId = s.LanguageProfile;
|
|
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
|
|
if (!int.TryParse(s.RootPathAnime, out int animePath))
|
|
{
|
|
animePath = int.Parse(s.RootPath); // Set it to the main root folder if we have no anime folder.
|
|
}
|
|
rootFolderPath = await GetSonarrRootPath(animePath, s);
|
|
languageProfileId = s.LanguageProfileAnime > 0 ? s.LanguageProfileAnime : s.LanguageProfile;
|
|
|
|
if (!int.TryParse(s.QualityProfileAnime, out qualityToUse))
|
|
{
|
|
qualityToUse = int.Parse(s.QualityProfile);
|
|
}
|
|
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(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)
|
|
{
|
|
var qualityOverride = model.ParentRequest.QualityOverride.Value;
|
|
if (qualityOverride > 0)
|
|
{
|
|
qualityToUse = qualityOverride;
|
|
}
|
|
}
|
|
if (model.ParentRequest.RootFolder.HasValue)
|
|
{
|
|
var rootfolderOverride = model.ParentRequest.RootFolder.Value;
|
|
if (rootfolderOverride > 0)
|
|
{
|
|
rootFolderPath = await GetSonarrRootPath(rootfolderOverride, s);
|
|
}
|
|
}
|
|
|
|
if (model.ParentRequest.LanguageProfile.HasValue)
|
|
{
|
|
var languageProfile = model.ParentRequest.LanguageProfile.Value;
|
|
if (languageProfile > 0)
|
|
{
|
|
languageProfileId = 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);
|
|
if (result?.ErrorMessages?.Any() ?? false)
|
|
{
|
|
throw new Exception(string.Join(',', result.ErrorMessages));
|
|
}
|
|
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 SendToSonarr(ChildRequests model, SonarrSeries result, SonarrSettings s)
|
|
{
|
|
// Check to ensure we have the all the seasons, ensure the Sonarr metadata has grabbed all the data
|
|
Season existingSeason = null;
|
|
foreach (var season in model.SeasonRequests)
|
|
{
|
|
var attempt = 0;
|
|
existingSeason = result.seasons.FirstOrDefault(x => x.seasonNumber == season.SeasonNumber);
|
|
while (existingSeason == null && attempt < 5)
|
|
{
|
|
attempt++;
|
|
Logger.LogInformation("There was no season numer {0} in Sonarr for title {1}. Will try again as the metadata did not get created", season.SeasonNumber, model.ParentRequest.Title);
|
|
result = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri);
|
|
existingSeason = result.seasons.FirstOrDefault(x => x.seasonNumber == season.SeasonNumber);
|
|
await Task.Delay(500);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
var seriesChanges = false;
|
|
|
|
foreach (var season in model.SeasonRequests)
|
|
{
|
|
foreach (var ep in season.Episodes)
|
|
{
|
|
var sonarrEp = sonarrEpList.FirstOrDefault(x =>
|
|
x.episodeNumber == ep.EpisodeNumber && x.seasonNumber == season.SeasonNumber);
|
|
if (sonarrEp != null && !sonarrEp.monitored)
|
|
{
|
|
sonarrEp.monitored = true;
|
|
episodesToUpdate.Add(sonarrEp);
|
|
}
|
|
}
|
|
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);
|
|
|
|
|
|
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;
|
|
}
|
|
// 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);
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
private static List<Season> GetSeasonsToCreate(ChildRequests model)
|
|
{
|
|
// Let's get a list of seasons just incase we need to change it
|
|
var seasonsToUpdate = new List<Season>();
|
|
for (var i = 0; i < model.ParentRequest.TotalSeasons + 1; i++)
|
|
{
|
|
var index = i;
|
|
var sea = new Season
|
|
{
|
|
seasonNumber = i,
|
|
monitored = false
|
|
};
|
|
seasonsToUpdate.Add(sea);
|
|
}
|
|
|
|
return seasonsToUpdate;
|
|
}
|
|
|
|
private async Task<bool> SendToSickRage(ChildRequests model, SickRageSettings settings, string qualityId = null)
|
|
{
|
|
var tvdbid = model.ParentRequest.TvDbId;
|
|
if (qualityId.HasValue())
|
|
{
|
|
var id = qualityId;
|
|
if (settings.Qualities.All(x => x.Value != id))
|
|
{
|
|
qualityId = settings.QualityProfile;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
qualityId = settings.QualityProfile;
|
|
}
|
|
// Check if the show exists
|
|
var existingShow = await SickRageApi.GetShow(tvdbid, settings.ApiKey, settings.FullUri);
|
|
|
|
if (existingShow.message.Equals("Show not found", StringComparison.CurrentCultureIgnoreCase))
|
|
{
|
|
var addResult = await SickRageApi.AddSeries(model.ParentRequest.TvDbId, qualityId, SickRageStatus.Ignored,
|
|
settings.ApiKey, settings.FullUri);
|
|
|
|
Logger.LogDebug("Added the show (tvdbid) {0}. The result is '{2}' : '{3}'", tvdbid, addResult.result, addResult.message);
|
|
if (addResult.result.Equals("failure") || addResult.result.Equals("fatal"))
|
|
{
|
|
// Do something
|
|
return false;
|
|
}
|
|
}
|
|
|
|
foreach (var seasonRequests in model.SeasonRequests)
|
|
{
|
|
var srEpisodes = await SickRageApi.GetEpisodesForSeason(tvdbid, seasonRequests.SeasonNumber, settings.ApiKey, settings.FullUri);
|
|
int retryTimes = 10;
|
|
var currentRetry = 0;
|
|
while (srEpisodes.message.Equals("Show not found", StringComparison.CurrentCultureIgnoreCase) || srEpisodes.message.Equals("Season not found", StringComparison.CurrentCultureIgnoreCase) && srEpisodes.data.Count <= 0)
|
|
{
|
|
if (currentRetry > retryTimes)
|
|
{
|
|
Logger.LogWarning("Couldnt find the SR Season or Show, message: {0}", srEpisodes.message);
|
|
break;
|
|
}
|
|
await Task.Delay(TimeSpan.FromSeconds(1));
|
|
currentRetry++;
|
|
srEpisodes = await SickRageApi.GetEpisodesForSeason(tvdbid, seasonRequests.SeasonNumber, settings.ApiKey, settings.FullUri);
|
|
}
|
|
|
|
var totalSrEpisodes = srEpisodes.data.Count;
|
|
|
|
if (totalSrEpisodes == seasonRequests.Episodes.Count)
|
|
{
|
|
// This is a request for the whole season
|
|
var wholeSeasonResult = await SickRageApi.SetEpisodeStatus(settings.ApiKey, settings.FullUri, tvdbid, SickRageStatus.Wanted,
|
|
seasonRequests.SeasonNumber);
|
|
|
|
Logger.LogDebug("Set the status to Wanted for season {0}. The result is '{1}' : '{2}'", seasonRequests.SeasonNumber, wholeSeasonResult.result, wholeSeasonResult.message);
|
|
continue;
|
|
}
|
|
|
|
foreach (var srEp in srEpisodes.data)
|
|
{
|
|
var epNumber = srEp.Key;
|
|
var epData = srEp.Value;
|
|
|
|
var epRequest = seasonRequests.Episodes.FirstOrDefault(x => x.EpisodeNumber == epNumber);
|
|
if (epRequest != null)
|
|
{
|
|
// We want to monior this episode since we have a request for it
|
|
// Let's check to see if it's wanted first, save an api call
|
|
if (epData.status.Equals(SickRageStatus.Wanted, StringComparison.CurrentCultureIgnoreCase))
|
|
{
|
|
continue;
|
|
}
|
|
var epResult = await SickRageApi.SetEpisodeStatus(settings.ApiKey, settings.FullUri, tvdbid,
|
|
SickRageStatus.Wanted, seasonRequests.SeasonNumber, epNumber);
|
|
|
|
Logger.LogDebug("Set the status to Wanted for Episode {0} in season {1}. The result is '{2}' : '{3}'", seasonRequests.SeasonNumber, epNumber, epResult.result, epResult.message);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|