Added the lidarr sync !wip

pull/2478/head
Jamie 6 years ago
parent d47e7a7c57
commit 207c60b7f8

@ -14,5 +14,7 @@ namespace Ombi.Api.Lidarr
Task<ArtistResult> GetArtistByForeignId(string foreignArtistId, string apiKey, string baseUrl);
Task<AlbumByArtistResponse> GetAlbumsByArtist(int artistId, string apiKey, string baseUrl);
Task<AlbumLookup> GetAlbumByForeignId(string foreignArtistId, string apiKey, string baseUrl);
Task<List<ArtistResult>> GetArtists(string apiKey, string baseUrl);
Task<List<AlbumByArtistResponse>> GetAllAlbums(string apiKey, string baseUrl);
}
}

@ -72,7 +72,6 @@ namespace Ombi.Api.Lidarr
return Api.Request<ArtistResult>(request);
}
public async Task<AlbumLookup> GetAlbumByForeignId(string foreignArtistId, string apiKey, string baseUrl)
{
var request = new Request($"{ApiVersion}/album/lookup", baseUrl, HttpMethod.Get);
@ -92,6 +91,22 @@ namespace Ombi.Api.Lidarr
return Api.Request<AlbumByArtistResponse>(request);
}
public Task<List<ArtistResult>> GetArtists(string apiKey, string baseUrl)
{
var request = new Request($"{ApiVersion}/artist", baseUrl, HttpMethod.Get);
AddHeaders(request, apiKey);
return Api.Request<List<ArtistResult>>(request);
}
public Task<List<AlbumByArtistResponse>> GetAllAlbums(string apiKey, string baseUrl)
{
var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get);
AddHeaders(request, apiKey);
return Api.Request<List<AlbumByArtistResponse>>(request);
}
private void AddHeaders(Request request, string key)
{
request.AddHeader("X-Api-Key", key);

@ -54,9 +54,11 @@ using PlexContentCacher = Ombi.Schedule.Jobs.Plex;
using Ombi.Api.Telegram;
using Ombi.Core.Authentication;
using Ombi.Core.Processor;
using Ombi.Schedule.Jobs.Lidarr;
using Ombi.Schedule.Jobs.Plex.Interfaces;
using Ombi.Schedule.Jobs.SickRage;
using Ombi.Schedule.Processor;
using Ombi.Store.Entities;
namespace Ombi.DependencyInjection
{
@ -185,6 +187,8 @@ namespace Ombi.DependencyInjection
services.AddTransient<IRefreshMetadata, RefreshMetadata>();
services.AddTransient<INewsletterJob, NewsletterJob>();
services.AddTransient<IPlexRecentlyAddedSync, PlexRecentlyAddedSync>();
services.AddTransient<ILidarrAlbumSync, LidarrAlbumSync>();
services.AddTransient<ILidarrArtistSync, LidarrArtistSync>();
}
}
}

@ -20,6 +20,7 @@ namespace Ombi.Helpers
public static EventId CouchPotatoCacher => new EventId(2007);
public static EventId PlexContentCacher => new EventId(2008);
public static EventId SickRageCacher => new EventId(2009);
public static EventId LidarrArtistCache => new EventId(2010);
public static EventId MovieSender => new EventId(3000);

@ -4,6 +4,7 @@ using Ombi.Core.Settings;
using Ombi.Schedule.Jobs;
using Ombi.Schedule.Jobs.Couchpotato;
using Ombi.Schedule.Jobs.Emby;
using Ombi.Schedule.Jobs.Lidarr;
using Ombi.Schedule.Jobs.Ombi;
using Ombi.Schedule.Jobs.Plex;
using Ombi.Schedule.Jobs.Radarr;
@ -19,7 +20,7 @@ namespace Ombi.Schedule
IOmbiAutomaticUpdater updater, IEmbyContentSync embySync, IPlexUserImporter userImporter,
IEmbyUserImporter embyUserImporter, ISonarrSync cache, ICouchPotatoSync cpCache,
ISettingsService<JobSettings> jobsettings, ISickRageSync srSync, IRefreshMetadata refresh,
INewsletterJob newsletter, IPlexRecentlyAddedSync recentlyAddedPlex)
INewsletterJob newsletter, IPlexRecentlyAddedSync recentlyAddedPlex, ILidarrArtistSync artist)
{
_plexContentSync = plexContentSync;
_radarrSync = radarrSync;
@ -34,6 +35,7 @@ namespace Ombi.Schedule
_refreshMetadata = refresh;
_newsletter = newsletter;
_plexRecentlyAddedSync = recentlyAddedPlex;
_lidarrArtistSync = artist;
}
private readonly IPlexContentSync _plexContentSync;
@ -49,6 +51,7 @@ namespace Ombi.Schedule
private readonly ISettingsService<JobSettings> _jobSettings;
private readonly IRefreshMetadata _refreshMetadata;
private readonly INewsletterJob _newsletter;
private readonly ILidarrArtistSync _lidarrArtistSync;
public void Setup()
{
@ -62,6 +65,7 @@ namespace Ombi.Schedule
RecurringJob.AddOrUpdate(() => _cpCache.Start(), JobSettingsHelper.CouchPotato(s));
RecurringJob.AddOrUpdate(() => _srSync.Start(), JobSettingsHelper.SickRageSync(s));
RecurringJob.AddOrUpdate(() => _refreshMetadata.Start(), JobSettingsHelper.RefreshMetadata(s));
RecurringJob.AddOrUpdate(() => _lidarrArtistSync.CacheContent(), JobSettingsHelper.LidarrArtistSync(s));
RecurringJob.AddOrUpdate(() => _updater.Update(null), JobSettingsHelper.Updater(s));

@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Store.Entities;
namespace Ombi.Schedule.Jobs.Lidarr
{
public interface ILidarrAlbumSync
{
Task CacheContent();
void Dispose();
Task<IEnumerable<LidarrAlbumCache>> GetCachedContent();
}
}

@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Store.Entities;
namespace Ombi.Schedule.Jobs.Lidarr
{
public interface ILidarrArtistSync
{
Task CacheContent();
void Dispose();
Task<IEnumerable<LidarrArtistCache>> GetCachedContent();
}
}

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.Extensions.Logging;
using Ombi.Api.Lidarr;
using Ombi.Api.Radarr;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Context;
using Ombi.Store.Entities;
using Serilog;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace Ombi.Schedule.Jobs.Lidarr
{
public class LidarrAlbumSync : ILidarrAlbumSync
{
public LidarrAlbumSync(ISettingsService<LidarrSettings> lidarr, ILidarrApi lidarrApi, ILogger<LidarrAlbumSync> log, IOmbiContext ctx)
{
_lidarrSettings = lidarr;
_lidarrApi = lidarrApi;
_logger = log;
_ctx = ctx;
_lidarrSettings.ClearCache();
}
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
private readonly ILidarrApi _lidarrApi;
private readonly ILogger _logger;
private readonly IOmbiContext _ctx;
public async Task CacheContent()
{
try
{
var settings = await _lidarrSettings.GetSettingsAsync();
if (settings.Enabled)
{
try
{
var albums = await _lidarrApi.GetAllAlbums(settings.ApiKey, settings.FullUri);
if (albums != null && albums.Any())
{
// Let's remove the old cached data
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM LidarrAlbumCache");
var artistCache = new List<LidarrAlbumCache>();
foreach (var a in albums)
{
if (a.id > 0)
{
artistCache.Add(new LidarrAlbumCache
{
ArtistId = a.artistId,
ForeignAlbumId = a.foreignAlbumId,
ReleaseDate = a.releaseDate,
TrackCount = a.currentRelease.trackCount,
Monitored = a.monitored,
Title = a.title
});
}
}
await _ctx.LidarrAlbumCache.AddRangeAsync(artistCache);
await _ctx.SaveChangesAsync();
}
}
catch (System.Exception ex)
{
_logger.LogError(LoggingEvents.Cacher, ex, "Failed caching queued items from Lidarr Album");
}
}
}
catch (Exception)
{
_logger.LogInformation(LoggingEvents.LidarrArtistCache, "Lidarr is not setup, cannot cache Album");
}
}
public async Task<IEnumerable<LidarrAlbumCache>> GetCachedContent()
{
return await _ctx.LidarrAlbumCache.ToListAsync();
}
private bool _disposed;
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_ctx?.Dispose();
_lidarrSettings?.Dispose();
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Hangfire;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.Extensions.Logging;
using Ombi.Api.Lidarr;
using Ombi.Api.Radarr;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Context;
using Ombi.Store.Entities;
using Serilog;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace Ombi.Schedule.Jobs.Lidarr
{
public class LidarrArtistSync : ILidarrArtistSync
{
public LidarrArtistSync(ISettingsService<LidarrSettings> lidarr, ILidarrApi lidarrApi, ILogger<LidarrArtistSync> log, IOmbiContext ctx,
IBackgroundJobClient background, ILidarrAlbumSync album)
{
_lidarrSettings = lidarr;
_lidarrApi = lidarrApi;
_logger = log;
_ctx = ctx;
_job = background;
_albumSync = album;
_lidarrSettings.ClearCache();
}
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
private readonly ILidarrApi _lidarrApi;
private readonly ILogger _logger;
private readonly IOmbiContext _ctx;
private readonly IBackgroundJobClient _job;
private readonly ILidarrAlbumSync _albumSync;
public async Task CacheContent()
{
try
{
var settings = await _lidarrSettings.GetSettingsAsync();
if (settings.Enabled)
{
try
{
var artists = await _lidarrApi.GetArtists(settings.ApiKey, settings.FullUri);
if (artists != null && artists.Any())
{
// Let's remove the old cached data
await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM LidarrArtistCache");
var artistCache = new List<LidarrArtistCache>();
foreach (var a in artists)
{
if (a.id > 0)
{
artistCache.Add(new LidarrArtistCache
{
ArtistId = a.id,
ArtistName = a.artistName,
ForeignArtistId = a.foreignArtistId,
Monitored = a.monitored
});
}
}
await _ctx.LidarrArtistCache.AddRangeAsync(artistCache);
await _ctx.SaveChangesAsync();
}
}
catch (Exception ex)
{
_logger.LogError(LoggingEvents.Cacher, ex, "Failed caching queued items from Lidarr");
}
_job.Enqueue(() => _albumSync.CacheContent());
}
}
catch (Exception)
{
_logger.LogInformation(LoggingEvents.LidarrArtistCache, "Lidarr is not setup, cannot cache Artist");
}
}
public async Task<IEnumerable<LidarrArtistCache>> GetCachedContent()
{
return await _ctx.LidarrArtistCache.ToListAsync();
}
private bool _disposed;
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_ctx?.Dispose();
_lidarrSettings?.Dispose();
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}

@ -27,6 +27,7 @@
<ItemGroup>
<ProjectReference Include="..\Ombi.Api.CouchPotato\Ombi.Api.CouchPotato.csproj" />
<ProjectReference Include="..\Ombi.Api.Emby\Ombi.Api.Emby.csproj" />
<ProjectReference Include="..\Ombi.Api.Lidarr\Ombi.Api.Lidarr.csproj" />
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
<ProjectReference Include="..\Ombi.Api.Radarr\Ombi.Api.Radarr.csproj" />
<ProjectReference Include="..\Ombi.Api.Service\Ombi.Api.Service.csproj" />

@ -13,5 +13,6 @@
public string SickRageSync { get; set; }
public string RefreshMetadata { get; set; }
public string Newsletter { get; set; }
public string LidarrArtistSync { get; set; }
}
}

@ -52,6 +52,10 @@ namespace Ombi.Settings.Settings.Models
{
return Get(s.RefreshMetadata, Cron.DayInterval(3));
}
public static string LidarrArtistSync(JobSettings s)
{
return Get(s.LidarrArtistSync, Cron.Hourly(40));
}
private static string Get(string settings, string defaultCron)
{

@ -40,6 +40,8 @@ namespace Ombi.Store.Context
EntityEntry<TEntity> Update<TEntity>(TEntity entity) where TEntity : class;
DbSet<CouchPotatoCache> CouchPotatoCache { get; set; }
DbSet<SickRageCache> SickRageCache { get; set; }
DbSet<LidarrArtistCache> LidarrArtistCache { get; set; }
DbSet<LidarrAlbumCache> LidarrAlbumCache { get; set; }
DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
DbSet<RequestLog> RequestLogs { get; set; }
DbSet<RecentlyAddedLog> RecentlyAddedLogs { get; set; }

@ -45,6 +45,8 @@ namespace Ombi.Store.Context
public DbSet<Audit> Audit { get; set; }
public DbSet<Tokens> Tokens { get; set; }
public DbSet<SonarrCache> SonarrCache { get; set; }
public DbSet<LidarrArtistCache> LidarrArtistCache { get; set; }
public DbSet<LidarrAlbumCache> LidarrAlbumCache { get; set; }
public DbSet<SonarrEpisodeCache> SonarrEpisodeCache { get; set; }
public DbSet<SickRageCache> SickRageCache { get; set; }
public DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }

@ -0,0 +1,19 @@
using System;
using System.ComponentModel.DataAnnotations.Schema;
namespace Ombi.Store.Entities
{
[Table("LidarrAlbumCache")]
public class LidarrAlbumCache : Entity
{
public int ArtistId { get; set; }
public string ForeignAlbumId { get; set; }
public int TrackCount { get; set; }
public DateTime ReleaseDate { get; set; }
public bool Monitored { get; set; }
public string Title { get; set; }
[ForeignKey(nameof(ArtistId))]
public LidarrArtistCache Artist { get; set; }
}
}

@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
namespace Ombi.Store.Entities
{
[Table("LidarrArtistCache")]
public class LidarrArtistCache : Entity
{
[ForeignKey(nameof(ArtistId))]
public int ArtistId { get; set; }
public string ArtistName { get; set; }
public string ForeignArtistId { get; set; }
public bool Monitored { get; set; }
public List<LidarrAlbumCache> Albums { get; set; }
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,65 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Ombi.Store.Migrations
{
public partial class LidarrSyncJobs : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "LidarrArtistCache",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
ArtistId = table.Column<int>(nullable: false),
ArtistName = table.Column<string>(nullable: true),
ForeignArtistId = table.Column<string>(nullable: true),
Monitored = table.Column<bool>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LidarrArtistCache", x => x.Id);
});
migrationBuilder.CreateTable(
name: "LidarrAlbumCache",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
ArtistId = table.Column<int>(nullable: false),
ForeignAlbumId = table.Column<string>(nullable: true),
TrackCount = table.Column<int>(nullable: false),
ReleaseDate = table.Column<DateTime>(nullable: false),
Monitored = table.Column<bool>(nullable: false),
Title = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_LidarrAlbumCache", x => x.Id);
table.ForeignKey(
name: "FK_LidarrAlbumCache_LidarrArtistCache_ArtistId",
column: x => x.ArtistId,
principalTable: "LidarrArtistCache",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_LidarrAlbumCache_ArtistId",
table: "LidarrAlbumCache",
column: "ArtistId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "LidarrAlbumCache");
migrationBuilder.DropTable(
name: "LidarrArtistCache");
}
}
}

@ -244,6 +244,48 @@ namespace Ombi.Store.Migrations
b.ToTable("GlobalSettings");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("ArtistId");
b.Property<string>("ForeignAlbumId");
b.Property<bool>("Monitored");
b.Property<DateTime>("ReleaseDate");
b.Property<string>("Title");
b.Property<int>("TrackCount");
b.HasKey("Id");
b.HasIndex("ArtistId");
b.ToTable("LidarrAlbumCache");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("ArtistId");
b.Property<string>("ArtistName");
b.Property<string>("ForeignArtistId");
b.Property<bool>("Monitored");
b.HasKey("Id");
b.ToTable("LidarrArtistCache");
});
modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b =>
{
b.Property<int>("Id")
@ -921,6 +963,14 @@ namespace Ombi.Store.Migrations
.HasPrincipalKey("EmbyId");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b =>
{
b.HasOne("Ombi.Store.Entities.LidarrArtistCache", "Artist")
.WithMany("Albums")
.HasForeignKey("ArtistId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
{
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")

@ -139,6 +139,7 @@ export interface IJobSettings {
refreshMetadata: string;
newsletter: string;
plexRecentlyAddedSync: string;
lidarrArtistSync: string;
}
export interface IIssueSettings extends ISettings {

@ -92,16 +92,16 @@
<br/>
<div class="dropdown" *ngIf="result.available && issueCategories && issuesEnabled">
<!-- <div class="dropdown" *ngIf="result.available && issueCategories && issuesEnabled">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true">
<i class="fa fa-plus"></i> Report Issue
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<!-- <li *ngFor="let cat of issueCategories"><a [routerLink]="" (click)="reportIssue(cat, result)">{{cat.value}}</a></li> -->
<li *ngFor="let cat of issueCategories"><a [routerLink]="" (click)="reportIssue(cat, result)">{{cat.value}}</a></li>
</ul>
</div>
</div> -->
</div>

@ -22,12 +22,19 @@
</div>
<div class="form-group">
<label for="radarrSync" class="control-label">Radarr Sync</label>
<input type="text" class="form-control form-control-custom" [ngClass]="{'form-error': form.get('radarrSync').hasError('required')}" id="radarrSync" name="radarrSync" formControlName="radarrSync">
<small *ngIf="form.get('radarrSync').hasError('required')" class="error-text">The Radarr Sync is required</small>
<button type="button" class="btn btn-sm btn-primary-outline" (click)="testCron(form.get('radarrSync')?.value)">Test</button>
</div>
<label for="radarrSync" class="control-label">Radarr Sync</label>
<input type="text" class="form-control form-control-custom" [ngClass]="{'form-error': form.get('radarrSync').hasError('required')}" id="radarrSync" name="radarrSync" formControlName="radarrSync">
<small *ngIf="form.get('radarrSync').hasError('required')" class="error-text">The Radarr Sync is required</small>
<button type="button" class="btn btn-sm btn-primary-outline" (click)="testCron(form.get('radarrSync')?.value)">Test</button>
</div>
<div class="form-group">
<label for="lidarrArtistSync" class="control-label">Lidarr Sync</label>
<input type="text" class="form-control form-control-custom" [ngClass]="{'form-error': form.get('lidarrArtistSync').hasError('required')}" id="lidarrArtistSync" name="lidarrArtistSync" formControlName="lidarrArtistSync">
<small *ngIf="form.get('lidarrArtistSync').hasError('required')" class="error-text">The Lidarr Sync is required</small>
<button type="button" class="btn btn-sm btn-primary-outline" (click)="testCron(form.get('lidarrArtistSync')?.value)">Test</button>
</div>
<div class="form-group">
<label for="couchPotatoSync" class="control-label">CouchPotato Sync</label>
<input type="text" class="form-control form-control-custom" [ngClass]="{'form-error': form.get('radarrSync').hasError('required')}" id="couchPotatoSync" name="couchPotatoSync" formControlName="couchPotatoSync">

@ -506,6 +506,7 @@ namespace Ombi.Controllers
j.RefreshMetadata = j.RefreshMetadata.HasValue() ? j.RefreshMetadata : JobSettingsHelper.RefreshMetadata(j);
j.PlexRecentlyAddedSync = j.PlexRecentlyAddedSync.HasValue() ? j.PlexRecentlyAddedSync : JobSettingsHelper.PlexRecentlyAdded(j);
j.Newsletter = j.Newsletter.HasValue() ? j.Newsletter : JobSettingsHelper.Newsletter(j);
j.LidarrArtistSync = j.LidarrArtistSync.HasValue() ? j.LidarrArtistSync : JobSettingsHelper.LidarrArtistSync(j);
return j;
}

Loading…
Cancel
Save