feat(sonarr): Add the username to a Sonarr tag when sent to Sonarr (#4802)

pull/4803/head
Jamie 2 years ago committed by GitHub
parent 40843fd6ac
commit 1d5fabd317
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,7 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Api.Sonarr.Models; using Ombi.Api.Sonarr.Models;
using System.Net.Http;
using Ombi.Api.Sonarr.Models.V3; using Ombi.Api.Sonarr.Models.V3;
namespace Ombi.Api.Sonarr namespace Ombi.Api.Sonarr
@ -9,5 +8,7 @@ namespace Ombi.Api.Sonarr
public interface ISonarrV3Api : ISonarrApi public interface ISonarrV3Api : ISonarrApi
{ {
Task<IEnumerable<LanguageProfiles>> LanguageProfiles(string apiKey, string baseUrl); Task<IEnumerable<LanguageProfiles>> LanguageProfiles(string apiKey, string baseUrl);
Task<Tag> CreateTag(string apiKey, string baseUrl, string tagName);
Task<Tag> GetTag(int tagId, string apiKey, string baseUrl);
} }
} }

@ -26,6 +26,7 @@ namespace Ombi.Api.Sonarr.Models
public string seriesType { get; set; } public string seriesType { get; set; }
public int id { get; set; } public int id { get; set; }
public List<SonarrImage> images { get; set; } public List<SonarrImage> images { get; set; }
public List<int> tags { get; set; }
// V3 Property // V3 Property
public int languageProfileId { get; set; } public int languageProfileId { get; set; }

@ -40,7 +40,7 @@ namespace Ombi.Api.Sonarr.Models
public string titleSlug { get; set; } public string titleSlug { get; set; }
public string certification { get; set; } public string certification { get; set; }
public string[] genres { get; set; } public string[] genres { get; set; }
public object[] tags { get; set; } public List<int> tags { get; set; }
public DateTime added { get; set; } public DateTime added { get; set; }
public Ratings ratings { get; set; } public Ratings ratings { get; set; }
public int qualityProfileId { get; set; } public int qualityProfileId { get; set; }

@ -11,7 +11,6 @@ namespace Ombi.Api.Sonarr
{ {
public SonarrV3Api(IApi api) : base(api) public SonarrV3Api(IApi api) : base(api)
{ {
} }
protected override string ApiBaseUrl => "/api/v3/"; protected override string ApiBaseUrl => "/api/v3/";
@ -30,5 +29,22 @@ namespace Ombi.Api.Sonarr
request.AddHeader("X-Api-Key", apiKey); request.AddHeader("X-Api-Key", apiKey);
return await Api.Request<List<SonarrProfile>>(request); return await Api.Request<List<SonarrProfile>>(request);
} }
public Task<Tag> CreateTag(string apiKey, string baseUrl, string tagName)
{
var request = new Request($"{ApiBaseUrl}tag", baseUrl, HttpMethod.Post);
request.AddHeader("X-Api-Key", apiKey);
request.AddJsonBody(new { Label = tagName });
return Api.Request<Tag>(request);
}
public Task<Tag> GetTag(int tagId, string apiKey, string baseUrl)
{
var request = new Request($"{ApiBaseUrl}tag/{tagId}", baseUrl, HttpMethod.Get);
request.AddHeader("X-Api-Key", apiKey);
return Api.Request<Tag>(request);
}
} }
} }

@ -0,0 +1,10 @@
using Ombi.Api.Sonarr.Models;
using System.Collections.Generic;
namespace Ombi.Core.Senders
{
internal class SonarrSendOptions
{
public List<int> Tags { get; set; } = new List<int>();
}
}

@ -1,9 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic;
using Ombi.Api.DogNzb; using Ombi.Api.DogNzb;
using Ombi.Api.DogNzb.Models; using Ombi.Api.DogNzb.Models;
using Ombi.Api.SickRage; using Ombi.Api.SickRage;
@ -155,11 +157,13 @@ namespace Ombi.Core.Senders
{ {
return null; return null;
} }
var options = new SonarrSendOptions();
int qualityToUse; int qualityToUse;
var languageProfileId = s.LanguageProfile; var languageProfileId = s.LanguageProfile;
string rootFolderPath; string rootFolderPath;
string seriesType; string seriesType;
int? tagToUse = null;
var profiles = await UserQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == model.RequestedUserId); var profiles = await UserQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == model.RequestedUserId);
@ -190,6 +194,7 @@ namespace Ombi.Core.Senders
} }
} }
seriesType = "anime"; seriesType = "anime";
tagToUse = s.AnimeTag;
} }
else else
{ {
@ -209,6 +214,7 @@ namespace Ombi.Core.Senders
} }
} }
seriesType = "standard"; seriesType = "standard";
tagToUse = s.Tag;
} }
// Overrides on the request take priority // Overrides on the request take priority
@ -240,6 +246,16 @@ namespace Ombi.Core.Senders
try try
{ {
if (tagToUse.HasValue)
{
options.Tags.Add(tagToUse.Value);
}
if (s.SendUserTags)
{
var userTag = await GetOrCreateTag(model, s);
options.Tags.Add(userTag.id);
}
// Does the series actually exist? // Does the series actually exist?
var allSeries = await SonarrApi.GetSeries(s.ApiKey, s.FullUri); var allSeries = await SonarrApi.GetSeries(s.ApiKey, s.FullUri);
var existingSeries = allSeries.FirstOrDefault(x => x.tvdbId == model.ParentRequest.TvDbId); var existingSeries = allSeries.FirstOrDefault(x => x.tvdbId == model.ParentRequest.TvDbId);
@ -265,10 +281,10 @@ namespace Ombi.Core.Senders
ignoreEpisodesWithoutFiles = false, // We want all missing 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. searchForMissingEpisodes = false // we want dont want to search yet. We want to make sure everything is unmonitored/monitored correctly.
}, },
languageProfileId = languageProfileId languageProfileId = languageProfileId,
}; tags = options.Tags
};
// Montitor the correct seasons, // Montitor the correct seasons,
// If we have that season in the model then it's monitored! // If we have that season in the model then it's monitored!
@ -280,11 +296,11 @@ namespace Ombi.Core.Senders
throw new Exception(string.Join(',', result.ErrorMessages)); throw new Exception(string.Join(',', result.ErrorMessages));
} }
existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri); existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri);
await SendToSonarr(model, existingSeries, s); await SendToSonarr(model, existingSeries, s, options);
} }
else else
{ {
await SendToSonarr(model, existingSeries, s); await SendToSonarr(model, existingSeries, s, options);
} }
return new NewSeries return new NewSeries
@ -303,7 +319,30 @@ namespace Ombi.Core.Senders
} }
} }
private async Task SendToSonarr(ChildRequests model, SonarrSeries result, SonarrSettings s) private async Task<Tag> GetOrCreateTag(ChildRequests model, SonarrSettings s)
{
var tagName = model.RequestedUser.UserName;
// Does tag exist?
var allTags = await SonarrV3Api.GetTags(s.ApiKey, s.FullUri);
var existingTag = allTags.FirstOrDefault(x => x.label.Equals(tagName, StringComparison.InvariantCultureIgnoreCase));
existingTag ??= await SonarrV3Api.CreateTag(s.ApiKey, s.FullUri, tagName);
return existingTag;
}
private async Task<Tag> GetTag(int tagId, SonarrSettings s)
{
var tag = await SonarrV3Api.GetTag(tagId, s.ApiKey, s.FullUri);
if (tag == null)
{
Logger.LogError($"Tag ID {tagId} does not exist in sonarr. Please update the settings");
return null;
}
return tag;
}
private async Task SendToSonarr(ChildRequests model, SonarrSeries result, SonarrSettings s, SonarrSendOptions options)
{ {
// Check to ensure we have the all the seasons, ensure the Sonarr metadata has grabbed all the data // Check to ensure we have the all the seasons, ensure the Sonarr metadata has grabbed all the data
Season existingSeason = null; Season existingSeason = null;
@ -321,15 +360,27 @@ namespace Ombi.Core.Senders
} }
} }
var episodesToUpdate = new List<Episode>(); // Does the show have the correct tags we are expecting
// Ok, now let's sort out the episodes. if (options.Tags.Any())
{
result.tags ??= options.Tags;
var tagsToAdd = options.Tags.Except(result.tags);
if (tagsToAdd.Any())
{
result.tags.AddRange(tagsToAdd);
}
result = await SonarrApi.UpdateSeries(result, s.ApiKey, s.FullUri);
}
if (model.SeriesType == SeriesType.Anime) if (model.SeriesType == SeriesType.Anime)
{ {
result.seriesType = "anime"; result.seriesType = "anime";
await SonarrApi.UpdateSeries(result, s.ApiKey, s.FullUri); result = await SonarrApi.UpdateSeries(result, s.ApiKey, s.FullUri);
} }
var episodesToUpdate = new List<Episode>();
// Ok, now let's sort out the episodes.
var sonarrEpisodes = await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri); var sonarrEpisodes = await SonarrApi.GetEpisodes(result.id, s.ApiKey, s.FullUri);
var sonarrEpList = sonarrEpisodes.ToList() ?? new List<Episode>(); var sonarrEpList = sonarrEpisodes.ToList() ?? new List<Episode>();
while (!sonarrEpList.Any()) while (!sonarrEpList.Any())

@ -17,9 +17,13 @@
public string QualityProfileAnime { get; set; } public string QualityProfileAnime { get; set; }
public string RootPathAnime { get; set; } public string RootPathAnime { get; set; }
public int? AnimeTag { get; set; }
public int? Tag { get; set; }
public bool AddOnly { get; set; } public bool AddOnly { get; set; }
public int LanguageProfile { get; set; } public int LanguageProfile { get; set; }
public int LanguageProfileAnime { get; set; } public int LanguageProfileAnime { get; set; }
public bool ScanForAvailability { get; set; } public bool ScanForAvailability { get; set; }
public bool SendUserTags { get; set; }
} }
} }

@ -146,6 +146,9 @@ export interface ISonarrSettings extends IExternalSettings {
languageProfile: number; languageProfile: number;
languageProfileAnime: number; languageProfileAnime: number;
scanForAvailability: boolean; scanForAvailability: boolean;
sendUserTags: boolean;
tag: number | null;
animeTag: number | null;
} }
export interface IRadarrSettings extends IExternalSettings { export interface IRadarrSettings extends IExternalSettings {

@ -16,6 +16,10 @@
<div class="md-form-field"> <div class="md-form-field">
<mat-slide-toggle formControlName="scanForAvailability">Scan for Availability</mat-slide-toggle> <mat-slide-toggle formControlName="scanForAvailability">Scan for Availability</mat-slide-toggle>
</div> </div>
<div class="md-form-field">
<mat-slide-toggle formControlName="sendUserTags" id="sendUserTags">Add the user as a tag</mat-slide-toggle>
<small><br>This will add the username of the requesting user as a tag in Sonarr. If the tag doesn't exist, Ombi will create it.</small>
</div>
<div class="md-form-field" style="margin-top:1em;"></div> <div class="md-form-field" style="margin-top:1em;"></div>
</div> </div>
</div> </div>

@ -75,6 +75,7 @@ export class SonarrComponent implements OnInit {
languageProfile: [x.languageProfile, [Validators.required, validateProfile]], languageProfile: [x.languageProfile, [Validators.required, validateProfile]],
languageProfileAnime: [x.languageProfileAnime], languageProfileAnime: [x.languageProfileAnime],
scanForAvailability: [x.scanForAvailability], scanForAvailability: [x.scanForAvailability],
sendUserTags: [x.sendUserTags]
}); });
if (x.qualityProfile) { if (x.qualityProfile) {

Loading…
Cancel
Save