Skip to content

Commit

Permalink
feat(sonarr): ✨ Add the username to a Sonarr tag when sent to Sonarr (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
tidusjar authored Nov 17, 2022
1 parent 40843fd commit 1d5fabd
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 12 deletions.
3 changes: 2 additions & 1 deletion src/Ombi.Api.Sonarr/ISonarrV3Api.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Api.Sonarr.Models;
using System.Net.Http;
using Ombi.Api.Sonarr.Models.V3;

namespace Ombi.Api.Sonarr
{
public interface ISonarrV3Api : ISonarrApi
{
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);
}
}
1 change: 1 addition & 0 deletions src/Ombi.Api.Sonarr/Models/NewSeries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public NewSeries()
public string seriesType { get; set; }
public int id { get; set; }
public List<SonarrImage> images { get; set; }
public List<int> tags { get; set; }

// V3 Property
public int languageProfileId { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion src/Ombi.Api.Sonarr/Models/SonarrSeries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class SonarrSeries
public string titleSlug { get; set; }
public string certification { get; set; }
public string[] genres { get; set; }
public object[] tags { get; set; }
public List<int> tags { get; set; }
public DateTime added { get; set; }
public Ratings ratings { get; set; }
public int qualityProfileId { get; set; }
Expand Down
18 changes: 17 additions & 1 deletion src/Ombi.Api.Sonarr/SonarrV3Api.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ public class SonarrV3Api : SonarrApi, ISonarrV3Api
{
public SonarrV3Api(IApi api) : base(api)
{

}

protected override string ApiBaseUrl => "/api/v3/";
Expand All @@ -30,5 +29,22 @@ public override async Task<IEnumerable<SonarrProfile>> GetProfiles(string apiKey
request.AddHeader("X-Api-Key", apiKey);
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);
}
}
}
10 changes: 10 additions & 0 deletions src/Ombi.Core/Senders/SonarrSendOptions.cs
Original file line number Diff line number Diff line change
@@ -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>();
}
}
69 changes: 60 additions & 9 deletions src/Ombi.Core/Senders/TvSender.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic;
using Ombi.Api.DogNzb;
using Ombi.Api.DogNzb.Models;
using Ombi.Api.SickRage;
Expand Down Expand Up @@ -155,11 +157,13 @@ public async Task<NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s)
{
return null;
}
var options = new SonarrSendOptions();

int qualityToUse;
var languageProfileId = s.LanguageProfile;
string rootFolderPath;
string seriesType;
int? tagToUse = null;

var profiles = await UserQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == model.RequestedUserId);

Expand Down Expand Up @@ -190,6 +194,7 @@ public async Task<NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s)
}
}
seriesType = "anime";
tagToUse = s.AnimeTag;
}
else
{
Expand All @@ -209,6 +214,7 @@ public async Task<NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s)
}
}
seriesType = "standard";
tagToUse = s.Tag;
}

// Overrides on the request take priority
Expand Down Expand Up @@ -240,6 +246,16 @@ public async Task<NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s)

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?
var allSeries = await SonarrApi.GetSeries(s.ApiKey, s.FullUri);
var existingSeries = allSeries.FirstOrDefault(x => x.tvdbId == model.ParentRequest.TvDbId);
Expand All @@ -265,10 +281,10 @@ public async Task<NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s)
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.
},
languageProfileId = languageProfileId
};
languageProfileId = languageProfileId,
tags = options.Tags
};



// Montitor the correct seasons,
// If we have that season in the model then it's monitored!
Expand All @@ -280,11 +296,11 @@ public async Task<NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s)
throw new Exception(string.Join(',', result.ErrorMessages));
}
existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri);
await SendToSonarr(model, existingSeries, s);
await SendToSonarr(model, existingSeries, s, options);
}
else
{
await SendToSonarr(model, existingSeries, s);
await SendToSonarr(model, existingSeries, s, options);
}

return new NewSeries
Expand All @@ -303,7 +319,30 @@ public async Task<NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s)
}
}

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
Season existingSeason = null;
Expand All @@ -321,15 +360,27 @@ private async Task SendToSonarr(ChildRequests model, SonarrSeries result, Sonarr
}
}

var episodesToUpdate = new List<Episode>();
// Ok, now let's sort out the episodes.
// Does the show have the correct tags we are expecting
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)
{
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 sonarrEpList = sonarrEpisodes.ToList() ?? new List<Episode>();
while (!sonarrEpList.Any())
Expand Down
4 changes: 4 additions & 0 deletions src/Ombi.Settings/Settings/Models/External/SonarrSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ public class SonarrSettings : ExternalSettings

public string QualityProfileAnime { get; set; }
public string RootPathAnime { get; set; }
public int? AnimeTag { get; set; }
public int? Tag { get; set; }
public bool AddOnly { get; set; }
public int LanguageProfile { get; set; }
public int LanguageProfileAnime { get; set; }
public bool ScanForAvailability { get; set; }

public bool SendUserTags { get; set; }
}
}
3 changes: 3 additions & 0 deletions src/Ombi/ClientApp/src/app/interfaces/ISettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ export interface ISonarrSettings extends IExternalSettings {
languageProfile: number;
languageProfileAnime: number;
scanForAvailability: boolean;
sendUserTags: boolean;
tag: number | null;
animeTag: number | null;
}

export interface IRadarrSettings extends IExternalSettings {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
<div class="md-form-field">
<mat-slide-toggle formControlName="scanForAvailability">Scan for Availability</mat-slide-toggle>
</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>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export class SonarrComponent implements OnInit {
languageProfile: [x.languageProfile, [Validators.required, validateProfile]],
languageProfileAnime: [x.languageProfileAnime],
scanForAvailability: [x.scanForAvailability],
sendUserTags: [x.sendUserTags]
});

if (x.qualityProfile) {
Expand Down

0 comments on commit 1d5fabd

Please sign in to comment.