mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 13:23:20 -07:00
commit
e3eee7453f
154 changed files with 7989 additions and 83 deletions
BIN
music-placeholder.psd
Normal file
BIN
music-placeholder.psd
Normal file
Binary file not shown.
25
src/Ombi.Api.Lidarr/ILidarrApi.cs
Normal file
25
src/Ombi.Api.Lidarr/ILidarrApi.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Api.Lidarr.Models;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr
|
||||||
|
{
|
||||||
|
public interface ILidarrApi
|
||||||
|
{
|
||||||
|
Task<List<AlbumLookup>> AlbumLookup(string searchTerm, string apiKey, string baseUrl);
|
||||||
|
Task<List<ArtistLookup>> ArtistLookup(string searchTerm, string apiKey, string baseUrl);
|
||||||
|
Task<List<LidarrProfile>> GetProfiles(string apiKey, string baseUrl);
|
||||||
|
Task<List<LidarrRootFolder>> GetRootFolders(string apiKey, string baseUrl);
|
||||||
|
Task<ArtistResult> GetArtist(int artistId, string apiKey, string baseUrl);
|
||||||
|
Task<ArtistResult> GetArtistByForeignId(string foreignArtistId, string apiKey, string baseUrl);
|
||||||
|
Task<AlbumByArtistResponse> GetAlbumsByArtist(string foreignArtistId);
|
||||||
|
Task<AlbumLookup> GetAlbumByForeignId(string foreignArtistId, string apiKey, string baseUrl);
|
||||||
|
Task<List<ArtistResult>> GetArtists(string apiKey, string baseUrl);
|
||||||
|
Task<List<AlbumResponse>> GetAllAlbums(string apiKey, string baseUrl);
|
||||||
|
Task<ArtistResult> AddArtist(ArtistAdd artist, string apiKey, string baseUrl);
|
||||||
|
Task<AlbumResponse> MontiorAlbum(int albumId, string apiKey, string baseUrl);
|
||||||
|
Task<List<AlbumResponse>> GetAllAlbumsByArtistId(int artistId, string apiKey, string baseUrl);
|
||||||
|
Task<List<MetadataProfile>> GetMetadataProfile(string apiKey, string baseUrl);
|
||||||
|
Task<List<LanguageProfiles>> GetLanguageProfile(string apiKey, string baseUrl);
|
||||||
|
}
|
||||||
|
}
|
155
src/Ombi.Api.Lidarr/LidarrApi.cs
Normal file
155
src/Ombi.Api.Lidarr/LidarrApi.cs
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.Lidarr.Models;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr
|
||||||
|
{
|
||||||
|
public class LidarrApi : ILidarrApi
|
||||||
|
{
|
||||||
|
public LidarrApi(ILogger<LidarrApi> logger, IApi api)
|
||||||
|
{
|
||||||
|
Api = api;
|
||||||
|
Logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IApi Api { get; }
|
||||||
|
private ILogger Logger { get; }
|
||||||
|
|
||||||
|
private const string ApiVersion = "/api/v1";
|
||||||
|
|
||||||
|
public Task<List<LidarrProfile>> GetProfiles(string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/qualityprofile", baseUrl, HttpMethod.Get);
|
||||||
|
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<List<LidarrProfile>>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<LidarrRootFolder>> GetRootFolders(string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/rootfolder", baseUrl, HttpMethod.Get);
|
||||||
|
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<List<LidarrRootFolder>>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<ArtistLookup>> ArtistLookup(string searchTerm, string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/Artist/lookup", baseUrl, HttpMethod.Get);
|
||||||
|
request.AddQueryString("term", searchTerm);
|
||||||
|
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return await Api.Request<List<ArtistLookup>>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<AlbumLookup>> AlbumLookup(string searchTerm, string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/Album/lookup", baseUrl, HttpMethod.Get);
|
||||||
|
request.AddQueryString("term", searchTerm);
|
||||||
|
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<List<AlbumLookup>>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ArtistResult> GetArtist(int artistId, string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/artist/{artistId}", baseUrl, HttpMethod.Get);
|
||||||
|
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<ArtistResult>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ArtistResult> GetArtistByForeignId(string foreignArtistId, string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/artist/lookup", baseUrl, HttpMethod.Get);
|
||||||
|
|
||||||
|
request.AddQueryString("term", $"lidarr:{foreignArtistId}");
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return (await Api.Request<List<ArtistResult>>(request)).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AlbumLookup> GetAlbumByForeignId(string foreignArtistId, string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/album/lookup", baseUrl, HttpMethod.Get);
|
||||||
|
|
||||||
|
request.AddQueryString("term", $"lidarr:{foreignArtistId}");
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
var albums = await Api.Request<List<AlbumLookup>>(request);
|
||||||
|
return albums.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AlbumByArtistResponse> GetAlbumsByArtist(string foreignArtistId)
|
||||||
|
{
|
||||||
|
var request = new Request(string.Empty, $"https://api.lidarr.audio/api/v0.3/artist/{foreignArtistId}",
|
||||||
|
HttpMethod.Get) {IgnoreBaseUrlAppend = true};
|
||||||
|
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<AlbumResponse>> GetAllAlbums(string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get);
|
||||||
|
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<List<AlbumResponse>>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ArtistResult> AddArtist(ArtistAdd artist, string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/artist", baseUrl, HttpMethod.Post);
|
||||||
|
request.AddJsonBody(artist);
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<ArtistResult>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AlbumResponse> MontiorAlbum(int albumId, string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/album/monitor", baseUrl, HttpMethod.Put);
|
||||||
|
request.AddJsonBody(new
|
||||||
|
{
|
||||||
|
albumIds = new[] { albumId },
|
||||||
|
monitored = true
|
||||||
|
});
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return (await Api.Request<List<AlbumResponse>>(request)).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<AlbumResponse>> GetAllAlbumsByArtistId(int artistId, string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get);
|
||||||
|
request.AddQueryString("artistId", artistId.ToString());
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<List<AlbumResponse>>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<LanguageProfiles>> GetLanguageProfile(string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/languageprofile", baseUrl, HttpMethod.Get);
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<List<LanguageProfiles>>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<MetadataProfile>> GetMetadataProfile(string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/metadataprofile", baseUrl, HttpMethod.Get);
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<List<MetadataProfile>>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddHeaders(Request request, string key)
|
||||||
|
{
|
||||||
|
request.AddHeader("X-Api-Key", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
src/Ombi.Api.Lidarr/Models/AlbumByArtistResponse.cs
Normal file
34
src/Ombi.Api.Lidarr/Models/AlbumByArtistResponse.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class AlbumByArtistResponse
|
||||||
|
{
|
||||||
|
public Album[] Albums { get; set; }
|
||||||
|
public string ArtistName { get; set; }
|
||||||
|
public string Disambiguation { get; set; }
|
||||||
|
public string Id { get; set; }
|
||||||
|
public Image[] Images { get; set; }
|
||||||
|
public Link[] Links { get; set; }
|
||||||
|
public string Overview { get; set; }
|
||||||
|
public Rating Rating { get; set; }
|
||||||
|
public string SortName { get; set; }
|
||||||
|
public string Status { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Rating
|
||||||
|
{
|
||||||
|
public int Count { get; set; }
|
||||||
|
public decimal Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Album
|
||||||
|
{
|
||||||
|
public string Disambiguation { get; set; }
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string ReleaseDate { get; set; }
|
||||||
|
public string[] ReleaseStatuses { get; set; }
|
||||||
|
public string[] SecondaryTypes { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
}
|
||||||
|
}
|
25
src/Ombi.Api.Lidarr/Models/AlbumLookup.cs
Normal file
25
src/Ombi.Api.Lidarr/Models/AlbumLookup.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class AlbumLookup
|
||||||
|
{
|
||||||
|
public string title { get; set; }
|
||||||
|
public int artistId { get; set; }
|
||||||
|
public string foreignAlbumId { get; set; }
|
||||||
|
public bool monitored { get; set; }
|
||||||
|
public int profileId { get; set; }
|
||||||
|
public int duration { get; set; }
|
||||||
|
public string albumType { get; set; }
|
||||||
|
public string[] secondaryTypes { get; set; }
|
||||||
|
public int mediumCount { get; set; }
|
||||||
|
public Ratings ratings { get; set; }
|
||||||
|
public DateTime releaseDate { get; set; }
|
||||||
|
//public object[] releases { get; set; }
|
||||||
|
public object[] genres { get; set; }
|
||||||
|
//public object[] media { get; set; }
|
||||||
|
public Artist artist { get; set; }
|
||||||
|
public Image[] images { get; set; }
|
||||||
|
public string remoteCover { get; set; }
|
||||||
|
}
|
||||||
|
}
|
27
src/Ombi.Api.Lidarr/Models/AlbumResponse.cs
Normal file
27
src/Ombi.Api.Lidarr/Models/AlbumResponse.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class AlbumResponse
|
||||||
|
{
|
||||||
|
public string title { get; set; }
|
||||||
|
public string disambiguation { get; set; }
|
||||||
|
public int artistId { get; set; }
|
||||||
|
public string foreignAlbumId { get; set; }
|
||||||
|
public bool monitored { get; set; }
|
||||||
|
public int profileId { get; set; }
|
||||||
|
public int duration { get; set; }
|
||||||
|
public string albumType { get; set; }
|
||||||
|
public object[] secondaryTypes { get; set; }
|
||||||
|
public int mediumCount { get; set; }
|
||||||
|
public Ratings ratings { get; set; }
|
||||||
|
public DateTime releaseDate { get; set; }
|
||||||
|
public Currentrelease currentRelease { get; set; }
|
||||||
|
public Release[] releases { get; set; }
|
||||||
|
public object[] genres { get; set; }
|
||||||
|
public Medium[] media { get; set; }
|
||||||
|
public Image[] images { get; set; }
|
||||||
|
public Statistics statistics { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
25
src/Ombi.Api.Lidarr/Models/Artist.cs
Normal file
25
src/Ombi.Api.Lidarr/Models/Artist.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class Artist
|
||||||
|
{
|
||||||
|
public string status { get; set; }
|
||||||
|
public bool ended { get; set; }
|
||||||
|
public string artistName { get; set; }
|
||||||
|
public string foreignArtistId { get; set; }
|
||||||
|
public int tadbId { get; set; }
|
||||||
|
public int discogsId { get; set; }
|
||||||
|
public object[] links { get; set; }
|
||||||
|
public object[] images { get; set; }
|
||||||
|
public int qualityProfileId { get; set; }
|
||||||
|
public int languageProfileId { get; set; }
|
||||||
|
public int metadataProfileId { get; set; }
|
||||||
|
public bool albumFolder { get; set; }
|
||||||
|
public bool monitored { get; set; }
|
||||||
|
public object[] genres { get; set; }
|
||||||
|
public object[] tags { get; set; }
|
||||||
|
public DateTime added { get; set; }
|
||||||
|
public Statistics statistics { get; set; }
|
||||||
|
}
|
||||||
|
}
|
49
src/Ombi.Api.Lidarr/Models/ArtistAdd.cs
Normal file
49
src/Ombi.Api.Lidarr/Models/ArtistAdd.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Mime;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class ArtistAdd
|
||||||
|
{
|
||||||
|
public string status { get; set; }
|
||||||
|
public bool ended { get; set; }
|
||||||
|
public string artistName { get; set; }
|
||||||
|
public string foreignArtistId { get; set; }
|
||||||
|
public int tadbId { get; set; }
|
||||||
|
public int discogsId { get; set; }
|
||||||
|
public string overview { get; set; }
|
||||||
|
public string disambiguation { get; set; }
|
||||||
|
public Link[] links { get; set; }
|
||||||
|
public Image[] images { get; set; }
|
||||||
|
public string remotePoster { get; set; }
|
||||||
|
public int qualityProfileId { get; set; }
|
||||||
|
public int languageProfileId { get; set; }
|
||||||
|
public int metadataProfileId { get; set; }
|
||||||
|
public bool albumFolder { get; set; }
|
||||||
|
public bool monitored { get; set; }
|
||||||
|
public string cleanName { get; set; }
|
||||||
|
public string sortName { get; set; }
|
||||||
|
public object[] tags { get; set; }
|
||||||
|
public DateTime added { get; set; }
|
||||||
|
public Ratings ratings { get; set; }
|
||||||
|
public Statistics statistics { get; set; }
|
||||||
|
public Addoptions addOptions { get; set; }
|
||||||
|
public string rootFolderPath { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Addoptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Future = 1
|
||||||
|
/// Missing = 2
|
||||||
|
/// Existing = 3
|
||||||
|
/// First = 5
|
||||||
|
/// Latest = 4
|
||||||
|
/// None = 6
|
||||||
|
/// </summary>
|
||||||
|
public int selectedOption { get; set; }
|
||||||
|
public bool monitored { get; set; }
|
||||||
|
public bool searchForMissingAlbums { get; set; }
|
||||||
|
public string[] AlbumsToMonitor { get; set; } // Uses the MusicBrainzAlbumId!
|
||||||
|
}
|
||||||
|
}
|
32
src/Ombi.Api.Lidarr/Models/ArtistLookup.cs
Normal file
32
src/Ombi.Api.Lidarr/Models/ArtistLookup.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Mime;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class ArtistLookup
|
||||||
|
{
|
||||||
|
public string status { get; set; }
|
||||||
|
public bool ended { get; set; }
|
||||||
|
public string artistName { get; set; }
|
||||||
|
public string foreignArtistId { get; set; }
|
||||||
|
public int tadbId { get; set; }
|
||||||
|
public int discogsId { get; set; }
|
||||||
|
public string overview { get; set; }
|
||||||
|
public string artistType { get; set; }
|
||||||
|
public string disambiguation { get; set; }
|
||||||
|
public Link[] links { get; set; }
|
||||||
|
public Image[] images { get; set; }
|
||||||
|
public string remotePoster { get; set; }
|
||||||
|
public int qualityProfileId { get; set; }
|
||||||
|
public int languageProfileId { get; set; }
|
||||||
|
public int metadataProfileId { get; set; }
|
||||||
|
public bool albumFolder { get; set; }
|
||||||
|
public bool monitored { get; set; }
|
||||||
|
public string cleanName { get; set; }
|
||||||
|
public string sortName { get; set; }
|
||||||
|
public object[] tags { get; set; }
|
||||||
|
public DateTime added { get; set; }
|
||||||
|
public Ratings ratings { get; set; }
|
||||||
|
public Statistics statistics { get; set; }
|
||||||
|
}
|
||||||
|
}
|
93
src/Ombi.Api.Lidarr/Models/ArtistResult.cs
Normal file
93
src/Ombi.Api.Lidarr/Models/ArtistResult.cs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ArtistResult
|
||||||
|
{
|
||||||
|
public string status { get; set; }
|
||||||
|
public bool ended { get; set; }
|
||||||
|
public DateTime lastInfoSync { get; set; }
|
||||||
|
public string artistName { get; set; }
|
||||||
|
public string foreignArtistId { get; set; }
|
||||||
|
public int tadbId { get; set; }
|
||||||
|
public int discogsId { get; set; }
|
||||||
|
public string overview { get; set; }
|
||||||
|
public string artistType { get; set; }
|
||||||
|
public string disambiguation { get; set; }
|
||||||
|
public Link[] links { get; set; }
|
||||||
|
public Nextalbum nextAlbum { get; set; }
|
||||||
|
public Image[] images { get; set; }
|
||||||
|
public string path { get; set; }
|
||||||
|
public int qualityProfileId { get; set; }
|
||||||
|
public int languageProfileId { get; set; }
|
||||||
|
public int metadataProfileId { get; set; }
|
||||||
|
public bool albumFolder { get; set; }
|
||||||
|
public bool monitored { get; set; }
|
||||||
|
public object[] genres { get; set; }
|
||||||
|
public string cleanName { get; set; }
|
||||||
|
public string sortName { get; set; }
|
||||||
|
public object[] tags { get; set; }
|
||||||
|
public DateTime added { get; set; }
|
||||||
|
public Ratings ratings { get; set; }
|
||||||
|
public Statistics statistics { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Nextalbum
|
||||||
|
{
|
||||||
|
public string foreignAlbumId { get; set; }
|
||||||
|
public int artistId { get; set; }
|
||||||
|
public string title { get; set; }
|
||||||
|
public string disambiguation { get; set; }
|
||||||
|
public string cleanTitle { get; set; }
|
||||||
|
public DateTime releaseDate { get; set; }
|
||||||
|
public int profileId { get; set; }
|
||||||
|
public int duration { get; set; }
|
||||||
|
public bool monitored { get; set; }
|
||||||
|
public object[] images { get; set; }
|
||||||
|
public object[] genres { get; set; }
|
||||||
|
public Medium[] media { get; set; }
|
||||||
|
public DateTime lastInfoSync { get; set; }
|
||||||
|
public DateTime added { get; set; }
|
||||||
|
public string albumType { get; set; }
|
||||||
|
public object[] secondaryTypes { get; set; }
|
||||||
|
public Ratings ratings { get; set; }
|
||||||
|
public Release[] releases { get; set; }
|
||||||
|
public Currentrelease currentRelease { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Currentrelease
|
||||||
|
{
|
||||||
|
public string id { get; set; }
|
||||||
|
public string title { get; set; }
|
||||||
|
public DateTime releaseDate { get; set; }
|
||||||
|
public int trackCount { get; set; }
|
||||||
|
public int mediaCount { get; set; }
|
||||||
|
public string disambiguation { get; set; }
|
||||||
|
public string[] country { get; set; }
|
||||||
|
public string format { get; set; }
|
||||||
|
public string[] label { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Medium
|
||||||
|
{
|
||||||
|
public int number { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public string format { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Release
|
||||||
|
{
|
||||||
|
public string id { get; set; }
|
||||||
|
public string title { get; set; }
|
||||||
|
public DateTime releaseDate { get; set; }
|
||||||
|
public int trackCount { get; set; }
|
||||||
|
public int mediaCount { get; set; }
|
||||||
|
public string disambiguation { get; set; }
|
||||||
|
public string[] country { get; set; }
|
||||||
|
public string format { get; set; }
|
||||||
|
public string[] label { get; set; }
|
||||||
|
}
|
||||||
|
}
|
8
src/Ombi.Api.Lidarr/Models/Image.cs
Normal file
8
src/Ombi.Api.Lidarr/Models/Image.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class Image
|
||||||
|
{
|
||||||
|
public string coverType { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
}
|
||||||
|
}
|
8
src/Ombi.Api.Lidarr/Models/LanguageProfiles.cs
Normal file
8
src/Ombi.Api.Lidarr/Models/LanguageProfiles.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class LanguageProfiles
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
23
src/Ombi.Api.Lidarr/Models/LidarrProfile.cs
Normal file
23
src/Ombi.Api.Lidarr/Models/LidarrProfile.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class Quality
|
||||||
|
{
|
||||||
|
public int id { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Item
|
||||||
|
{
|
||||||
|
public Quality quality { get; set; }
|
||||||
|
public bool allowed { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LidarrProfile
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public List<Item> items { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
src/Ombi.Api.Lidarr/Models/LidarrRootFolder.cs
Normal file
11
src/Ombi.Api.Lidarr/Models/LidarrRootFolder.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class LidarrRootFolder
|
||||||
|
{
|
||||||
|
public string path { get; set; }
|
||||||
|
public long freeSpace { get; set; }
|
||||||
|
public object[] unmappedFolders { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
src/Ombi.Api.Lidarr/Models/Link.cs
Normal file
8
src/Ombi.Api.Lidarr/Models/Link.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class Link
|
||||||
|
{
|
||||||
|
public string url { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
8
src/Ombi.Api.Lidarr/Models/MetadataProfile.cs
Normal file
8
src/Ombi.Api.Lidarr/Models/MetadataProfile.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class MetadataProfile
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
8
src/Ombi.Api.Lidarr/Models/Ratings.cs
Normal file
8
src/Ombi.Api.Lidarr/Models/Ratings.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class Ratings
|
||||||
|
{
|
||||||
|
public int votes { get; set; }
|
||||||
|
public decimal value { get; set; }
|
||||||
|
}
|
||||||
|
}
|
12
src/Ombi.Api.Lidarr/Models/Statistics.cs
Normal file
12
src/Ombi.Api.Lidarr/Models/Statistics.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class Statistics
|
||||||
|
{
|
||||||
|
public int albumCount { get; set; }
|
||||||
|
public int trackFileCount { get; set; }
|
||||||
|
public int trackCount { get; set; }
|
||||||
|
public int totalTrackCount { get; set; }
|
||||||
|
public int sizeOnDisk { get; set; }
|
||||||
|
public decimal percentOfEpisodes { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
src/Ombi.Api.Lidarr/Ombi.Api.Lidarr.csproj
Normal file
11
src/Ombi.Api.Lidarr/Ombi.Api.Lidarr.csproj
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -28,6 +28,7 @@ namespace Ombi.Api
|
||||||
public bool IgnoreErrors { get; set; }
|
public bool IgnoreErrors { get; set; }
|
||||||
public bool Retry { get; set; }
|
public bool Retry { get; set; }
|
||||||
public List<HttpStatusCode> StatusCodeToRetry { get; set; } = new List<HttpStatusCode>();
|
public List<HttpStatusCode> StatusCodeToRetry { get; set; } = new List<HttpStatusCode>();
|
||||||
|
public bool IgnoreBaseUrlAppend { get; set; }
|
||||||
|
|
||||||
public Action<string> OnBeforeDeserialization { get; set; }
|
public Action<string> OnBeforeDeserialization { get; set; }
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ namespace Ombi.Api
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
if (!string.IsNullOrEmpty(BaseUrl))
|
if (!string.IsNullOrEmpty(BaseUrl))
|
||||||
{
|
{
|
||||||
sb.Append(!BaseUrl.EndsWith("/") ? string.Format("{0}/", BaseUrl) : BaseUrl);
|
sb.Append(!BaseUrl.EndsWith("/") && !IgnoreBaseUrlAppend ? string.Format("{0}/", BaseUrl) : BaseUrl);
|
||||||
}
|
}
|
||||||
sb.Append(Endpoint.StartsWith("/") ? Endpoint.Remove(0, 1) : Endpoint);
|
sb.Append(Endpoint.StartsWith("/") ? Endpoint.Remove(0, 1) : Endpoint);
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
|
|
|
@ -19,12 +19,14 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
|
|
||||||
MovieMock = new Mock<IMovieRequestRepository>();
|
MovieMock = new Mock<IMovieRequestRepository>();
|
||||||
TvMock = new Mock<ITvRequestRepository>();
|
TvMock = new Mock<ITvRequestRepository>();
|
||||||
Rule = new ExistingRule(MovieMock.Object, TvMock.Object);
|
MusicMock = new Mock<IMusicRequestRepository>();
|
||||||
|
Rule = new ExistingRule(MovieMock.Object, TvMock.Object, MusicMock.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExistingRule Rule { get; set; }
|
private ExistingRule Rule { get; set; }
|
||||||
private Mock<IMovieRequestRepository> MovieMock { get; set; }
|
private Mock<IMovieRequestRepository> MovieMock { get; set; }
|
||||||
private Mock<ITvRequestRepository> TvMock { get; set; }
|
private Mock<ITvRequestRepository> TvMock { get; set; }
|
||||||
|
private Mock<IMusicRequestRepository> MusicMock { get; set; }
|
||||||
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -36,6 +36,7 @@ namespace Ombi.Core.Engine
|
||||||
protected IRequestServiceMain RequestService { get; }
|
protected IRequestServiceMain RequestService { get; }
|
||||||
protected IMovieRequestRepository MovieRepository => RequestService.MovieRequestService;
|
protected IMovieRequestRepository MovieRepository => RequestService.MovieRequestService;
|
||||||
protected ITvRequestRepository TvRepository => RequestService.TvRequestService;
|
protected ITvRequestRepository TvRepository => RequestService.TvRequestService;
|
||||||
|
protected IMusicRequestRepository MusicRepository => RequestService.MusicRequestRepository;
|
||||||
protected readonly ICacheService Cache;
|
protected readonly ICacheService Cache;
|
||||||
protected readonly ISettingsService<OmbiSettings> OmbiSettings;
|
protected readonly ISettingsService<OmbiSettings> OmbiSettings;
|
||||||
protected readonly IRepository<RequestSubscription> _subscriptionRepository;
|
protected readonly IRepository<RequestSubscription> _subscriptionRepository;
|
||||||
|
|
24
src/Ombi.Core/Engine/IMusicRequestEngine.cs
Normal file
24
src/Ombi.Core/Engine/IMusicRequestEngine.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Core.Models.Requests;
|
||||||
|
using Ombi.Core.Models.UI;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Engine
|
||||||
|
{
|
||||||
|
public interface IMusicRequestEngine
|
||||||
|
{
|
||||||
|
Task<RequestEngineResult>ApproveAlbum(AlbumRequest request);
|
||||||
|
Task<RequestEngineResult> ApproveAlbumById(int requestId);
|
||||||
|
Task<RequestEngineResult> DenyAlbumById(int modelId);
|
||||||
|
Task<IEnumerable<AlbumRequest>> GetRequests();
|
||||||
|
Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position, OrderFilterModel orderFilter);
|
||||||
|
Task<int> GetTotal();
|
||||||
|
Task<RequestEngineResult> MarkAvailable(int modelId);
|
||||||
|
Task<RequestEngineResult> MarkUnavailable(int modelId);
|
||||||
|
Task RemoveAlbumRequest(int requestId);
|
||||||
|
Task<RequestEngineResult> RequestAlbum(MusicAlbumRequestViewModel model);
|
||||||
|
Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search);
|
||||||
|
Task<bool> UserHasRequest(string userId);
|
||||||
|
}
|
||||||
|
}
|
16
src/Ombi.Core/Engine/Interfaces/IMusicSearchEngine.cs
Normal file
16
src/Ombi.Core/Engine/Interfaces/IMusicSearchEngine.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Api.Lidarr.Models;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Engine
|
||||||
|
{
|
||||||
|
public interface IMusicSearchEngine
|
||||||
|
{
|
||||||
|
Task<ArtistResult> GetAlbumArtist(string foreignArtistId);
|
||||||
|
Task<ArtistResult> GetArtist(int artistId);
|
||||||
|
Task<IEnumerable<SearchAlbumViewModel>> GetArtistAlbums(string foreignArtistId);
|
||||||
|
Task<IEnumerable<SearchAlbumViewModel>> SearchAlbum(string search);
|
||||||
|
Task<IEnumerable<SearchArtistViewModel>> SearchArtist(string search);
|
||||||
|
}
|
||||||
|
}
|
|
@ -336,6 +336,7 @@ namespace Ombi.Core.Engine
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request.MarkedAsApproved = DateTime.Now;
|
||||||
request.Approved = true;
|
request.Approved = true;
|
||||||
request.Denied = false;
|
request.Denied = false;
|
||||||
await MovieRepository.Update(request);
|
await MovieRepository.Update(request);
|
||||||
|
|
457
src/Ombi.Core/Engine/MusicRequestEngine.cs
Normal file
457
src/Ombi.Core/Engine/MusicRequestEngine.cs
Normal file
|
@ -0,0 +1,457 @@
|
||||||
|
using Ombi.Api.TheMovieDb;
|
||||||
|
using Ombi.Core.Models.Requests;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.Lidarr;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Engine.Interfaces;
|
||||||
|
using Ombi.Core.Models.UI;
|
||||||
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Ombi.Core.Senders;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
using Ombi.Settings.Settings.Models.External;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Engine
|
||||||
|
{
|
||||||
|
public class MusicRequestEngine : BaseMediaEngine, IMusicRequestEngine
|
||||||
|
{
|
||||||
|
public MusicRequestEngine(IRequestServiceMain requestService, IPrincipal user,
|
||||||
|
INotificationHelper helper, IRuleEvaluator r, ILogger<MusicRequestEngine> log,
|
||||||
|
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
|
||||||
|
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, ILidarrApi lidarr,
|
||||||
|
ISettingsService<LidarrSettings> lidarrSettings, IMusicSender sender)
|
||||||
|
: base(user, requestService, r, manager, cache, ombiSettings, sub)
|
||||||
|
{
|
||||||
|
NotificationHelper = helper;
|
||||||
|
_musicSender = sender;
|
||||||
|
Logger = log;
|
||||||
|
_requestLog = rl;
|
||||||
|
_lidarrApi = lidarr;
|
||||||
|
_lidarrSettings = lidarrSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
private INotificationHelper NotificationHelper { get; }
|
||||||
|
//private IMovieSender Sender { get; }
|
||||||
|
private ILogger Logger { get; }
|
||||||
|
private readonly IRepository<RequestLog> _requestLog;
|
||||||
|
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||||
|
private readonly ILidarrApi _lidarrApi;
|
||||||
|
private readonly IMusicSender _musicSender;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests the Album.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The model.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<RequestEngineResult> RequestAlbum(MusicAlbumRequestViewModel model)
|
||||||
|
{
|
||||||
|
var s = await _lidarrSettings.GetSettingsAsync();
|
||||||
|
var album = await _lidarrApi.GetAlbumByForeignId(model.ForeignAlbumId, s.ApiKey, s.FullUri);
|
||||||
|
if (album == null)
|
||||||
|
{
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
Result = false,
|
||||||
|
Message = "There was an issue adding this album!",
|
||||||
|
ErrorMessage = "Please try again later"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var userDetails = await GetUser();
|
||||||
|
|
||||||
|
var requestModel = new AlbumRequest
|
||||||
|
{
|
||||||
|
ForeignAlbumId = model.ForeignAlbumId,
|
||||||
|
ArtistName = album.artist?.artistName,
|
||||||
|
ReleaseDate = album.releaseDate,
|
||||||
|
RequestedDate = DateTime.Now,
|
||||||
|
RequestType = RequestType.Album,
|
||||||
|
Rating = album.ratings?.value ?? 0m,
|
||||||
|
RequestedUserId = userDetails.Id,
|
||||||
|
Title = album.title,
|
||||||
|
Disk = album.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url,
|
||||||
|
Cover = album.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url,
|
||||||
|
ForeignArtistId = album?.artist?.foreignArtistId ?? string.Empty
|
||||||
|
};
|
||||||
|
if (requestModel.Cover.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
requestModel.Cover = album.remoteCover;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ruleResults = (await RunRequestRules(requestModel)).ToList();
|
||||||
|
if (ruleResults.Any(x => !x.Success))
|
||||||
|
{
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
ErrorMessage = ruleResults.FirstOrDefault(x => x.Message.HasValue()).Message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestModel.Approved) // The rules have auto approved this
|
||||||
|
{
|
||||||
|
var requestEngineResult = await AddAlbumRequest(requestModel);
|
||||||
|
if (requestEngineResult.Result)
|
||||||
|
{
|
||||||
|
var result = await ApproveAlbum(requestModel);
|
||||||
|
if (result.IsError)
|
||||||
|
{
|
||||||
|
Logger.LogWarning("Tried auto sending Album but failed. Message: {0}", result.Message);
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
Message = result.Message,
|
||||||
|
ErrorMessage = result.Message,
|
||||||
|
Result = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestEngineResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no providers then it's successful but album has not been sent
|
||||||
|
}
|
||||||
|
|
||||||
|
return await AddAlbumRequest(requestModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the requests.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count">The count.</param>
|
||||||
|
/// <param name="position">The position.</param>
|
||||||
|
/// <param name="orderFilter">The order/filter type.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position,
|
||||||
|
OrderFilterModel orderFilter)
|
||||||
|
{
|
||||||
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
IQueryable<AlbumRequest> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests =
|
||||||
|
MusicRepository.GetWithUser(shouldHide
|
||||||
|
.UserId); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests =
|
||||||
|
MusicRepository
|
||||||
|
.GetWithUser(); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (orderFilter.AvailabilityFilter)
|
||||||
|
{
|
||||||
|
case FilterType.None:
|
||||||
|
break;
|
||||||
|
case FilterType.Available:
|
||||||
|
allRequests = allRequests.Where(x => x.Available);
|
||||||
|
break;
|
||||||
|
case FilterType.NotAvailable:
|
||||||
|
allRequests = allRequests.Where(x => !x.Available);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (orderFilter.StatusFilter)
|
||||||
|
{
|
||||||
|
case FilterType.None:
|
||||||
|
break;
|
||||||
|
case FilterType.Approved:
|
||||||
|
allRequests = allRequests.Where(x => x.Approved);
|
||||||
|
break;
|
||||||
|
case FilterType.Processing:
|
||||||
|
allRequests = allRequests.Where(x => x.Approved && !x.Available);
|
||||||
|
break;
|
||||||
|
case FilterType.PendingApproval:
|
||||||
|
allRequests = allRequests.Where(x => !x.Approved && !x.Available && !(x.Denied ?? false));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var total = allRequests.Count();
|
||||||
|
|
||||||
|
var requests = await (OrderAlbums(allRequests, orderFilter.OrderType)).Skip(position).Take(count)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
requests.ForEach(async x =>
|
||||||
|
{
|
||||||
|
await CheckForSubscription(shouldHide, x);
|
||||||
|
});
|
||||||
|
return new RequestsViewModel<AlbumRequest>
|
||||||
|
{
|
||||||
|
Collection = requests,
|
||||||
|
Total = total
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private IQueryable<AlbumRequest> OrderAlbums(IQueryable<AlbumRequest> allRequests, OrderType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case OrderType.RequestedDateAsc:
|
||||||
|
return allRequests.OrderBy(x => x.RequestedDate);
|
||||||
|
case OrderType.RequestedDateDesc:
|
||||||
|
return allRequests.OrderByDescending(x => x.RequestedDate);
|
||||||
|
case OrderType.TitleAsc:
|
||||||
|
return allRequests.OrderBy(x => x.Title);
|
||||||
|
case OrderType.TitleDesc:
|
||||||
|
return allRequests.OrderByDescending(x => x.Title);
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> GetTotal()
|
||||||
|
{
|
||||||
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
return await MusicRepository.GetWithUser(shouldHide.UserId).CountAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return await MusicRepository.GetWithUser().CountAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the requests.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<AlbumRequest>> GetRequests()
|
||||||
|
{
|
||||||
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
List<AlbumRequest> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = await MusicRepository.GetWithUser(shouldHide.UserId).ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = await MusicRepository.GetWithUser().ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
allRequests.ForEach(async x =>
|
||||||
|
{
|
||||||
|
await CheckForSubscription(shouldHide, x);
|
||||||
|
});
|
||||||
|
return allRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CheckForSubscription(HideResult shouldHide, AlbumRequest x)
|
||||||
|
{
|
||||||
|
if (shouldHide.UserId == x.RequestedUserId)
|
||||||
|
{
|
||||||
|
x.ShowSubscribe = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x.ShowSubscribe = true;
|
||||||
|
var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s =>
|
||||||
|
s.UserId == shouldHide.UserId && s.RequestId == x.Id && s.RequestType == RequestType.Album);
|
||||||
|
x.Subscribed = sub != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Searches the album request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="search">The search.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search)
|
||||||
|
{
|
||||||
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
List<AlbumRequest> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = await MusicRepository.GetWithUser(shouldHide.UserId).ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = await MusicRepository.GetWithUser().ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList();
|
||||||
|
results.ForEach(async x =>
|
||||||
|
{
|
||||||
|
await CheckForSubscription(shouldHide, x);
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestEngineResult> ApproveAlbumById(int requestId)
|
||||||
|
{
|
||||||
|
var request = await MusicRepository.Find(requestId);
|
||||||
|
return await ApproveAlbum(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestEngineResult> DenyAlbumById(int modelId)
|
||||||
|
{
|
||||||
|
var request = await MusicRepository.Find(modelId);
|
||||||
|
if (request == null)
|
||||||
|
{
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
ErrorMessage = "Request does not exist"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Denied = true;
|
||||||
|
// We are denying a request
|
||||||
|
NotificationHelper.Notify(request, NotificationType.RequestDeclined);
|
||||||
|
await MusicRepository.Update(request);
|
||||||
|
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
Message = "Request successfully deleted",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestEngineResult> ApproveAlbum(AlbumRequest request)
|
||||||
|
{
|
||||||
|
if (request == null)
|
||||||
|
{
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
ErrorMessage = "Request does not exist"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
request.MarkedAsApproved = DateTime.Now;
|
||||||
|
request.Approved = true;
|
||||||
|
request.Denied = false;
|
||||||
|
await MusicRepository.Update(request);
|
||||||
|
|
||||||
|
|
||||||
|
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification);
|
||||||
|
if (canNotify.Success)
|
||||||
|
{
|
||||||
|
NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.Approved)
|
||||||
|
{
|
||||||
|
var result = await _musicSender.Send(request);
|
||||||
|
if (result.Success && result.Sent)
|
||||||
|
{
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
Result = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.Success)
|
||||||
|
{
|
||||||
|
Logger.LogWarning("Tried auto sending album but failed. Message: {0}", result.Message);
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
Message = result.Message,
|
||||||
|
ErrorMessage = result.Message,
|
||||||
|
Result = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no providers then it's successful but movie has not been sent
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
Result = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the Album request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestId">The request identifier.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task RemoveAlbumRequest(int requestId)
|
||||||
|
{
|
||||||
|
var request = await MusicRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||||
|
await MusicRepository.Delete(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> UserHasRequest(string userId)
|
||||||
|
{
|
||||||
|
return await MusicRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestEngineResult> MarkUnavailable(int modelId)
|
||||||
|
{
|
||||||
|
var request = await MusicRepository.Find(modelId);
|
||||||
|
if (request == null)
|
||||||
|
{
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
ErrorMessage = "Request does not exist"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Available = false;
|
||||||
|
await MusicRepository.Update(request);
|
||||||
|
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
Message = "Request is now unavailable",
|
||||||
|
Result = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestEngineResult> MarkAvailable(int modelId)
|
||||||
|
{
|
||||||
|
var request = await MusicRepository.Find(modelId);
|
||||||
|
if (request == null)
|
||||||
|
{
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
ErrorMessage = "Request does not exist"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Available = true;
|
||||||
|
request.MarkedAsAvailable = DateTime.Now;
|
||||||
|
NotificationHelper.Notify(request, NotificationType.RequestAvailable);
|
||||||
|
await MusicRepository.Update(request);
|
||||||
|
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
Message = "Request is now available",
|
||||||
|
Result = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<RequestEngineResult> AddAlbumRequest(AlbumRequest model)
|
||||||
|
{
|
||||||
|
await MusicRepository.Add(model);
|
||||||
|
|
||||||
|
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification);
|
||||||
|
if (result.Success)
|
||||||
|
{
|
||||||
|
NotificationHelper.NewRequest(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _requestLog.Add(new RequestLog
|
||||||
|
{
|
||||||
|
UserId = (await GetUser()).Id,
|
||||||
|
RequestDate = DateTime.UtcNow,
|
||||||
|
RequestId = model.Id,
|
||||||
|
RequestType = RequestType.Album,
|
||||||
|
});
|
||||||
|
|
||||||
|
return new RequestEngineResult { Result = true, Message = $"{model.Title} has been successfully added!" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
219
src/Ombi.Core/Engine/MusicSearchEngine.cs
Normal file
219
src/Ombi.Core/Engine/MusicSearchEngine.cs
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
using System;
|
||||||
|
using AutoMapper;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.TheMovieDb;
|
||||||
|
using Ombi.Api.TheMovieDb.Models;
|
||||||
|
using Ombi.Core.Models.Requests;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Ombi.Api.Lidarr;
|
||||||
|
using Ombi.Api.Lidarr.Models;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
using Ombi.Settings.Settings.Models.External;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Engine
|
||||||
|
{
|
||||||
|
public class MusicSearchEngine : BaseMediaEngine, IMusicSearchEngine
|
||||||
|
{
|
||||||
|
public MusicSearchEngine(IPrincipal identity, IRequestServiceMain service, ILidarrApi lidarrApi, IMapper mapper,
|
||||||
|
ILogger<MusicSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub,
|
||||||
|
ISettingsService<LidarrSettings> lidarrSettings)
|
||||||
|
: base(identity, service, r, um, mem, s, sub)
|
||||||
|
{
|
||||||
|
_lidarrApi = lidarrApi;
|
||||||
|
_lidarrSettings = lidarrSettings;
|
||||||
|
Mapper = mapper;
|
||||||
|
Logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ILidarrApi _lidarrApi;
|
||||||
|
private IMapper Mapper { get; }
|
||||||
|
private ILogger Logger { get; }
|
||||||
|
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Searches the specified album.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="search">The search.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<SearchAlbumViewModel>> SearchAlbum(string search)
|
||||||
|
{
|
||||||
|
var settings = await GetSettings();
|
||||||
|
var result = await _lidarrApi.AlbumLookup(search, settings.ApiKey, settings.FullUri);
|
||||||
|
var vm = new List<SearchAlbumViewModel>();
|
||||||
|
foreach (var r in result)
|
||||||
|
{
|
||||||
|
vm.Add(await MapIntoAlbumVm(r, settings));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Searches the specified artist
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="search">The search.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<SearchArtistViewModel>> SearchArtist(string search)
|
||||||
|
{
|
||||||
|
var settings = await GetSettings();
|
||||||
|
var result = await _lidarrApi.ArtistLookup(search, settings.ApiKey, settings.FullUri);
|
||||||
|
|
||||||
|
var vm = new List<SearchArtistViewModel>();
|
||||||
|
foreach (var r in result)
|
||||||
|
{
|
||||||
|
vm.Add(await MapIntoArtistVm(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns all albums by the specified artist
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="foreignArtistId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IEnumerable<SearchAlbumViewModel>> GetArtistAlbums(string foreignArtistId)
|
||||||
|
{
|
||||||
|
var settings = await GetSettings();
|
||||||
|
var result = await _lidarrApi.GetAlbumsByArtist(foreignArtistId);
|
||||||
|
// We do not want any Singles (This will include EP's)
|
||||||
|
var albumsOnly =
|
||||||
|
result.Albums.Where(x => !x.Type.Equals("Single", StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
var vm = new List<SearchAlbumViewModel>();
|
||||||
|
foreach (var album in albumsOnly)
|
||||||
|
{
|
||||||
|
vm.Add(await MapIntoAlbumVm(album, result.Id, result.ArtistName, settings));
|
||||||
|
}
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the artist that produced the album
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="foreignArtistId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<ArtistResult> GetAlbumArtist(string foreignArtistId)
|
||||||
|
{
|
||||||
|
var settings = await GetSettings();
|
||||||
|
return await _lidarrApi.GetArtistByForeignId(foreignArtistId, settings.ApiKey, settings.FullUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ArtistResult> GetArtist(int artistId)
|
||||||
|
{
|
||||||
|
var settings = await GetSettings();
|
||||||
|
return await _lidarrApi.GetArtist(artistId, settings.ApiKey, settings.FullUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SearchArtistViewModel> MapIntoArtistVm(ArtistLookup a)
|
||||||
|
{
|
||||||
|
var vm = new SearchArtistViewModel
|
||||||
|
{
|
||||||
|
ArtistName = a.artistName,
|
||||||
|
ArtistType = a.artistType,
|
||||||
|
Banner = a.images?.FirstOrDefault(x => x.coverType.Equals("banner"))?.url,
|
||||||
|
Logo = a.images?.FirstOrDefault(x => x.coverType.Equals("logo"))?.url,
|
||||||
|
CleanName = a.cleanName,
|
||||||
|
Disambiguation = a.disambiguation,
|
||||||
|
ForignArtistId = a.foreignArtistId,
|
||||||
|
Links = a.links,
|
||||||
|
Overview = a.overview,
|
||||||
|
};
|
||||||
|
|
||||||
|
var poster = a.images?.FirstOrDefault(x => x.coverType.Equals("poaster"));
|
||||||
|
if (poster == null)
|
||||||
|
{
|
||||||
|
vm.Poster = a.remotePoster;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await Rules.StartSpecificRules(vm, SpecificRules.LidarrArtist);
|
||||||
|
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SearchAlbumViewModel> MapIntoAlbumVm(AlbumLookup a, LidarrSettings settings)
|
||||||
|
{
|
||||||
|
var vm = new SearchAlbumViewModel
|
||||||
|
{
|
||||||
|
ForeignAlbumId = a.foreignAlbumId,
|
||||||
|
Monitored = a.monitored,
|
||||||
|
Rating = a.ratings?.value ?? 0m,
|
||||||
|
ReleaseDate = a.releaseDate,
|
||||||
|
Title = a.title,
|
||||||
|
Disk = a.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url
|
||||||
|
};
|
||||||
|
if (a.artistId > 0)
|
||||||
|
{
|
||||||
|
//TODO THEY HAVE FIXED THIS IN DEV
|
||||||
|
// The JSON is different for some stupid reason
|
||||||
|
// Need to lookup the artist now and all the images -.-"
|
||||||
|
var artist = await _lidarrApi.GetArtist(a.artistId, settings.ApiKey, settings.FullUri);
|
||||||
|
vm.ArtistName = artist.artistName;
|
||||||
|
vm.ForeignArtistId = artist.foreignArtistId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vm.ForeignArtistId = a.artist?.foreignArtistId;
|
||||||
|
vm.ArtistName = a.artist?.artistName;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.Cover = a.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url;
|
||||||
|
if (vm.Cover.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
vm.Cover = a.remoteCover;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum);
|
||||||
|
|
||||||
|
await RunSearchRules(vm);
|
||||||
|
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SearchAlbumViewModel> MapIntoAlbumVm(Album a, string artistId, string artistName, LidarrSettings settings)
|
||||||
|
{
|
||||||
|
var fullAlbum = await _lidarrApi.GetAlbumByForeignId(a.Id, settings.ApiKey, settings.FullUri);
|
||||||
|
var vm = new SearchAlbumViewModel
|
||||||
|
{
|
||||||
|
ForeignAlbumId = a.Id,
|
||||||
|
Monitored = fullAlbum.monitored,
|
||||||
|
Rating = fullAlbum.ratings?.value ?? 0m,
|
||||||
|
ReleaseDate = fullAlbum.releaseDate,
|
||||||
|
Title = a.Title,
|
||||||
|
Disk = fullAlbum.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url,
|
||||||
|
ForeignArtistId = artistId,
|
||||||
|
ArtistName = artistName,
|
||||||
|
Cover = fullAlbum.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url
|
||||||
|
};
|
||||||
|
|
||||||
|
if (vm.Cover.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
vm.Cover = fullAlbum.remoteCover;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum);
|
||||||
|
|
||||||
|
await RunSearchRules(vm);
|
||||||
|
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LidarrSettings _settings;
|
||||||
|
private async Task<LidarrSettings> GetSettings()
|
||||||
|
{
|
||||||
|
return _settings ?? (_settings = await _lidarrSettings.GetSettingsAsync());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,18 @@ namespace Ombi.Core
|
||||||
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
|
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void NewRequest(AlbumRequest model)
|
||||||
|
{
|
||||||
|
var notificationModel = new NotificationOptions
|
||||||
|
{
|
||||||
|
RequestId = model.Id,
|
||||||
|
DateTime = DateTime.Now,
|
||||||
|
NotificationType = NotificationType.NewRequest,
|
||||||
|
RequestType = model.RequestType
|
||||||
|
};
|
||||||
|
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Notify(MovieRequests model, NotificationType type)
|
public void Notify(MovieRequests model, NotificationType type)
|
||||||
{
|
{
|
||||||
|
@ -66,5 +78,19 @@ namespace Ombi.Core
|
||||||
};
|
};
|
||||||
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
|
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Notify(AlbumRequest model, NotificationType type)
|
||||||
|
{
|
||||||
|
var notificationModel = new NotificationOptions
|
||||||
|
{
|
||||||
|
RequestId = model.Id,
|
||||||
|
DateTime = DateTime.Now,
|
||||||
|
NotificationType = type,
|
||||||
|
RequestType = model.RequestType,
|
||||||
|
Recipient = model.RequestedUser?.Email ?? string.Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,5 +7,6 @@ namespace Ombi.Core.Models.Requests
|
||||||
{
|
{
|
||||||
IMovieRequestRepository MovieRequestService { get; }
|
IMovieRequestRepository MovieRequestService { get; }
|
||||||
ITvRequestRepository TvRequestService { get; }
|
ITvRequestRepository TvRequestService { get; }
|
||||||
|
IMusicRequestRepository MusicRequestRepository { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Ombi.Core.Models.Requests
|
||||||
|
{
|
||||||
|
public class MusicAlbumRequestViewModel
|
||||||
|
{
|
||||||
|
public string ForeignAlbumId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,13 +5,15 @@ namespace Ombi.Core.Models.Requests
|
||||||
{
|
{
|
||||||
public class RequestService : IRequestServiceMain
|
public class RequestService : IRequestServiceMain
|
||||||
{
|
{
|
||||||
public RequestService(ITvRequestRepository tv, IMovieRequestRepository movie)
|
public RequestService(ITvRequestRepository tv, IMovieRequestRepository movie, IMusicRequestRepository music)
|
||||||
{
|
{
|
||||||
TvRequestService = tv;
|
TvRequestService = tv;
|
||||||
MovieRequestService = movie;
|
MovieRequestService = movie;
|
||||||
|
MusicRequestRepository = music;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITvRequestRepository TvRequestService { get; }
|
public ITvRequestRepository TvRequestService { get; }
|
||||||
|
public IMusicRequestRepository MusicRequestRepository { get; }
|
||||||
public IMovieRequestRepository MovieRequestService { get; }
|
public IMovieRequestRepository MovieRequestService { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
23
src/Ombi.Core/Models/Search/SearchAlbumViewModel.cs
Normal file
23
src/Ombi.Core/Models/Search/SearchAlbumViewModel.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models.Search
|
||||||
|
{
|
||||||
|
public class SearchAlbumViewModel : SearchViewModel
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string ForeignAlbumId { get; set; }
|
||||||
|
public bool Monitored { get; set; }
|
||||||
|
public string AlbumType { get; set; }
|
||||||
|
public decimal Rating { get; set; }
|
||||||
|
public DateTime ReleaseDate { get; set; }
|
||||||
|
public string ArtistName { get; set; }
|
||||||
|
public string ForeignArtistId { get; set; }
|
||||||
|
public string Cover { get; set; }
|
||||||
|
public string Disk { get; set; }
|
||||||
|
public decimal PercentOfTracks { get; set; }
|
||||||
|
public override RequestType Type => RequestType.Album;
|
||||||
|
public bool PartiallyAvailable => PercentOfTracks != 100 && PercentOfTracks > 0;
|
||||||
|
public bool FullyAvailable => PercentOfTracks == 100;
|
||||||
|
}
|
||||||
|
}
|
19
src/Ombi.Core/Models/Search/SearchArtistViewModel.cs
Normal file
19
src/Ombi.Core/Models/Search/SearchArtistViewModel.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
using Ombi.Api.Lidarr.Models;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models.Search
|
||||||
|
{
|
||||||
|
public class SearchArtistViewModel
|
||||||
|
{
|
||||||
|
public string ArtistName { get; set; }
|
||||||
|
public string ForignArtistId { get; set; }
|
||||||
|
public string Overview { get; set; }
|
||||||
|
public string Disambiguation { get; set; }
|
||||||
|
public string Banner { get; set; }
|
||||||
|
public string Poster { get; set; }
|
||||||
|
public string Logo { get; set; }
|
||||||
|
public bool Monitored { get; set; }
|
||||||
|
public string ArtistType { get; set; }
|
||||||
|
public string CleanName { get; set; }
|
||||||
|
public Link[] Links { get; set; } // Couldn't be bothered to map it
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,6 @@
|
||||||
<PackageReference Include="Hangfire" Version="1.6.19" />
|
<PackageReference Include="Hangfire" Version="1.6.19" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.1.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="2.0.0-preview1-final" />
|
|
||||||
<PackageReference Include="MiniProfiler.AspNetCore" Version="4.0.0-alpha6-79" />
|
<PackageReference Include="MiniProfiler.AspNetCore" Version="4.0.0-alpha6-79" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
||||||
|
@ -22,6 +21,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ombi.Api.DogNzb\Ombi.Api.DogNzb.csproj" />
|
<ProjectReference Include="..\Ombi.Api.DogNzb\Ombi.Api.DogNzb.csproj" />
|
||||||
|
<ProjectReference Include="..\Ombi.Api.Lidarr\Ombi.Api.Lidarr.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.SickRage\Ombi.Api.SickRage.csproj" />
|
<ProjectReference Include="..\Ombi.Api.SickRage\Ombi.Api.SickRage.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj" />
|
||||||
|
|
|
@ -3,5 +3,7 @@
|
||||||
public enum SpecificRules
|
public enum SpecificRules
|
||||||
{
|
{
|
||||||
CanSendNotification,
|
CanSendNotification,
|
||||||
|
LidarrArtist,
|
||||||
|
LidarrAlbum,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,6 +29,8 @@ namespace Ombi.Core.Rule.Rules.Request
|
||||||
obj.Approved = true;
|
obj.Approved = true;
|
||||||
if (obj.RequestType == RequestType.TvShow && User.IsInRole(OmbiRoles.AutoApproveTv))
|
if (obj.RequestType == RequestType.TvShow && User.IsInRole(OmbiRoles.AutoApproveTv))
|
||||||
obj.Approved = true;
|
obj.Approved = true;
|
||||||
|
if (obj.RequestType == RequestType.Album && User.IsInRole(OmbiRoles.AutoApproveMusic))
|
||||||
|
obj.Approved = true;
|
||||||
return Task.FromResult(Success()); // We don't really care, we just don't set the obj to approve
|
return Task.FromResult(Success()); // We don't really care, we just don't set the obj to approve
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,23 @@ namespace Ombi.Core.Rule.Rules
|
||||||
|
|
||||||
if (obj.RequestType == RequestType.Movie)
|
if (obj.RequestType == RequestType.Movie)
|
||||||
{
|
{
|
||||||
if (User.IsInRole(OmbiRoles.RequestMovie))
|
if (User.IsInRole(OmbiRoles.RequestMovie) || User.IsInRole(OmbiRoles.AutoApproveMovie))
|
||||||
return Task.FromResult(Success());
|
return Task.FromResult(Success());
|
||||||
return Task.FromResult(Fail("You do not have permissions to Request a Movie"));
|
return Task.FromResult(Fail("You do not have permissions to Request a Movie"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (User.IsInRole(OmbiRoles.RequestTv))
|
if (obj.RequestType == RequestType.TvShow)
|
||||||
|
{
|
||||||
|
if (User.IsInRole(OmbiRoles.RequestTv) || User.IsInRole(OmbiRoles.AutoApproveTv))
|
||||||
return Task.FromResult(Success());
|
return Task.FromResult(Success());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.RequestType == RequestType.Album)
|
||||||
|
{
|
||||||
|
if (User.IsInRole(OmbiRoles.RequestMusic) || User.IsInRole(OmbiRoles.AutoApproveMusic))
|
||||||
|
return Task.FromResult(Success());
|
||||||
|
}
|
||||||
|
|
||||||
return Task.FromResult(Fail("You do not have permissions to Request a TV Show"));
|
return Task.FromResult(Fail("You do not have permissions to Request a TV Show"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
||||||
|
|
||||||
var movieLimit = user.MovieRequestLimit;
|
var movieLimit = user.MovieRequestLimit;
|
||||||
var episodeLimit = user.EpisodeRequestLimit;
|
var episodeLimit = user.EpisodeRequestLimit;
|
||||||
|
var musicLimit = user.MusicRequestLimit;
|
||||||
|
|
||||||
var requestLog = _requestLog.GetAll().Where(x => x.UserId == obj.RequestedUserId);
|
var requestLog = _requestLog.GetAll().Where(x => x.UserId == obj.RequestedUserId);
|
||||||
if (obj.RequestType == RequestType.Movie)
|
if (obj.RequestType == RequestType.Movie)
|
||||||
|
@ -71,7 +72,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
||||||
return Fail("You have exceeded your Movie request quota!");
|
return Fail("You have exceeded your Movie request quota!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (obj.RequestType == RequestType.TvShow)
|
||||||
{
|
{
|
||||||
if (episodeLimit <= 0)
|
if (episodeLimit <= 0)
|
||||||
return Success();
|
return Success();
|
||||||
|
@ -94,6 +95,20 @@ namespace Ombi.Core.Rule.Rules.Request
|
||||||
{
|
{
|
||||||
return Fail("You have exceeded your Episode request quota!");
|
return Fail("You have exceeded your Episode request quota!");
|
||||||
}
|
}
|
||||||
|
} else if (obj.RequestType == RequestType.Album)
|
||||||
|
{
|
||||||
|
if (musicLimit <= 0)
|
||||||
|
return Success();
|
||||||
|
|
||||||
|
var albumLogs = requestLog.Where(x => x.RequestType == RequestType.Album);
|
||||||
|
|
||||||
|
// Count how many requests in the past 7 days
|
||||||
|
var count = await albumLogs.CountAsync(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7));
|
||||||
|
count += 1; // Since we are including this request
|
||||||
|
if (count > musicLimit)
|
||||||
|
{
|
||||||
|
return Fail("You have exceeded your Album request quota!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Success();
|
return Success();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,22 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
{
|
{
|
||||||
public class ExistingRule : BaseSearchRule, IRules<SearchViewModel>
|
public class ExistingRule : BaseSearchRule, IRules<SearchViewModel>
|
||||||
{
|
{
|
||||||
public ExistingRule(IMovieRequestRepository movie, ITvRequestRepository tv)
|
public ExistingRule(IMovieRequestRepository movie, ITvRequestRepository tv, IMusicRequestRepository music)
|
||||||
{
|
{
|
||||||
Movie = movie;
|
Movie = movie;
|
||||||
Tv = tv;
|
Tv = tv;
|
||||||
|
Music = music;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMovieRequestRepository Movie { get; }
|
private IMovieRequestRepository Movie { get; }
|
||||||
|
private IMusicRequestRepository Music { get; }
|
||||||
private ITvRequestRepository Tv { get; }
|
private ITvRequestRepository Tv { get; }
|
||||||
|
|
||||||
public Task<RuleResult> Execute(SearchViewModel obj)
|
public async Task<RuleResult> Execute(SearchViewModel obj)
|
||||||
{
|
{
|
||||||
if (obj.Type == RequestType.Movie)
|
if (obj.Type == RequestType.Movie)
|
||||||
{
|
{
|
||||||
var movieRequests = Movie.GetRequest(obj.Id);
|
var movieRequests = await Movie.GetRequestAsync(obj.Id);
|
||||||
if (movieRequests != null) // Do we already have a request for this?
|
if (movieRequests != null) // Do we already have a request for this?
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -33,11 +35,11 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
obj.Approved = movieRequests.Approved;
|
obj.Approved = movieRequests.Approved;
|
||||||
obj.Available = movieRequests.Available;
|
obj.Available = movieRequests.Available;
|
||||||
|
|
||||||
return Task.FromResult(Success());
|
return Success();
|
||||||
}
|
}
|
||||||
return Task.FromResult(Success());
|
return Success();
|
||||||
}
|
}
|
||||||
else
|
if (obj.Type == RequestType.TvShow)
|
||||||
{
|
{
|
||||||
//var tvRequests = Tv.GetRequest(obj.Id);
|
//var tvRequests = Tv.GetRequest(obj.Id);
|
||||||
//if (tvRequests != null) // Do we already have a request for this?
|
//if (tvRequests != null) // Do we already have a request for this?
|
||||||
|
@ -94,8 +96,24 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
request.PartlyAvailable = true;
|
request.PartlyAvailable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(Success());
|
return Success();
|
||||||
}
|
}
|
||||||
|
if (obj.Type == RequestType.Album)
|
||||||
|
{
|
||||||
|
var album = (SearchAlbumViewModel) obj;
|
||||||
|
var albumRequest = await Music.GetRequestAsync(album.ForeignAlbumId);
|
||||||
|
if (albumRequest != null) // Do we already have a request for this?
|
||||||
|
{
|
||||||
|
obj.Requested = true;
|
||||||
|
obj.RequestId = albumRequest.Id;
|
||||||
|
obj.Approved = albumRequest.Approved;
|
||||||
|
obj.Available = albumRequest.Available;
|
||||||
|
|
||||||
|
return Success();
|
||||||
|
}
|
||||||
|
return Success();
|
||||||
|
}
|
||||||
|
return Success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
36
src/Ombi.Core/Rule/Rules/Search/LidarrAlbumCacheRule.cs
Normal file
36
src/Ombi.Core/Rule/Rules/Search/LidarrAlbumCacheRule.cs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Rule.Rules.Search
|
||||||
|
{
|
||||||
|
public class LidarrAlbumCacheRule : SpecificRule, ISpecificRule<object>
|
||||||
|
{
|
||||||
|
public LidarrAlbumCacheRule(IRepository<LidarrAlbumCache> db)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IRepository<LidarrAlbumCache> _db;
|
||||||
|
|
||||||
|
public Task<RuleResult> Execute(object objec)
|
||||||
|
{
|
||||||
|
var obj = (SearchAlbumViewModel) objec;
|
||||||
|
// Check if it's in Lidarr
|
||||||
|
var result = _db.GetAll().FirstOrDefault(x => x.ForeignAlbumId.Equals(obj.ForeignAlbumId, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
obj.PercentOfTracks = result.PercentOfTracks;
|
||||||
|
obj.Monitored = true; // It's in Lidarr so it's monitored
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(Success());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SpecificRules Rule => SpecificRules.LidarrAlbum;
|
||||||
|
}
|
||||||
|
}
|
35
src/Ombi.Core/Rule/Rules/Search/LidarrArtistCacheRule.cs
Normal file
35
src/Ombi.Core/Rule/Rules/Search/LidarrArtistCacheRule.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Core.Models.Search;
|
||||||
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Rule.Rules.Search
|
||||||
|
{
|
||||||
|
public class LidarrArtistCacheRule : SpecificRule, ISpecificRule<object>
|
||||||
|
{
|
||||||
|
public LidarrArtistCacheRule(IRepository<LidarrArtistCache> db)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IRepository<LidarrArtistCache> _db;
|
||||||
|
|
||||||
|
public Task<RuleResult> Execute(object objec)
|
||||||
|
{
|
||||||
|
var obj = (SearchArtistViewModel) objec;
|
||||||
|
// Check if it's in Lidarr
|
||||||
|
var result = _db.GetAll().FirstOrDefault(x => x.ForeignArtistId.Equals(obj.ForignArtistId, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
obj.Monitored = true; // It's in Lidarr so it's monitored
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(Success());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SpecificRules Rule => SpecificRules.LidarrArtist;
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,6 +42,13 @@ namespace Ombi.Core.Rule.Rules.Specific
|
||||||
sendNotification = !await UserManager.IsInRoleAsync(requestedUser, OmbiRoles.AutoApproveTv);
|
sendNotification = !await UserManager.IsInRoleAsync(requestedUser, OmbiRoles.AutoApproveTv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (req.RequestType == RequestType.Album)
|
||||||
|
{
|
||||||
|
if (settings.DoNotSendNotificationsForAutoApprove)
|
||||||
|
{
|
||||||
|
sendNotification = !await UserManager.IsInRoleAsync(requestedUser, OmbiRoles.AutoApproveMusic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (await UserManager.IsInRoleAsync(requestedUser, OmbiRoles.Admin))
|
if (await UserManager.IsInRoleAsync(requestedUser, OmbiRoles.Admin))
|
||||||
{
|
{
|
||||||
|
|
10
src/Ombi.Core/Senders/IMusicSender.cs
Normal file
10
src/Ombi.Core/Senders/IMusicSender.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Senders
|
||||||
|
{
|
||||||
|
public interface IMusicSender
|
||||||
|
{
|
||||||
|
Task<SenderResult> Send(AlbumRequest model);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,9 @@ namespace Ombi.Core
|
||||||
{
|
{
|
||||||
void NewRequest(FullBaseRequest model);
|
void NewRequest(FullBaseRequest model);
|
||||||
void NewRequest(ChildRequests model);
|
void NewRequest(ChildRequests model);
|
||||||
|
void NewRequest(AlbumRequest model);
|
||||||
void Notify(MovieRequests model, NotificationType type);
|
void Notify(MovieRequests model, NotificationType type);
|
||||||
void Notify(ChildRequests model, NotificationType type);
|
void Notify(ChildRequests model, NotificationType type);
|
||||||
|
void Notify(AlbumRequest model, NotificationType type);
|
||||||
}
|
}
|
||||||
}
|
}
|
126
src/Ombi.Core/Senders/MusicSender.cs
Normal file
126
src/Ombi.Core/Senders/MusicSender.cs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Api.Lidarr;
|
||||||
|
using Ombi.Api.Lidarr.Models;
|
||||||
|
using Ombi.Api.Radarr;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Settings.Settings.Models.External;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Senders
|
||||||
|
{
|
||||||
|
public class MusicSender : IMusicSender
|
||||||
|
{
|
||||||
|
public MusicSender(ISettingsService<LidarrSettings> lidarr, ILidarrApi lidarrApi)
|
||||||
|
{
|
||||||
|
_lidarrSettings = lidarr;
|
||||||
|
_lidarrApi = lidarrApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||||
|
private readonly ILidarrApi _lidarrApi;
|
||||||
|
|
||||||
|
public async Task<SenderResult> Send(AlbumRequest model)
|
||||||
|
{
|
||||||
|
var settings = await _lidarrSettings.GetSettingsAsync();
|
||||||
|
if (settings.Enabled)
|
||||||
|
{
|
||||||
|
return await SendToLidarr(model, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SenderResult { Success = false, Sent = false, Message = "Lidarr is not enabled" };
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SenderResult> SendToLidarr(AlbumRequest model, LidarrSettings settings)
|
||||||
|
{
|
||||||
|
var qualityToUse = int.Parse(settings.DefaultQualityProfile);
|
||||||
|
//if (model.QualityOverride > 0)
|
||||||
|
//{
|
||||||
|
// qualityToUse = model.QualityOverride;
|
||||||
|
//}
|
||||||
|
|
||||||
|
var rootFolderPath = /*model.RootPathOverride <= 0 ?*/ settings.DefaultRootPath /*: await RadarrRootPath(model.RootPathOverride, settings)*/;
|
||||||
|
|
||||||
|
// Need to get the artist
|
||||||
|
var artist = await _lidarrApi.GetArtistByForeignId(model.ForeignArtistId, settings.ApiKey, settings.FullUri);
|
||||||
|
|
||||||
|
if (artist == null || artist.id <= 0)
|
||||||
|
{
|
||||||
|
// Create artist
|
||||||
|
var newArtist = new ArtistAdd
|
||||||
|
{
|
||||||
|
foreignArtistId = model.ForeignArtistId,
|
||||||
|
addOptions = new Addoptions
|
||||||
|
{
|
||||||
|
monitored = true,
|
||||||
|
searchForMissingAlbums = false,
|
||||||
|
selectedOption = 6, // None
|
||||||
|
AlbumsToMonitor = new[] {model.ForeignAlbumId}
|
||||||
|
},
|
||||||
|
added = DateTime.Now,
|
||||||
|
monitored = true,
|
||||||
|
albumFolder = settings.AlbumFolder,
|
||||||
|
artistName = model.ArtistName,
|
||||||
|
cleanName = model.ArtistName.ToLowerInvariant().RemoveSpaces(),
|
||||||
|
images = new Image[] { },
|
||||||
|
languageProfileId = settings.LanguageProfileId,
|
||||||
|
links = new Link[] {},
|
||||||
|
metadataProfileId = settings.MetadataProfileId,
|
||||||
|
qualityProfileId = qualityToUse,
|
||||||
|
rootFolderPath = rootFolderPath,
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await _lidarrApi.AddArtist(newArtist, settings.ApiKey, settings.FullUri);
|
||||||
|
if (result != null && result.id > 0)
|
||||||
|
{
|
||||||
|
// Setup the albums
|
||||||
|
return new SenderResult { Message = "Album has been requested!", Sent = true, Success = true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await SetupAlbum(model, artist, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SenderResult { Success = false, Sent = false, Message = "Album is already monitored" };
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SenderResult> SetupAlbum(AlbumRequest model, ArtistResult artist, LidarrSettings settings)
|
||||||
|
{
|
||||||
|
// Get the album id
|
||||||
|
var albums = await _lidarrApi.GetAllAlbumsByArtistId(artist.id, settings.ApiKey, settings.FullUri);
|
||||||
|
var album = albums.FirstOrDefault(x =>
|
||||||
|
x.foreignAlbumId.Equals(model.ForeignAlbumId, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
var maxRetryCount = 10; // 5 seconds
|
||||||
|
var currentRetry = 0;
|
||||||
|
while (!albums.Any() || album == null)
|
||||||
|
{
|
||||||
|
if (currentRetry >= maxRetryCount)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
currentRetry++;
|
||||||
|
await Task.Delay(500);
|
||||||
|
albums = await _lidarrApi.GetAllAlbumsByArtistId(artist.id, settings.ApiKey, settings.FullUri);
|
||||||
|
album = albums.FirstOrDefault(x =>
|
||||||
|
x.foreignAlbumId.Equals(model.ForeignAlbumId, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
}
|
||||||
|
// Get the album we want.
|
||||||
|
|
||||||
|
if (album == null)
|
||||||
|
{
|
||||||
|
return new SenderResult { Message = "Could not find album in Lidarr", Sent = false, Success = false };
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await _lidarrApi.MontiorAlbum(album.id, settings.ApiKey, settings.FullUri);
|
||||||
|
if (result.monitored)
|
||||||
|
{
|
||||||
|
return new SenderResult {Message = "Album has been requested!", Sent = true, Success = true};
|
||||||
|
}
|
||||||
|
return new SenderResult { Message = "Could not set album to monitored", Sent = false, Success = false };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ using Ombi.Api.CouchPotato;
|
||||||
using Ombi.Api.DogNzb;
|
using Ombi.Api.DogNzb;
|
||||||
using Ombi.Api.FanartTv;
|
using Ombi.Api.FanartTv;
|
||||||
using Ombi.Api.Github;
|
using Ombi.Api.Github;
|
||||||
|
using Ombi.Api.Lidarr;
|
||||||
using Ombi.Api.Mattermost;
|
using Ombi.Api.Mattermost;
|
||||||
using Ombi.Api.Notifications;
|
using Ombi.Api.Notifications;
|
||||||
using Ombi.Api.Pushbullet;
|
using Ombi.Api.Pushbullet;
|
||||||
|
@ -53,9 +54,11 @@ using PlexContentCacher = Ombi.Schedule.Jobs.Plex;
|
||||||
using Ombi.Api.Telegram;
|
using Ombi.Api.Telegram;
|
||||||
using Ombi.Core.Authentication;
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Processor;
|
using Ombi.Core.Processor;
|
||||||
|
using Ombi.Schedule.Jobs.Lidarr;
|
||||||
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
||||||
using Ombi.Schedule.Jobs.SickRage;
|
using Ombi.Schedule.Jobs.SickRage;
|
||||||
using Ombi.Schedule.Processor;
|
using Ombi.Schedule.Processor;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
namespace Ombi.DependencyInjection
|
namespace Ombi.DependencyInjection
|
||||||
{
|
{
|
||||||
|
@ -82,7 +85,10 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<IUserStatsEngine, UserStatsEngine>();
|
services.AddTransient<IUserStatsEngine, UserStatsEngine>();
|
||||||
services.AddTransient<IMovieSender, MovieSender>();
|
services.AddTransient<IMovieSender, MovieSender>();
|
||||||
services.AddTransient<IRecentlyAddedEngine, RecentlyAddedEngine>();
|
services.AddTransient<IRecentlyAddedEngine, RecentlyAddedEngine>();
|
||||||
|
services.AddTransient<IMusicSearchEngine, MusicSearchEngine>();
|
||||||
|
services.AddTransient<IMusicRequestEngine, MusicRequestEngine>();
|
||||||
services.AddTransient<ITvSender, TvSender>();
|
services.AddTransient<ITvSender, TvSender>();
|
||||||
|
services.AddTransient<IMusicSender, MusicSender>();
|
||||||
services.AddTransient<IMassEmailSender, MassEmailSender>();
|
services.AddTransient<IMassEmailSender, MassEmailSender>();
|
||||||
services.AddTransient<IPlexOAuthManager, PlexOAuthManager>();
|
services.AddTransient<IPlexOAuthManager, PlexOAuthManager>();
|
||||||
}
|
}
|
||||||
|
@ -117,6 +123,7 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<ISickRageApi, SickRageApi>();
|
services.AddTransient<ISickRageApi, SickRageApi>();
|
||||||
services.AddTransient<IAppVeyorApi, AppVeyorApi>();
|
services.AddTransient<IAppVeyorApi, AppVeyorApi>();
|
||||||
services.AddTransient<IOneSignalApi, OneSignalApi>();
|
services.AddTransient<IOneSignalApi, OneSignalApi>();
|
||||||
|
services.AddTransient<ILidarrApi, LidarrApi>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RegisterStore(this IServiceCollection services) {
|
public static void RegisterStore(this IServiceCollection services) {
|
||||||
|
@ -131,6 +138,7 @@ namespace Ombi.DependencyInjection
|
||||||
|
|
||||||
services.AddTransient<ITvRequestRepository, TvRequestRepository>();
|
services.AddTransient<ITvRequestRepository, TvRequestRepository>();
|
||||||
services.AddTransient<IMovieRequestRepository, MovieRequestRepository>();
|
services.AddTransient<IMovieRequestRepository, MovieRequestRepository>();
|
||||||
|
services.AddTransient<IMusicRequestRepository, MusicRequestRepository>();
|
||||||
services.AddTransient<IAuditRepository, AuditRepository>();
|
services.AddTransient<IAuditRepository, AuditRepository>();
|
||||||
services.AddTransient<IApplicationConfigRepository, ApplicationConfigRepository>();
|
services.AddTransient<IApplicationConfigRepository, ApplicationConfigRepository>();
|
||||||
services.AddTransient<ITokenRepository, TokenRepository>();
|
services.AddTransient<ITokenRepository, TokenRepository>();
|
||||||
|
@ -180,6 +188,9 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<IRefreshMetadata, RefreshMetadata>();
|
services.AddTransient<IRefreshMetadata, RefreshMetadata>();
|
||||||
services.AddTransient<INewsletterJob, NewsletterJob>();
|
services.AddTransient<INewsletterJob, NewsletterJob>();
|
||||||
services.AddTransient<IPlexRecentlyAddedSync, PlexRecentlyAddedSync>();
|
services.AddTransient<IPlexRecentlyAddedSync, PlexRecentlyAddedSync>();
|
||||||
|
services.AddTransient<ILidarrAlbumSync, LidarrAlbumSync>();
|
||||||
|
services.AddTransient<ILidarrArtistSync, LidarrArtistSync>();
|
||||||
|
services.AddTransient<ILidarrAvailabilityChecker, LidarrAvailabilityChecker>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<ProjectReference Include="..\Ombi.Api.Emby\Ombi.Api.Emby.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Emby\Ombi.Api.Emby.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.FanartTv\Ombi.Api.FanartTv.csproj" />
|
<ProjectReference Include="..\Ombi.Api.FanartTv\Ombi.Api.FanartTv.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Github\Ombi.Api.Github.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Github\Ombi.Api.Github.csproj" />
|
||||||
|
<ProjectReference Include="..\Ombi.Api.Lidarr\Ombi.Api.Lidarr.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Notifications\Ombi.Api.Notifications.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Notifications\Ombi.Api.Notifications.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace Ombi.Helpers
|
||||||
public const string NowPlayingMovies = nameof(NowPlayingMovies);
|
public const string NowPlayingMovies = nameof(NowPlayingMovies);
|
||||||
public const string RadarrRootProfiles = nameof(RadarrRootProfiles);
|
public const string RadarrRootProfiles = nameof(RadarrRootProfiles);
|
||||||
public const string RadarrQualityProfiles = nameof(RadarrQualityProfiles);
|
public const string RadarrQualityProfiles = nameof(RadarrQualityProfiles);
|
||||||
|
public const string LidarrRootFolders = nameof(LidarrRootFolders);
|
||||||
|
public const string LidarrQualityProfiles = nameof(LidarrQualityProfiles);
|
||||||
public const string FanartTv = nameof(FanartTv);
|
public const string FanartTv = nameof(FanartTv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace Ombi.Helpers
|
||||||
public static EventId CouchPotatoCacher => new EventId(2007);
|
public static EventId CouchPotatoCacher => new EventId(2007);
|
||||||
public static EventId PlexContentCacher => new EventId(2008);
|
public static EventId PlexContentCacher => new EventId(2008);
|
||||||
public static EventId SickRageCacher => new EventId(2009);
|
public static EventId SickRageCacher => new EventId(2009);
|
||||||
|
public static EventId LidarrArtistCache => new EventId(2010);
|
||||||
|
|
||||||
public static EventId MovieSender => new EventId(3000);
|
public static EventId MovieSender => new EventId(3000);
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,11 @@
|
||||||
public const string Admin = nameof(Admin);
|
public const string Admin = nameof(Admin);
|
||||||
public const string AutoApproveMovie = nameof(AutoApproveMovie);
|
public const string AutoApproveMovie = nameof(AutoApproveMovie);
|
||||||
public const string AutoApproveTv = nameof(AutoApproveTv);
|
public const string AutoApproveTv = nameof(AutoApproveTv);
|
||||||
|
public const string AutoApproveMusic = nameof(AutoApproveMusic);
|
||||||
public const string PowerUser = nameof(PowerUser);
|
public const string PowerUser = nameof(PowerUser);
|
||||||
public const string RequestTv = nameof(RequestTv);
|
public const string RequestTv = nameof(RequestTv);
|
||||||
public const string RequestMovie = nameof(RequestMovie);
|
public const string RequestMovie = nameof(RequestMovie);
|
||||||
|
public const string RequestMusic = nameof(RequestMusic);
|
||||||
public const string Disabled = nameof(Disabled);
|
public const string Disabled = nameof(Disabled);
|
||||||
public const string ReceivesNewsletter = nameof(ReceivesNewsletter);
|
public const string ReceivesNewsletter = nameof(ReceivesNewsletter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,10 @@ namespace Ombi.Helpers
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string RemoveSpaces(this string str)
|
||||||
|
{
|
||||||
|
return str.Replace(" ", "");
|
||||||
|
}
|
||||||
public static string StripCharacters(this string str, params char[] chars)
|
public static string StripCharacters(this string str, params char[] chars)
|
||||||
{
|
{
|
||||||
return string.Concat(str.Where(c => !chars.Contains(c)));
|
return string.Concat(str.Where(c => !chars.Contains(c)));
|
||||||
|
|
|
@ -20,8 +20,8 @@ namespace Ombi.Notifications.Agents
|
||||||
{
|
{
|
||||||
public DiscordNotification(IDiscordApi api, ISettingsService<DiscordNotificationSettings> sn,
|
public DiscordNotification(IDiscordApi api, ISettingsService<DiscordNotificationSettings> sn,
|
||||||
ILogger<DiscordNotification> log, INotificationTemplatesRepository r,
|
ILogger<DiscordNotification> log, INotificationTemplatesRepository r,
|
||||||
IMovieRequestRepository m, ITvRequestRepository t, ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub)
|
IMovieRequestRepository m, ITvRequestRepository t, ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub, IMusicRequestRepository music)
|
||||||
: base(sn, r, m, t,s,log, sub)
|
: base(sn, r, m, t, s, log, sub, music)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
@ -130,12 +130,18 @@ namespace Ombi.Notifications.Agents
|
||||||
title = MovieRequest.Title;
|
title = MovieRequest.Title;
|
||||||
image = MovieRequest.PosterPath;
|
image = MovieRequest.PosterPath;
|
||||||
}
|
}
|
||||||
else
|
else if (model.RequestType == RequestType.TvShow)
|
||||||
{
|
{
|
||||||
user = TvRequest.RequestedUser.UserAlias;
|
user = TvRequest.RequestedUser.UserAlias;
|
||||||
title = TvRequest.ParentRequest.Title;
|
title = TvRequest.ParentRequest.Title;
|
||||||
image = TvRequest.ParentRequest.PosterPath;
|
image = TvRequest.ParentRequest.PosterPath;
|
||||||
}
|
}
|
||||||
|
else if (model.RequestType == RequestType.Album)
|
||||||
|
{
|
||||||
|
user = AlbumRequest.RequestedUser.UserAlias;
|
||||||
|
title = AlbumRequest.Title;
|
||||||
|
image = AlbumRequest.Cover;
|
||||||
|
}
|
||||||
var message = $"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
var message = $"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Ombi.Notifications.Agents
|
||||||
public class EmailNotification : BaseNotification<EmailNotificationSettings>, IEmailNotification
|
public class EmailNotification : BaseNotification<EmailNotificationSettings>, IEmailNotification
|
||||||
{
|
{
|
||||||
public EmailNotification(ISettingsService<EmailNotificationSettings> settings, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, IEmailProvider prov, ISettingsService<CustomizationSettings> c,
|
public EmailNotification(ISettingsService<EmailNotificationSettings> settings, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, IEmailProvider prov, ISettingsService<CustomizationSettings> c,
|
||||||
ILogger<EmailNotification> log, UserManager<OmbiUser> um, IRepository<RequestSubscription> sub) : base(settings, r, m, t, c, log, sub)
|
ILogger<EmailNotification> log, UserManager<OmbiUser> um, IRepository<RequestSubscription> sub, IMusicRequestRepository music) : base(settings, r, m, t, c, log, sub, music)
|
||||||
{
|
{
|
||||||
EmailProvider = prov;
|
EmailProvider = prov;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace Ombi.Notifications.Agents
|
||||||
public class MattermostNotification : BaseNotification<MattermostNotificationSettings>, IMattermostNotification
|
public class MattermostNotification : BaseNotification<MattermostNotificationSettings>, IMattermostNotification
|
||||||
{
|
{
|
||||||
public MattermostNotification(IMattermostApi api, ISettingsService<MattermostNotificationSettings> sn, ILogger<MattermostNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
public MattermostNotification(IMattermostApi api, ISettingsService<MattermostNotificationSettings> sn, ILogger<MattermostNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
||||||
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub) : base(sn, r, m, t,s,log, sub)
|
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub, IMusicRequestRepository music) : base(sn, r, m, t, s, log, sub, music)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Ombi.Notifications.Agents
|
||||||
{
|
{
|
||||||
public MobileNotification(IOneSignalApi api, ISettingsService<MobileNotificationSettings> sn, ILogger<MobileNotification> log, INotificationTemplatesRepository r,
|
public MobileNotification(IOneSignalApi api, ISettingsService<MobileNotificationSettings> sn, ILogger<MobileNotification> log, INotificationTemplatesRepository r,
|
||||||
IMovieRequestRepository m, ITvRequestRepository t, ISettingsService<CustomizationSettings> s, IRepository<NotificationUserId> notification,
|
IMovieRequestRepository m, ITvRequestRepository t, ISettingsService<CustomizationSettings> s, IRepository<NotificationUserId> notification,
|
||||||
UserManager<OmbiUser> um, IRepository<RequestSubscription> sub) : base(sn, r, m, t, s,log, sub)
|
UserManager<OmbiUser> um, IRepository<RequestSubscription> sub, IMusicRequestRepository music) : base(sn, r, m, t, s, log, sub, music)
|
||||||
{
|
{
|
||||||
_api = api;
|
_api = api;
|
||||||
_logger = log;
|
_logger = log;
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Ombi.Notifications.Agents
|
||||||
public class PushbulletNotification : BaseNotification<PushbulletSettings>, IPushbulletNotification
|
public class PushbulletNotification : BaseNotification<PushbulletSettings>, IPushbulletNotification
|
||||||
{
|
{
|
||||||
public PushbulletNotification(IPushbulletApi api, ISettingsService<PushbulletSettings> sn, ILogger<PushbulletNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
public PushbulletNotification(IPushbulletApi api, ISettingsService<PushbulletSettings> sn, ILogger<PushbulletNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
||||||
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub) : base(sn, r, m, t,s,log, sub)
|
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub, IMusicRequestRepository music) : base(sn, r, m, t, s, log, sub, music)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace Ombi.Notifications.Agents
|
||||||
public class PushoverNotification : BaseNotification<PushoverSettings>, IPushoverNotification
|
public class PushoverNotification : BaseNotification<PushoverSettings>, IPushoverNotification
|
||||||
{
|
{
|
||||||
public PushoverNotification(IPushoverApi api, ISettingsService<PushoverSettings> sn, ILogger<PushoverNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
public PushoverNotification(IPushoverApi api, ISettingsService<PushoverSettings> sn, ILogger<PushoverNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
||||||
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub) : base(sn, r, m, t, s, log, sub)
|
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub, IMusicRequestRepository music) : base(sn, r, m, t, s, log, sub, music)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace Ombi.Notifications.Agents
|
||||||
public class SlackNotification : BaseNotification<SlackNotificationSettings>, ISlackNotification
|
public class SlackNotification : BaseNotification<SlackNotificationSettings>, ISlackNotification
|
||||||
{
|
{
|
||||||
public SlackNotification(ISlackApi api, ISettingsService<SlackNotificationSettings> sn, ILogger<SlackNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
public SlackNotification(ISlackApi api, ISettingsService<SlackNotificationSettings> sn, ILogger<SlackNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
||||||
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub) : base(sn, r, m, t, s, log, sub)
|
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub, IMusicRequestRepository music) : base(sn, r, m, t, s, log, sub, music)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Ombi.Notifications.Agents
|
||||||
public TelegramNotification(ITelegramApi api, ISettingsService<TelegramSettings> sn, ILogger<TelegramNotification> log,
|
public TelegramNotification(ITelegramApi api, ISettingsService<TelegramSettings> sn, ILogger<TelegramNotification> log,
|
||||||
INotificationTemplatesRepository r, IMovieRequestRepository m,
|
INotificationTemplatesRepository r, IMovieRequestRepository m,
|
||||||
ITvRequestRepository t, ISettingsService<CustomizationSettings> s
|
ITvRequestRepository t, ISettingsService<CustomizationSettings> s
|
||||||
, IRepository<RequestSubscription> sub) : base(sn, r, m, t,s,log, sub)
|
, IRepository<RequestSubscription> sub, IMusicRequestRepository music) : base(sn, r, m, t,s,log, sub, music)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Ombi.Notifications.Interfaces
|
||||||
public abstract class BaseNotification<T> : INotification where T : Settings.Settings.Models.Settings, new()
|
public abstract class BaseNotification<T> : INotification where T : Settings.Settings.Models.Settings, new()
|
||||||
{
|
{
|
||||||
protected BaseNotification(ISettingsService<T> settings, INotificationTemplatesRepository templateRepo, IMovieRequestRepository movie, ITvRequestRepository tv,
|
protected BaseNotification(ISettingsService<T> settings, INotificationTemplatesRepository templateRepo, IMovieRequestRepository movie, ITvRequestRepository tv,
|
||||||
ISettingsService<CustomizationSettings> customization, ILogger<BaseNotification<T>> log, IRepository<RequestSubscription> sub)
|
ISettingsService<CustomizationSettings> customization, ILogger<BaseNotification<T>> log, IRepository<RequestSubscription> sub, IMusicRequestRepository album)
|
||||||
{
|
{
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
TemplateRepository = templateRepo;
|
TemplateRepository = templateRepo;
|
||||||
|
@ -30,12 +30,14 @@ namespace Ombi.Notifications.Interfaces
|
||||||
CustomizationSettings.ClearCache();
|
CustomizationSettings.ClearCache();
|
||||||
RequestSubscription = sub;
|
RequestSubscription = sub;
|
||||||
_log = log;
|
_log = log;
|
||||||
|
AlbumRepository = album;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ISettingsService<T> Settings { get; }
|
protected ISettingsService<T> Settings { get; }
|
||||||
protected INotificationTemplatesRepository TemplateRepository { get; }
|
protected INotificationTemplatesRepository TemplateRepository { get; }
|
||||||
protected IMovieRequestRepository MovieRepository { get; }
|
protected IMovieRequestRepository MovieRepository { get; }
|
||||||
protected ITvRequestRepository TvRepository { get; }
|
protected ITvRequestRepository TvRepository { get; }
|
||||||
|
protected IMusicRequestRepository AlbumRepository { get; }
|
||||||
protected CustomizationSettings Customization { get; set; }
|
protected CustomizationSettings Customization { get; set; }
|
||||||
protected IRepository<RequestSubscription> RequestSubscription { get; set; }
|
protected IRepository<RequestSubscription> RequestSubscription { get; set; }
|
||||||
private ISettingsService<CustomizationSettings> CustomizationSettings { get; }
|
private ISettingsService<CustomizationSettings> CustomizationSettings { get; }
|
||||||
|
@ -43,6 +45,7 @@ namespace Ombi.Notifications.Interfaces
|
||||||
|
|
||||||
|
|
||||||
protected ChildRequests TvRequest { get; set; }
|
protected ChildRequests TvRequest { get; set; }
|
||||||
|
protected AlbumRequest AlbumRequest { get; set; }
|
||||||
protected MovieRequests MovieRequest { get; set; }
|
protected MovieRequests MovieRequest { get; set; }
|
||||||
protected IQueryable<OmbiUser> SubsribedUsers { get; private set; }
|
protected IQueryable<OmbiUser> SubsribedUsers { get; private set; }
|
||||||
|
|
||||||
|
@ -130,10 +133,14 @@ namespace Ombi.Notifications.Interfaces
|
||||||
{
|
{
|
||||||
MovieRequest = await MovieRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == requestId);
|
MovieRequest = await MovieRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||||
}
|
}
|
||||||
else
|
else if (type == RequestType.TvShow)
|
||||||
{
|
{
|
||||||
TvRequest = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId);
|
TvRequest = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||||
}
|
}
|
||||||
|
else if (type == RequestType.Album)
|
||||||
|
{
|
||||||
|
AlbumRequest = await AlbumRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<T> GetConfiguration()
|
private async Task<T> GetConfiguration()
|
||||||
|
@ -181,11 +188,16 @@ namespace Ombi.Notifications.Interfaces
|
||||||
|
|
||||||
curlys.Setup(model, MovieRequest, Customization);
|
curlys.Setup(model, MovieRequest, Customization);
|
||||||
}
|
}
|
||||||
else
|
else if (model.RequestType == RequestType.TvShow)
|
||||||
{
|
{
|
||||||
_log.LogDebug("Notification options: {@model}, Req: {@TvRequest}, Settings: {@Customization}", model, TvRequest, Customization);
|
_log.LogDebug("Notification options: {@model}, Req: {@TvRequest}, Settings: {@Customization}", model, TvRequest, Customization);
|
||||||
curlys.Setup(model, TvRequest, Customization);
|
curlys.Setup(model, TvRequest, Customization);
|
||||||
}
|
}
|
||||||
|
else if (model.RequestType == RequestType.Album)
|
||||||
|
{
|
||||||
|
_log.LogDebug("Notification options: {@model}, Req: {@AlbumRequest}, Settings: {@Customization}", model, AlbumRequest, Customization);
|
||||||
|
curlys.Setup(model, AlbumRequest, Customization);
|
||||||
|
}
|
||||||
var parsed = resolver.ParseMessage(template, curlys);
|
var parsed = resolver.ParseMessage(template, curlys);
|
||||||
|
|
||||||
return parsed;
|
return parsed;
|
||||||
|
|
|
@ -58,6 +58,40 @@ namespace Ombi.Notifications
|
||||||
AdditionalInformation = opts?.AdditionalInformation ?? string.Empty;
|
AdditionalInformation = opts?.AdditionalInformation ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Setup(NotificationOptions opts, AlbumRequest req, CustomizationSettings s)
|
||||||
|
{
|
||||||
|
LoadIssues(opts);
|
||||||
|
string title;
|
||||||
|
if (req == null)
|
||||||
|
{
|
||||||
|
opts.Substitutes.TryGetValue("Title", out title);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
title = req?.Title;
|
||||||
|
}
|
||||||
|
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
|
||||||
|
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
|
||||||
|
RequestedUser = req?.RequestedUser?.UserName;
|
||||||
|
if (UserName.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
// Can be set if it's an issue
|
||||||
|
UserName = req?.RequestedUser?.UserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName;
|
||||||
|
Title = title;
|
||||||
|
RequestedDate = req?.RequestedDate.ToString("D");
|
||||||
|
if (Type.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
Type = req?.RequestType.Humanize();
|
||||||
|
}
|
||||||
|
Year = req?.ReleaseDate.Year.ToString();
|
||||||
|
PosterImage = (req?.Cover.HasValue() ?? false) ? req.Cover : req?.Disk ?? string.Empty;
|
||||||
|
|
||||||
|
AdditionalInformation = opts?.AdditionalInformation ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetupNewsletter(CustomizationSettings s, OmbiUser username)
|
public void SetupNewsletter(CustomizationSettings s, OmbiUser username)
|
||||||
{
|
{
|
||||||
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
|
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
|
||||||
|
|
|
@ -4,6 +4,7 @@ using Ombi.Core.Settings;
|
||||||
using Ombi.Schedule.Jobs;
|
using Ombi.Schedule.Jobs;
|
||||||
using Ombi.Schedule.Jobs.Couchpotato;
|
using Ombi.Schedule.Jobs.Couchpotato;
|
||||||
using Ombi.Schedule.Jobs.Emby;
|
using Ombi.Schedule.Jobs.Emby;
|
||||||
|
using Ombi.Schedule.Jobs.Lidarr;
|
||||||
using Ombi.Schedule.Jobs.Ombi;
|
using Ombi.Schedule.Jobs.Ombi;
|
||||||
using Ombi.Schedule.Jobs.Plex;
|
using Ombi.Schedule.Jobs.Plex;
|
||||||
using Ombi.Schedule.Jobs.Radarr;
|
using Ombi.Schedule.Jobs.Radarr;
|
||||||
|
@ -19,7 +20,7 @@ namespace Ombi.Schedule
|
||||||
IOmbiAutomaticUpdater updater, IEmbyContentSync embySync, IPlexUserImporter userImporter,
|
IOmbiAutomaticUpdater updater, IEmbyContentSync embySync, IPlexUserImporter userImporter,
|
||||||
IEmbyUserImporter embyUserImporter, ISonarrSync cache, ICouchPotatoSync cpCache,
|
IEmbyUserImporter embyUserImporter, ISonarrSync cache, ICouchPotatoSync cpCache,
|
||||||
ISettingsService<JobSettings> jobsettings, ISickRageSync srSync, IRefreshMetadata refresh,
|
ISettingsService<JobSettings> jobsettings, ISickRageSync srSync, IRefreshMetadata refresh,
|
||||||
INewsletterJob newsletter, IPlexRecentlyAddedSync recentlyAddedPlex)
|
INewsletterJob newsletter, IPlexRecentlyAddedSync recentlyAddedPlex, ILidarrArtistSync artist)
|
||||||
{
|
{
|
||||||
_plexContentSync = plexContentSync;
|
_plexContentSync = plexContentSync;
|
||||||
_radarrSync = radarrSync;
|
_radarrSync = radarrSync;
|
||||||
|
@ -34,6 +35,7 @@ namespace Ombi.Schedule
|
||||||
_refreshMetadata = refresh;
|
_refreshMetadata = refresh;
|
||||||
_newsletter = newsletter;
|
_newsletter = newsletter;
|
||||||
_plexRecentlyAddedSync = recentlyAddedPlex;
|
_plexRecentlyAddedSync = recentlyAddedPlex;
|
||||||
|
_lidarrArtistSync = artist;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IPlexContentSync _plexContentSync;
|
private readonly IPlexContentSync _plexContentSync;
|
||||||
|
@ -49,6 +51,7 @@ namespace Ombi.Schedule
|
||||||
private readonly ISettingsService<JobSettings> _jobSettings;
|
private readonly ISettingsService<JobSettings> _jobSettings;
|
||||||
private readonly IRefreshMetadata _refreshMetadata;
|
private readonly IRefreshMetadata _refreshMetadata;
|
||||||
private readonly INewsletterJob _newsletter;
|
private readonly INewsletterJob _newsletter;
|
||||||
|
private readonly ILidarrArtistSync _lidarrArtistSync;
|
||||||
|
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
|
@ -62,6 +65,7 @@ namespace Ombi.Schedule
|
||||||
RecurringJob.AddOrUpdate(() => _cpCache.Start(), JobSettingsHelper.CouchPotato(s));
|
RecurringJob.AddOrUpdate(() => _cpCache.Start(), JobSettingsHelper.CouchPotato(s));
|
||||||
RecurringJob.AddOrUpdate(() => _srSync.Start(), JobSettingsHelper.SickRageSync(s));
|
RecurringJob.AddOrUpdate(() => _srSync.Start(), JobSettingsHelper.SickRageSync(s));
|
||||||
RecurringJob.AddOrUpdate(() => _refreshMetadata.Start(), JobSettingsHelper.RefreshMetadata(s));
|
RecurringJob.AddOrUpdate(() => _refreshMetadata.Start(), JobSettingsHelper.RefreshMetadata(s));
|
||||||
|
RecurringJob.AddOrUpdate(() => _lidarrArtistSync.CacheContent(), JobSettingsHelper.LidarrArtistSync(s));
|
||||||
|
|
||||||
RecurringJob.AddOrUpdate(() => _updater.Update(null), JobSettingsHelper.Updater(s));
|
RecurringJob.AddOrUpdate(() => _updater.Update(null), JobSettingsHelper.Updater(s));
|
||||||
|
|
||||||
|
|
13
src/Ombi.Schedule/Jobs/Lidarr/ILidarrAlbumSync.cs
Normal file
13
src/Ombi.Schedule/Jobs/Lidarr/ILidarrAlbumSync.cs
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
13
src/Ombi.Schedule/Jobs/Lidarr/ILidarrArtistSync.cs
Normal file
13
src/Ombi.Schedule/Jobs/Lidarr/ILidarrArtistSync.cs
Normal file
|
@ -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,9 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ombi.Schedule.Jobs.Lidarr
|
||||||
|
{
|
||||||
|
public interface ILidarrAvailabilityChecker
|
||||||
|
{
|
||||||
|
Task Start();
|
||||||
|
}
|
||||||
|
}
|
119
src/Ombi.Schedule/Jobs/Lidarr/LidarrAlbumSync.cs
Normal file
119
src/Ombi.Schedule/Jobs/Lidarr/LidarrAlbumSync.cs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
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 LidarrAlbumSync : ILidarrAlbumSync
|
||||||
|
{
|
||||||
|
public LidarrAlbumSync(ISettingsService<LidarrSettings> lidarr, ILidarrApi lidarrApi, ILogger<LidarrAlbumSync> log, IOmbiContext ctx,
|
||||||
|
IBackgroundJobClient job, ILidarrAvailabilityChecker availability)
|
||||||
|
{
|
||||||
|
_lidarrSettings = lidarr;
|
||||||
|
_lidarrApi = lidarrApi;
|
||||||
|
_logger = log;
|
||||||
|
_ctx = ctx;
|
||||||
|
_job = job;
|
||||||
|
_availability = availability;
|
||||||
|
_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 ILidarrAvailabilityChecker _availability;
|
||||||
|
|
||||||
|
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 albumCache = new List<LidarrAlbumCache>();
|
||||||
|
foreach (var a in albums)
|
||||||
|
{
|
||||||
|
if (a.id > 0)
|
||||||
|
{
|
||||||
|
albumCache.Add(new LidarrAlbumCache
|
||||||
|
{
|
||||||
|
ArtistId = a.artistId,
|
||||||
|
ForeignAlbumId = a.foreignAlbumId,
|
||||||
|
ReleaseDate = a.releaseDate,
|
||||||
|
TrackCount = a.currentRelease.trackCount,
|
||||||
|
Monitored = a.monitored,
|
||||||
|
Title = a.title,
|
||||||
|
PercentOfTracks = a.statistics?.percentOfEpisodes ?? 0m,
|
||||||
|
AddedAt = DateTime.Now,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await _ctx.LidarrAlbumCache.AddRangeAsync(albumCache);
|
||||||
|
|
||||||
|
await _ctx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(LoggingEvents.Cacher, ex, "Failed caching queued items from Lidarr Album");
|
||||||
|
}
|
||||||
|
|
||||||
|
_job.Enqueue(() => _availability.Start());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
115
src/Ombi.Schedule/Jobs/Lidarr/LidarrArtistSync.cs
Normal file
115
src/Ombi.Schedule/Jobs/Lidarr/LidarrArtistSync.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
src/Ombi.Schedule/Jobs/Lidarr/LidarrAvailabilityChecker.cs
Normal file
73
src/Ombi.Schedule/Jobs/Lidarr/LidarrAvailabilityChecker.cs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Hangfire;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Core.Notifications;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Notifications.Models;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Schedule.Jobs.Lidarr
|
||||||
|
{
|
||||||
|
public class LidarrAvailabilityChecker : ILidarrAvailabilityChecker
|
||||||
|
{
|
||||||
|
public LidarrAvailabilityChecker(IMusicRequestRepository requests, IRepository<LidarrAlbumCache> albums, ILogger<LidarrAvailabilityChecker> log,
|
||||||
|
IBackgroundJobClient job, INotificationService notification)
|
||||||
|
{
|
||||||
|
_cachedAlbums = albums;
|
||||||
|
_requestRepository = requests;
|
||||||
|
_logger = log;
|
||||||
|
_job = job;
|
||||||
|
_notificationService = notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IMusicRequestRepository _requestRepository;
|
||||||
|
private readonly IRepository<LidarrAlbumCache> _cachedAlbums;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly IBackgroundJobClient _job;
|
||||||
|
private readonly INotificationService _notificationService;
|
||||||
|
|
||||||
|
public async Task Start()
|
||||||
|
{
|
||||||
|
var allAlbumRequests = _requestRepository.GetAll().Include(x => x.RequestedUser).Where(x => !x.Available);
|
||||||
|
var albumsToUpdate = new List<AlbumRequest>();
|
||||||
|
foreach (var request in allAlbumRequests)
|
||||||
|
{
|
||||||
|
// Check if we have it cached
|
||||||
|
var cachedAlbum = await _cachedAlbums.FirstOrDefaultAsync(x => x.ForeignAlbumId.Equals(request.ForeignAlbumId));
|
||||||
|
if (cachedAlbum != null)
|
||||||
|
{
|
||||||
|
if (cachedAlbum.Monitored && cachedAlbum.FullyAvailable)
|
||||||
|
{
|
||||||
|
request.Available = true;
|
||||||
|
request.MarkedAsAvailable = DateTime.Now;
|
||||||
|
albumsToUpdate.Add(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var albumRequest in albumsToUpdate)
|
||||||
|
{
|
||||||
|
await _requestRepository.Update(albumRequest);
|
||||||
|
var recipient = albumRequest.RequestedUser.Email.HasValue() ? albumRequest.RequestedUser.Email : string.Empty;
|
||||||
|
|
||||||
|
_logger.LogDebug("AlbumId: {0}, RequestUser: {1}", albumRequest.Id, recipient);
|
||||||
|
|
||||||
|
_job.Enqueue(() => _notificationService.Publish(new NotificationOptions
|
||||||
|
{
|
||||||
|
DateTime = DateTime.Now,
|
||||||
|
NotificationType = NotificationType.RequestAvailable,
|
||||||
|
RequestId = albumRequest.Id,
|
||||||
|
RequestType = RequestType.Album,
|
||||||
|
Recipient = recipient,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
|
||||||
namespace Ombi.Schedule.Jobs.Ombi
|
namespace Ombi.Schedule.Jobs.Ombi
|
||||||
{
|
{
|
||||||
|
@ -21,14 +22,21 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void AddMediaServerUrl(StringBuilder sb, string mediaurl, string url)
|
protected virtual void AddMediaServerUrl(StringBuilder sb, string mediaurl, string url)
|
||||||
|
{
|
||||||
|
if (url.HasValue())
|
||||||
{
|
{
|
||||||
sb.Append("<tr>");
|
sb.Append("<tr>");
|
||||||
sb.Append("<td style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 14px; vertical-align: top; \">");
|
sb.Append(
|
||||||
|
"<td style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 14px; vertical-align: top; \">");
|
||||||
sb.AppendFormat("<a href=\"{0}\" target=\"_blank\">", mediaurl);
|
sb.AppendFormat("<a href=\"{0}\" target=\"_blank\">", mediaurl);
|
||||||
sb.AppendFormat("<img class=\"poster-overlay\" src=\"{0}\" width=\"150\" height=\"225\" style=\"border: none;-ms-interpolation-mode: bicubic; max-width: 100%;display: block; visibility: hidden; \">", url);
|
sb.AppendFormat(
|
||||||
|
"<img class=\"poster-overlay\" src=\"{0}\" width=\"150\" height=\"225\" style=\"border: none;-ms-interpolation-mode: bicubic; max-width: 100%;display: block; visibility: hidden; \">",
|
||||||
|
url);
|
||||||
sb.Append("</a>");
|
sb.Append("</a>");
|
||||||
sb.Append("</td>");
|
sb.Append("</td>");
|
||||||
sb.Append("</tr>");
|
sb.Append("</tr>");
|
||||||
|
}
|
||||||
|
|
||||||
sb.Append("</table>");
|
sb.Append("</table>");
|
||||||
sb.Append("</td>");
|
sb.Append("</td>");
|
||||||
}
|
}
|
||||||
|
@ -44,9 +52,9 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
{
|
{
|
||||||
sb.Append("<tr>");
|
sb.Append("<tr>");
|
||||||
sb.Append("<td class=\"title\" style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 0.9rem; vertical-align: top; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; line-height: 1.2rem; padding: 5px; \">");
|
sb.Append("<td class=\"title\" style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 0.9rem; vertical-align: top; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; line-height: 1.2rem; padding: 5px; \">");
|
||||||
sb.AppendFormat("<a href=\"{0}\" target=\"_blank\">", url);
|
if(url.HasValue()) sb.AppendFormat("<a href=\"{0}\" target=\"_blank\">", url);
|
||||||
sb.AppendFormat("<h1 style=\"white-space: normal; line-height: 1;\" >{0}</h1>", title);
|
sb.AppendFormat("<h1 style=\"white-space: normal; line-height: 1;\" >{0}</h1>", title);
|
||||||
sb.Append("</a>");
|
if (url.HasValue()) sb.Append("</a>");
|
||||||
sb.Append("</td>");
|
sb.Append("</td>");
|
||||||
sb.Append("</tr>");
|
sb.Append("</tr>");
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ using MailKit;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.Lidarr;
|
||||||
|
using Ombi.Api.Lidarr.Models;
|
||||||
using Ombi.Api.TheMovieDb;
|
using Ombi.Api.TheMovieDb;
|
||||||
using Ombi.Api.TheMovieDb.Models;
|
using Ombi.Api.TheMovieDb.Models;
|
||||||
using Ombi.Api.TvMaze;
|
using Ombi.Api.TvMaze;
|
||||||
|
@ -18,6 +20,7 @@ using Ombi.Notifications;
|
||||||
using Ombi.Notifications.Models;
|
using Ombi.Notifications.Models;
|
||||||
using Ombi.Notifications.Templates;
|
using Ombi.Notifications.Templates;
|
||||||
using Ombi.Settings.Settings.Models;
|
using Ombi.Settings.Settings.Models;
|
||||||
|
using Ombi.Settings.Settings.Models.External;
|
||||||
using Ombi.Settings.Settings.Models.Notifications;
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
@ -29,7 +32,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
public NewsletterJob(IPlexContentRepository plex, IEmbyContentRepository emby, IRepository<RecentlyAddedLog> addedLog,
|
public NewsletterJob(IPlexContentRepository plex, IEmbyContentRepository emby, IRepository<RecentlyAddedLog> addedLog,
|
||||||
IMovieDbApi movieApi, ITvMazeApi tvApi, IEmailProvider email, ISettingsService<CustomizationSettings> custom,
|
IMovieDbApi movieApi, ITvMazeApi tvApi, IEmailProvider email, ISettingsService<CustomizationSettings> custom,
|
||||||
ISettingsService<EmailNotificationSettings> emailSettings, INotificationTemplatesRepository templateRepo,
|
ISettingsService<EmailNotificationSettings> emailSettings, INotificationTemplatesRepository templateRepo,
|
||||||
UserManager<OmbiUser> um, ISettingsService<NewsletterSettings> newsletter, ILogger<NewsletterJob> log)
|
UserManager<OmbiUser> um, ISettingsService<NewsletterSettings> newsletter, ILogger<NewsletterJob> log,
|
||||||
|
ILidarrApi lidarrApi, IRepository<LidarrAlbumCache> albumCache, ISettingsService<LidarrSettings> lidarrSettings)
|
||||||
{
|
{
|
||||||
_plex = plex;
|
_plex = plex;
|
||||||
_emby = emby;
|
_emby = emby;
|
||||||
|
@ -46,6 +50,10 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
_customizationSettings.ClearCache();
|
_customizationSettings.ClearCache();
|
||||||
_newsletterSettings.ClearCache();
|
_newsletterSettings.ClearCache();
|
||||||
_log = log;
|
_log = log;
|
||||||
|
_lidarrApi = lidarrApi;
|
||||||
|
_lidarrAlbumRepository = albumCache;
|
||||||
|
_lidarrSettings = lidarrSettings;
|
||||||
|
_lidarrSettings.ClearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IPlexContentRepository _plex;
|
private readonly IPlexContentRepository _plex;
|
||||||
|
@ -60,6 +68,9 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
private readonly ISettingsService<NewsletterSettings> _newsletterSettings;
|
private readonly ISettingsService<NewsletterSettings> _newsletterSettings;
|
||||||
private readonly UserManager<OmbiUser> _userManager;
|
private readonly UserManager<OmbiUser> _userManager;
|
||||||
private readonly ILogger _log;
|
private readonly ILogger _log;
|
||||||
|
private readonly ILidarrApi _lidarrApi;
|
||||||
|
private readonly IRepository<LidarrAlbumCache> _lidarrAlbumRepository;
|
||||||
|
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||||
|
|
||||||
public async Task Start(NewsletterSettings settings, bool test)
|
public async Task Start(NewsletterSettings settings, bool test)
|
||||||
{
|
{
|
||||||
|
@ -87,21 +98,26 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
// Get the Content
|
// Get the Content
|
||||||
var plexContent = _plex.GetAll().Include(x => x.Episodes).AsNoTracking();
|
var plexContent = _plex.GetAll().Include(x => x.Episodes).AsNoTracking();
|
||||||
var embyContent = _emby.GetAll().Include(x => x.Episodes).AsNoTracking();
|
var embyContent = _emby.GetAll().Include(x => x.Episodes).AsNoTracking();
|
||||||
|
var lidarrContent = _lidarrAlbumRepository.GetAll().AsNoTracking();
|
||||||
|
|
||||||
var addedLog = _recentlyAddedLog.GetAll();
|
var addedLog = _recentlyAddedLog.GetAll();
|
||||||
var addedPlexMovieLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
|
var addedPlexMovieLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
|
||||||
var addedEmbyMoviesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
|
var addedEmbyMoviesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
|
||||||
|
var addedAlbumLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Lidarr && x.ContentType == ContentType.Album).Select(x => x.AlbumId);
|
||||||
|
|
||||||
var addedPlexEpisodesLogIds =
|
var addedPlexEpisodesLogIds =
|
||||||
addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode);
|
addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode);
|
||||||
var addedEmbyEpisodesLogIds =
|
var addedEmbyEpisodesLogIds =
|
||||||
addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Episode);
|
addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Episode);
|
||||||
|
|
||||||
|
|
||||||
// Filter out the ones that we haven't sent yet
|
// Filter out the ones that we haven't sent yet
|
||||||
var plexContentMoviesToSend = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie && x.HasTheMovieDb && !addedPlexMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId)));
|
var plexContentMoviesToSend = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie && x.HasTheMovieDb && !addedPlexMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId)));
|
||||||
var embyContentMoviesToSend = embyContent.Where(x => x.Type == EmbyMediaType.Movie && x.HasTheMovieDb && !addedEmbyMoviesLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId)));
|
var embyContentMoviesToSend = embyContent.Where(x => x.Type == EmbyMediaType.Movie && x.HasTheMovieDb && !addedEmbyMoviesLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId)));
|
||||||
|
var lidarrContentAlbumsToSend = lidarrContent.Where(x => !addedAlbumLogIds.Contains(x.ForeignAlbumId)).ToHashSet();
|
||||||
_log.LogInformation("Plex Movies to send: {0}", plexContentMoviesToSend.Count());
|
_log.LogInformation("Plex Movies to send: {0}", plexContentMoviesToSend.Count());
|
||||||
_log.LogInformation("Emby Movies to send: {0}", embyContentMoviesToSend.Count());
|
_log.LogInformation("Emby Movies to send: {0}", embyContentMoviesToSend.Count());
|
||||||
|
_log.LogInformation("Albums to send: {0}", lidarrContentAlbumsToSend.Count());
|
||||||
|
|
||||||
var plexEpisodesToSend =
|
var plexEpisodesToSend =
|
||||||
FilterPlexEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).Where(x => x.Series.HasTvDb).AsNoTracking(), addedPlexEpisodesLogIds);
|
FilterPlexEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).Where(x => x.Series.HasTvDb).AsNoTracking(), addedPlexEpisodesLogIds);
|
||||||
|
@ -117,11 +133,12 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
var embym = embyContent.Where(x => x.Type == EmbyMediaType.Movie ).OrderByDescending(x => x.AddedAt).Take(10);
|
var embym = embyContent.Where(x => x.Type == EmbyMediaType.Movie ).OrderByDescending(x => x.AddedAt).Take(10);
|
||||||
var plext = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet();
|
var plext = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet();
|
||||||
var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
|
var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
|
||||||
body = await BuildHtml(plexm, embym, plext, embyt, settings);
|
var lidarr = lidarrContent.OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
|
||||||
|
body = await BuildHtml(plexm, embym, plext, embyt, lidarr, settings);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, settings);
|
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, lidarrContentAlbumsToSend, settings);
|
||||||
if (body.IsNullOrEmpty())
|
if (body.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -298,7 +315,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
return resolver.ParseMessage(template, curlys);
|
return resolver.ParseMessage(template, curlys);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> BuildHtml(IQueryable<PlexServerContent> plexContentToSend, IQueryable<EmbyContent> embyContentToSend, HashSet<PlexEpisode> plexEpisodes, HashSet<EmbyEpisode> embyEp, NewsletterSettings settings)
|
private async Task<string> BuildHtml(IQueryable<PlexServerContent> plexContentToSend, IQueryable<EmbyContent> embyContentToSend,
|
||||||
|
HashSet<PlexEpisode> plexEpisodes, HashSet<EmbyEpisode> embyEp, HashSet<LidarrAlbumCache> albums, NewsletterSettings settings)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
@ -340,6 +358,24 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
sb.Append("</table>");
|
sb.Append("</table>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (albums.Any() && !settings.DisableMusic)
|
||||||
|
{
|
||||||
|
sb.Append("<h1 style=\"text-align: center; max-width: 1042px;\">New Albums</h1><br /><br />");
|
||||||
|
sb.Append(
|
||||||
|
"<table class=\"movies-table\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; \">");
|
||||||
|
sb.Append("<tr>");
|
||||||
|
sb.Append("<td style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 14px; vertical-align: top; \">");
|
||||||
|
sb.Append("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; \">");
|
||||||
|
sb.Append("<tr>");
|
||||||
|
await ProcessAlbums(albums, sb);
|
||||||
|
sb.Append("</tr>");
|
||||||
|
sb.Append("</table>");
|
||||||
|
sb.Append("</td>");
|
||||||
|
sb.Append("</tr>");
|
||||||
|
sb.Append("</table>");
|
||||||
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,6 +418,40 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private async Task ProcessAlbums(HashSet<LidarrAlbumCache> albumsToSend, StringBuilder sb)
|
||||||
|
{
|
||||||
|
var settings = await _lidarrSettings.GetSettingsAsync();
|
||||||
|
int count = 0;
|
||||||
|
var ordered = albumsToSend.OrderByDescending(x => x.AddedAt);
|
||||||
|
foreach (var content in ordered)
|
||||||
|
{
|
||||||
|
var info = await _lidarrApi.GetAlbumByForeignId(content.ForeignAlbumId, settings.ApiKey, settings.FullUri);
|
||||||
|
if (info == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CreateAlbumHtmlContent(sb, info);
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_log.LogError(e, "Error when Processing Lidarr Album {0}", info.title);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
EndLoopHtml(sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 2)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
sb.Append("</tr>");
|
||||||
|
sb.Append("<tr>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ProcessEmbyMovies(IQueryable<EmbyContent> embyContent, StringBuilder sb)
|
private async Task ProcessEmbyMovies(IQueryable<EmbyContent> embyContent, StringBuilder sb)
|
||||||
{
|
{
|
||||||
|
@ -467,6 +537,41 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateAlbumHtmlContent(StringBuilder sb, AlbumLookup info)
|
||||||
|
{
|
||||||
|
var cover = info.images
|
||||||
|
.FirstOrDefault(x => x.coverType.Equals("cover", StringComparison.InvariantCultureIgnoreCase))?.url;
|
||||||
|
if (cover.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
cover = info.remoteCover;
|
||||||
|
}
|
||||||
|
AddBackgroundInsideTable(sb, cover);
|
||||||
|
var disk = info.images
|
||||||
|
.FirstOrDefault(x => x.coverType.Equals("disc", StringComparison.InvariantCultureIgnoreCase))?.url;
|
||||||
|
if (disk.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
disk = info.remoteCover;
|
||||||
|
}
|
||||||
|
AddPosterInsideTable(sb, disk);
|
||||||
|
|
||||||
|
AddMediaServerUrl(sb, string.Empty, string.Empty);
|
||||||
|
AddInfoTable(sb);
|
||||||
|
|
||||||
|
var releaseDate = $"({info.releaseDate.Year})";
|
||||||
|
|
||||||
|
AddTitle(sb, string.Empty, $"{info.title} {releaseDate}");
|
||||||
|
|
||||||
|
var summary = info.artist?.artistName ?? string.Empty;
|
||||||
|
if (summary.Length > 280)
|
||||||
|
{
|
||||||
|
summary = summary.Remove(280);
|
||||||
|
summary = summary + "...</p>";
|
||||||
|
}
|
||||||
|
AddParagraph(sb, summary);
|
||||||
|
|
||||||
|
AddGenres(sb, $"Type: {info.albumType}");
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ProcessPlexTv(HashSet<PlexEpisode> plexContent, StringBuilder sb)
|
private async Task ProcessPlexTv(HashSet<PlexEpisode> plexContent, StringBuilder sb)
|
||||||
{
|
{
|
||||||
var series = new List<PlexServerContent>();
|
var series = new List<PlexServerContent>();
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ombi.Api.CouchPotato\Ombi.Api.CouchPotato.csproj" />
|
<ProjectReference Include="..\Ombi.Api.CouchPotato\Ombi.Api.CouchPotato.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Emby\Ombi.Api.Emby.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.Plex\Ombi.Api.Plex.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Radarr\Ombi.Api.Radarr.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Radarr\Ombi.Api.Radarr.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Service\Ombi.Api.Service.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Service\Ombi.Api.Service.csproj" />
|
||||||
|
|
15
src/Ombi.Settings/Settings/Models/External/LidarrSettings.cs
vendored
Normal file
15
src/Ombi.Settings/Settings/Models/External/LidarrSettings.cs
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using Ombi.Core.Settings.Models.External;
|
||||||
|
|
||||||
|
namespace Ombi.Settings.Settings.Models.External
|
||||||
|
{
|
||||||
|
public class LidarrSettings : ExternalSettings
|
||||||
|
{
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
public string DefaultQualityProfile { get; set; }
|
||||||
|
public string DefaultRootPath { get; set; }
|
||||||
|
public bool AlbumFolder { get; set; }
|
||||||
|
public int LanguageProfileId { get; set; }
|
||||||
|
public int MetadataProfileId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,5 +13,6 @@
|
||||||
public string SickRageSync { get; set; }
|
public string SickRageSync { get; set; }
|
||||||
public string RefreshMetadata { get; set; }
|
public string RefreshMetadata { get; set; }
|
||||||
public string Newsletter { 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));
|
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)
|
private static string Get(string settings, string defaultCron)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace Ombi.Settings.Settings.Models.Notifications
|
||||||
{
|
{
|
||||||
public bool DisableTv { get; set; }
|
public bool DisableTv { get; set; }
|
||||||
public bool DisableMovies { get; set; }
|
public bool DisableMovies { get; set; }
|
||||||
|
public bool DisableMusic { get; set; }
|
||||||
public bool Enabled { get; set; }
|
public bool Enabled { get; set; }
|
||||||
public List<string> ExternalEmails { get; set; } = new List<string>();
|
public List<string> ExternalEmails { get; set; } = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace Ombi.Store.Context
|
||||||
void Seed();
|
void Seed();
|
||||||
DbSet<Audit> Audit { get; set; }
|
DbSet<Audit> Audit { get; set; }
|
||||||
DbSet<MovieRequests> MovieRequests { get; set; }
|
DbSet<MovieRequests> MovieRequests { get; set; }
|
||||||
|
DbSet<AlbumRequest> AlbumRequests { get; set; }
|
||||||
DbSet<TvRequests> TvRequests { get; set; }
|
DbSet<TvRequests> TvRequests { get; set; }
|
||||||
DbSet<ChildRequests> ChildRequests { get; set; }
|
DbSet<ChildRequests> ChildRequests { get; set; }
|
||||||
DbSet<Issues> Issues { get; set; }
|
DbSet<Issues> Issues { get; set; }
|
||||||
|
@ -39,6 +40,8 @@ namespace Ombi.Store.Context
|
||||||
EntityEntry<TEntity> Update<TEntity>(TEntity entity) where TEntity : class;
|
EntityEntry<TEntity> Update<TEntity>(TEntity entity) where TEntity : class;
|
||||||
DbSet<CouchPotatoCache> CouchPotatoCache { get; set; }
|
DbSet<CouchPotatoCache> CouchPotatoCache { get; set; }
|
||||||
DbSet<SickRageCache> SickRageCache { get; set; }
|
DbSet<SickRageCache> SickRageCache { get; set; }
|
||||||
|
DbSet<LidarrArtistCache> LidarrArtistCache { get; set; }
|
||||||
|
DbSet<LidarrAlbumCache> LidarrAlbumCache { get; set; }
|
||||||
DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
|
DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
|
||||||
DbSet<RequestLog> RequestLogs { get; set; }
|
DbSet<RequestLog> RequestLogs { get; set; }
|
||||||
DbSet<RecentlyAddedLog> RecentlyAddedLogs { get; set; }
|
DbSet<RecentlyAddedLog> RecentlyAddedLogs { get; set; }
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace Ombi.Store.Context
|
||||||
public DbSet<EmbyEpisode> EmbyEpisode { get; set; }
|
public DbSet<EmbyEpisode> EmbyEpisode { get; set; }
|
||||||
|
|
||||||
public DbSet<MovieRequests> MovieRequests { get; set; }
|
public DbSet<MovieRequests> MovieRequests { get; set; }
|
||||||
|
public DbSet<AlbumRequest> AlbumRequests { get; set; }
|
||||||
public DbSet<TvRequests> TvRequests { get; set; }
|
public DbSet<TvRequests> TvRequests { get; set; }
|
||||||
public DbSet<ChildRequests> ChildRequests { get; set; }
|
public DbSet<ChildRequests> ChildRequests { get; set; }
|
||||||
|
|
||||||
|
@ -44,6 +45,8 @@ namespace Ombi.Store.Context
|
||||||
public DbSet<Audit> Audit { get; set; }
|
public DbSet<Audit> Audit { get; set; }
|
||||||
public DbSet<Tokens> Tokens { get; set; }
|
public DbSet<Tokens> Tokens { get; set; }
|
||||||
public DbSet<SonarrCache> SonarrCache { 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<SonarrEpisodeCache> SonarrEpisodeCache { get; set; }
|
||||||
public DbSet<SickRageCache> SickRageCache { get; set; }
|
public DbSet<SickRageCache> SickRageCache { get; set; }
|
||||||
public DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
|
public DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
|
||||||
|
|
23
src/Ombi.Store/Entities/LidarrAlbumCache.cs
Normal file
23
src/Ombi.Store/Entities/LidarrAlbumCache.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
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; }
|
||||||
|
public decimal PercentOfTracks { get; set; }
|
||||||
|
public DateTime AddedAt { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public bool PartiallyAvailable => PercentOfTracks != 100 && PercentOfTracks > 0;
|
||||||
|
[NotMapped]
|
||||||
|
public bool FullyAvailable => PercentOfTracks == 100;
|
||||||
|
}
|
||||||
|
}
|
14
src/Ombi.Store/Entities/LidarrArtistCache.cs
Normal file
14
src/Ombi.Store/Entities/LidarrArtistCache.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Entities
|
||||||
|
{
|
||||||
|
[Table("LidarrArtistCache")]
|
||||||
|
public class LidarrArtistCache : Entity
|
||||||
|
{
|
||||||
|
public int ArtistId { get; set; }
|
||||||
|
public string ArtistName { get; set; }
|
||||||
|
public string ForeignArtistId { get; set; }
|
||||||
|
public bool Monitored { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ namespace Ombi.Store.Entities
|
||||||
|
|
||||||
public int? MovieRequestLimit { get; set; }
|
public int? MovieRequestLimit { get; set; }
|
||||||
public int? EpisodeRequestLimit { get; set; }
|
public int? EpisodeRequestLimit { get; set; }
|
||||||
|
public int? MusicRequestLimit { get; set; }
|
||||||
|
|
||||||
public string UserAccessToken { get; set; }
|
public string UserAccessToken { get; set; }
|
||||||
|
|
||||||
|
@ -59,5 +60,6 @@ namespace Ombi.Store.Entities
|
||||||
get => base.ConcurrencyStamp;
|
get => base.ConcurrencyStamp;
|
||||||
set => base.ConcurrencyStamp = value;
|
set => base.ConcurrencyStamp = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,18 +11,21 @@ namespace Ombi.Store.Entities
|
||||||
public int ContentId { get; set; } // This is dependant on the type, it's either TMDBID or TVDBID
|
public int ContentId { get; set; } // This is dependant on the type, it's either TMDBID or TVDBID
|
||||||
public int? EpisodeNumber { get; set; }
|
public int? EpisodeNumber { get; set; }
|
||||||
public int? SeasonNumber { get; set; }
|
public int? SeasonNumber { get; set; }
|
||||||
|
public string AlbumId { get; set; }
|
||||||
public DateTime AddedAt { get; set; }
|
public DateTime AddedAt { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum RecentlyAddedType
|
public enum RecentlyAddedType
|
||||||
{
|
{
|
||||||
Plex = 0,
|
Plex = 0,
|
||||||
Emby = 1
|
Emby = 1,
|
||||||
|
Lidarr = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ContentType
|
public enum ContentType
|
||||||
{
|
{
|
||||||
Parent = 0,
|
Parent = 0,
|
||||||
Episode = 1
|
Episode = 1,
|
||||||
|
Album = 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ namespace Ombi.Store.Entities
|
||||||
public enum RequestType
|
public enum RequestType
|
||||||
{
|
{
|
||||||
TvShow = 0,
|
TvShow = 0,
|
||||||
Movie = 1
|
Movie = 1,
|
||||||
|
Album = 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
21
src/Ombi.Store/Entities/Requests/AlbumRequest.cs
Normal file
21
src/Ombi.Store/Entities/Requests/AlbumRequest.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Entities.Requests
|
||||||
|
{
|
||||||
|
[Table("AlbumRequests")]
|
||||||
|
public class AlbumRequest : BaseRequest
|
||||||
|
{
|
||||||
|
public string ForeignAlbumId { get; set; }
|
||||||
|
public string ForeignArtistId { get; set; }
|
||||||
|
public string Disk { get; set; }
|
||||||
|
public string Cover { get; set; }
|
||||||
|
public decimal Rating { get; set; }
|
||||||
|
public DateTime ReleaseDate { get; set; }
|
||||||
|
public string ArtistName { get; set; }
|
||||||
|
[NotMapped]
|
||||||
|
public bool Subscribed { get; set; }
|
||||||
|
[NotMapped]
|
||||||
|
public bool ShowSubscribe { get; set; }
|
||||||
|
}
|
||||||
|
}
|
1045
src/Ombi.Store/Migrations/20180824152254_MusicRequests.Designer.cs
generated
Normal file
1045
src/Ombi.Store/Migrations/20180824152254_MusicRequests.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
67
src/Ombi.Store/Migrations/20180824152254_MusicRequests.cs
Normal file
67
src/Ombi.Store/Migrations/20180824152254_MusicRequests.cs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Migrations
|
||||||
|
{
|
||||||
|
public partial class MusicRequests : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "MusicRequestLimit",
|
||||||
|
table: "AspNetUsers",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AlbumRequests",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Title = table.Column<string>(nullable: true),
|
||||||
|
Approved = table.Column<bool>(nullable: false),
|
||||||
|
MarkedAsApproved = table.Column<DateTime>(nullable: false),
|
||||||
|
RequestedDate = table.Column<DateTime>(nullable: false),
|
||||||
|
Available = table.Column<bool>(nullable: false),
|
||||||
|
MarkedAsAvailable = table.Column<DateTime>(nullable: true),
|
||||||
|
RequestedUserId = table.Column<string>(nullable: true),
|
||||||
|
Denied = table.Column<bool>(nullable: true),
|
||||||
|
MarkedAsDenied = table.Column<DateTime>(nullable: false),
|
||||||
|
DeniedReason = table.Column<string>(nullable: true),
|
||||||
|
RequestType = table.Column<int>(nullable: false),
|
||||||
|
ForeignAlbumId = table.Column<string>(nullable: true),
|
||||||
|
ForeignArtistId = table.Column<string>(nullable: true),
|
||||||
|
Disk = table.Column<string>(nullable: true),
|
||||||
|
Cover = table.Column<string>(nullable: true),
|
||||||
|
Rating = table.Column<decimal>(nullable: false),
|
||||||
|
ReleaseDate = table.Column<DateTime>(nullable: false),
|
||||||
|
ArtistName = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AlbumRequests", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AlbumRequests_AspNetUsers_RequestedUserId",
|
||||||
|
column: x => x.RequestedUserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AlbumRequests_RequestedUserId",
|
||||||
|
table: "AlbumRequests",
|
||||||
|
column: "RequestedUserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AlbumRequests");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MusicRequestLimit",
|
||||||
|
table: "AspNetUsers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1087
src/Ombi.Store/Migrations/20180824211553_LidarrSyncJobs.Designer.cs
generated
Normal file
1087
src/Ombi.Store/Migrations/20180824211553_LidarrSyncJobs.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
55
src/Ombi.Store/Migrations/20180824211553_LidarrSyncJobs.cs
Normal file
55
src/Ombi.Store/Migrations/20180824211553_LidarrSyncJobs.cs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Migrations
|
||||||
|
{
|
||||||
|
public partial class LidarrSyncJobs : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
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),
|
||||||
|
PercentOfTracks = table.Column<decimal>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_LidarrAlbumCache", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "LidarrAlbumCache");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "LidarrArtistCache");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1091
src/Ombi.Store/Migrations/20180828083219_MusicIssues.Designer.cs
generated
Normal file
1091
src/Ombi.Store/Migrations/20180828083219_MusicIssues.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
33
src/Ombi.Store/Migrations/20180828083219_MusicIssues.cs
Normal file
33
src/Ombi.Store/Migrations/20180828083219_MusicIssues.cs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Migrations
|
||||||
|
{
|
||||||
|
public partial class MusicIssues : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "AlbumId",
|
||||||
|
table: "RecentlyAddedLog",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "AddedAt",
|
||||||
|
table: "LidarrAlbumCache",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AlbumId",
|
||||||
|
table: "RecentlyAddedLog");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AddedAt",
|
||||||
|
table: "LidarrAlbumCache");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -244,6 +244,50 @@ namespace Ombi.Store.Migrations
|
||||||
b.ToTable("GlobalSettings");
|
b.ToTable("GlobalSettings");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime>("AddedAt");
|
||||||
|
|
||||||
|
b.Property<int>("ArtistId");
|
||||||
|
|
||||||
|
b.Property<string>("ForeignAlbumId");
|
||||||
|
|
||||||
|
b.Property<bool>("Monitored");
|
||||||
|
|
||||||
|
b.Property<decimal>("PercentOfTracks");
|
||||||
|
|
||||||
|
b.Property<DateTime>("ReleaseDate");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
b.Property<int>("TrackCount");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
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 =>
|
modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
@ -311,6 +355,8 @@ namespace Ombi.Store.Migrations
|
||||||
|
|
||||||
b.Property<int?>("MovieRequestLimit");
|
b.Property<int?>("MovieRequestLimit");
|
||||||
|
|
||||||
|
b.Property<int?>("MusicRequestLimit");
|
||||||
|
|
||||||
b.Property<string>("NormalizedEmail")
|
b.Property<string>("NormalizedEmail")
|
||||||
.HasMaxLength(256);
|
.HasMaxLength(256);
|
||||||
|
|
||||||
|
@ -445,6 +491,8 @@ namespace Ombi.Store.Migrations
|
||||||
|
|
||||||
b.Property<DateTime>("AddedAt");
|
b.Property<DateTime>("AddedAt");
|
||||||
|
|
||||||
|
b.Property<string>("AlbumId");
|
||||||
|
|
||||||
b.Property<int>("ContentId");
|
b.Property<int>("ContentId");
|
||||||
|
|
||||||
b.Property<int>("ContentType");
|
b.Property<int>("ContentType");
|
||||||
|
@ -460,6 +508,54 @@ namespace Ombi.Store.Migrations
|
||||||
b.ToTable("RecentlyAddedLog");
|
b.ToTable("RecentlyAddedLog");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.AlbumRequest", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Approved");
|
||||||
|
|
||||||
|
b.Property<string>("ArtistName");
|
||||||
|
|
||||||
|
b.Property<bool>("Available");
|
||||||
|
|
||||||
|
b.Property<string>("Cover");
|
||||||
|
|
||||||
|
b.Property<bool?>("Denied");
|
||||||
|
|
||||||
|
b.Property<string>("DeniedReason");
|
||||||
|
|
||||||
|
b.Property<string>("Disk");
|
||||||
|
|
||||||
|
b.Property<string>("ForeignAlbumId");
|
||||||
|
|
||||||
|
b.Property<string>("ForeignArtistId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("MarkedAsApproved");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("MarkedAsAvailable");
|
||||||
|
|
||||||
|
b.Property<DateTime>("MarkedAsDenied");
|
||||||
|
|
||||||
|
b.Property<decimal>("Rating");
|
||||||
|
|
||||||
|
b.Property<DateTime>("ReleaseDate");
|
||||||
|
|
||||||
|
b.Property<int>("RequestType");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RequestedDate");
|
||||||
|
|
||||||
|
b.Property<string>("RequestedUserId");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RequestedUserId");
|
||||||
|
|
||||||
|
b.ToTable("AlbumRequests");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
@ -894,6 +990,13 @@ namespace Ombi.Store.Migrations
|
||||||
.HasForeignKey("PlexServerContentId");
|
.HasForeignKey("PlexServerContentId");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.AlbumRequest", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RequestedUserId");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest")
|
b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest")
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Repository.Requests
|
||||||
|
{
|
||||||
|
public interface IMusicRequestRepository : IRepository<AlbumRequest>
|
||||||
|
{
|
||||||
|
IQueryable<AlbumRequest> GetAll(string userId);
|
||||||
|
AlbumRequest GetRequest(string foreignAlbumId);
|
||||||
|
Task<AlbumRequest> GetRequestAsync(string foreignAlbumId);
|
||||||
|
IQueryable<AlbumRequest> GetWithUser();
|
||||||
|
IQueryable<AlbumRequest> GetWithUser(string userId);
|
||||||
|
Task Save();
|
||||||
|
Task Update(AlbumRequest request);
|
||||||
|
}
|
||||||
|
}
|
72
src/Ombi.Store/Repository/Requests/MusicRequestRepository.cs
Normal file
72
src/Ombi.Store/Repository/Requests/MusicRequestRepository.cs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Ombi.Store.Context;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Repository.Requests
|
||||||
|
{
|
||||||
|
public class MusicRequestRepository : Repository<AlbumRequest>, IMusicRequestRepository
|
||||||
|
{
|
||||||
|
public MusicRequestRepository(IOmbiContext ctx) : base(ctx)
|
||||||
|
{
|
||||||
|
Db = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IOmbiContext Db { get; }
|
||||||
|
|
||||||
|
public Task<AlbumRequest> GetRequestAsync(string foreignAlbumId)
|
||||||
|
{
|
||||||
|
return Db.AlbumRequests.Where(x => x.ForeignAlbumId == foreignAlbumId)
|
||||||
|
.Include(x => x.RequestedUser)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IQueryable<AlbumRequest> GetAll(string userId)
|
||||||
|
{
|
||||||
|
return GetWithUser().Where(x => x.RequestedUserId == userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlbumRequest GetRequest(string foreignAlbumId)
|
||||||
|
{
|
||||||
|
return Db.AlbumRequests.Where(x => x.ForeignAlbumId == foreignAlbumId)
|
||||||
|
.Include(x => x.RequestedUser)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IQueryable<AlbumRequest> GetWithUser()
|
||||||
|
{
|
||||||
|
return Db.AlbumRequests
|
||||||
|
.Include(x => x.RequestedUser)
|
||||||
|
.ThenInclude(x => x.NotificationUserIds)
|
||||||
|
.AsQueryable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public IQueryable<AlbumRequest> GetWithUser(string userId)
|
||||||
|
{
|
||||||
|
return Db.AlbumRequests
|
||||||
|
.Where(x => x.RequestedUserId == userId)
|
||||||
|
.Include(x => x.RequestedUser)
|
||||||
|
.ThenInclude(x => x.NotificationUserIds)
|
||||||
|
.AsQueryable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Update(AlbumRequest request)
|
||||||
|
{
|
||||||
|
if (Db.Entry(request).State == EntityState.Detached)
|
||||||
|
{
|
||||||
|
Db.AlbumRequests.Attach(request);
|
||||||
|
Db.Update(request);
|
||||||
|
}
|
||||||
|
await Db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Save()
|
||||||
|
{
|
||||||
|
await Db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -94,6 +94,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.SickRage", "Ombi.A
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Notifications", "Ombi.Api.Notifications\Ombi.Api.Notifications.csproj", "{10D1FE9D-9124-42B7-B1E1-CEB99B832618}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Notifications", "Ombi.Api.Notifications\Ombi.Api.Notifications.csproj", "{10D1FE9D-9124-42B7-B1E1-CEB99B832618}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Lidarr", "Ombi.Api.Lidarr\Ombi.Api.Lidarr.csproj", "{4FA21A20-92F4-462C-B929-2C517A88CC56}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -244,6 +246,10 @@ Global
|
||||||
{10D1FE9D-9124-42B7-B1E1-CEB99B832618}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{10D1FE9D-9124-42B7-B1E1-CEB99B832618}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{10D1FE9D-9124-42B7-B1E1-CEB99B832618}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{10D1FE9D-9124-42B7-B1E1-CEB99B832618}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{10D1FE9D-9124-42B7-B1E1-CEB99B832618}.Release|Any CPU.Build.0 = Release|Any CPU
|
{10D1FE9D-9124-42B7-B1E1-CEB99B832618}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4FA21A20-92F4-462C-B929-2C517A88CC56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4FA21A20-92F4-462C-B929-2C517A88CC56}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4FA21A20-92F4-462C-B929-2C517A88CC56}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4FA21A20-92F4-462C-B929-2C517A88CC56}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -279,6 +285,7 @@ Global
|
||||||
{55866DEE-46D1-4AF7-B1A2-62F6190C8EC7} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
{55866DEE-46D1-4AF7-B1A2-62F6190C8EC7} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
{94C9A366-2595-45EA-AABB-8E4A2E90EC5B} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
{94C9A366-2595-45EA-AABB-8E4A2E90EC5B} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
{10D1FE9D-9124-42B7-B1E1-CEB99B832618} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
{10D1FE9D-9124-42B7-B1E1-CEB99B832618} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
|
{4FA21A20-92F4-462C-B929-2C517A88CC56} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869}
|
SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { IIssueCategory, IUser, RequestType } from "./";
|
import { IIssueCategory, IUser, RequestType } from ".";
|
||||||
|
|
||||||
export interface IIssues {
|
export interface IIssues {
|
||||||
id?: number;
|
id?: number;
|
||||||
|
|
9
src/Ombi/ClientApp/app/interfaces/ILidarr.ts
Normal file
9
src/Ombi/ClientApp/app/interfaces/ILidarr.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
export interface ILidarrRootFolder {
|
||||||
|
id: number;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILidarrProfile {
|
||||||
|
name: string;
|
||||||
|
id: number;
|
||||||
|
}
|
|
@ -8,6 +8,11 @@ export interface IRadarrProfile {
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IProfiles {
|
||||||
|
name: string;
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IMinimumAvailability {
|
export interface IMinimumAvailability {
|
||||||
value: string;
|
value: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -20,6 +20,23 @@ export interface IMovieRequests extends IFullBaseRequest {
|
||||||
qualityOverrideTitle: string;
|
qualityOverrideTitle: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IAlbumRequest extends IBaseRequest {
|
||||||
|
foreignAlbumId: string;
|
||||||
|
foreignArtistId: string;
|
||||||
|
disk: string;
|
||||||
|
cover: string;
|
||||||
|
releaseDate: Date;
|
||||||
|
artistName: string;
|
||||||
|
|
||||||
|
subscribed: boolean;
|
||||||
|
showSubscribe: boolean;
|
||||||
|
background: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAlbumRequestModel {
|
||||||
|
foreignAlbumId: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IRequestsViewModel<T> {
|
export interface IRequestsViewModel<T> {
|
||||||
total: number;
|
total: number;
|
||||||
collection: T[];
|
collection: T[];
|
||||||
|
@ -29,6 +46,10 @@ export interface IMovieUpdateModel {
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IAlbumUpdateModel {
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IFullBaseRequest extends IBaseRequest {
|
export interface IFullBaseRequest extends IBaseRequest {
|
||||||
imdbId: string;
|
imdbId: string;
|
||||||
overview: string;
|
overview: string;
|
||||||
|
|
55
src/Ombi/ClientApp/app/interfaces/ISearchMusicResult.ts
Normal file
55
src/Ombi/ClientApp/app/interfaces/ISearchMusicResult.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
export interface ISearchArtistResult {
|
||||||
|
artistName: string;
|
||||||
|
artistType: string;
|
||||||
|
disambiguation: string;
|
||||||
|
forignArtistId: string;
|
||||||
|
|
||||||
|
banner: string;
|
||||||
|
overview: string;
|
||||||
|
poster: string;
|
||||||
|
monitored: boolean;
|
||||||
|
approved: boolean;
|
||||||
|
requested: boolean;
|
||||||
|
requestId: number;
|
||||||
|
available: boolean;
|
||||||
|
links: ILink[];
|
||||||
|
|
||||||
|
subscribed: boolean;
|
||||||
|
showSubscribe: boolean;
|
||||||
|
|
||||||
|
// for the UI
|
||||||
|
requestProcessing: boolean;
|
||||||
|
processed: boolean;
|
||||||
|
background: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILink {
|
||||||
|
url: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISearchAlbumResult {
|
||||||
|
id: number;
|
||||||
|
requestId: number;
|
||||||
|
albumType: string;
|
||||||
|
artistName: string;
|
||||||
|
cover: string;
|
||||||
|
disk: string;
|
||||||
|
foreignAlbumId: string;
|
||||||
|
foreignArtistId: string;
|
||||||
|
monitored: boolean;
|
||||||
|
rating: number;
|
||||||
|
releaseDate: Date;
|
||||||
|
title: string;
|
||||||
|
fullyAvailable: boolean;
|
||||||
|
partiallyAvailable: boolean;
|
||||||
|
requested: boolean;
|
||||||
|
approved: boolean;
|
||||||
|
subscribed: boolean;
|
||||||
|
|
||||||
|
// for the UI
|
||||||
|
showSubscribe: boolean;
|
||||||
|
requestProcessing: boolean;
|
||||||
|
processed: boolean;
|
||||||
|
background: any;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue