mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-19 12:59:39 -07:00
commit
c0e9227e38
226 changed files with 12167 additions and 510 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -243,3 +243,6 @@ _Pvt_Extensions
|
||||||
# CAKE - C# Make
|
# CAKE - C# Make
|
||||||
/Tools/*
|
/Tools/*
|
||||||
*.db-journal
|
*.db-journal
|
||||||
|
|
||||||
|
# Ignore local vscode config
|
||||||
|
*.vscode
|
||||||
|
|
153
CHANGELOG.md
153
CHANGELOG.md
|
@ -1,5 +1,152 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## (unreleased)
|
||||||
|
|
||||||
|
### **New Features**
|
||||||
|
|
||||||
|
- Added the request limits in the ui for music. [Jamie]
|
||||||
|
|
||||||
|
- Added the root folders and qualities per user! [Jamie]
|
||||||
|
|
||||||
|
- Updated all the MS packages. [TidusJar]
|
||||||
|
|
||||||
|
- Update the .net core packages to fix "CVE-2018-8409: ASP.NET Core Denial Of Service Vulnerability" [TidusJar]
|
||||||
|
|
||||||
|
- Change way remainingrequests component is notified. [Kenton Royal]
|
||||||
|
|
||||||
|
- Added the music request limits. [TidusJar]
|
||||||
|
|
||||||
|
- Added the Notification Preferences to the user. [TidusJar]
|
||||||
|
|
||||||
|
- Added the API to add user notification preferences. [TidusJar]
|
||||||
|
|
||||||
|
- Added more logging into the updater. [Jamie]
|
||||||
|
|
||||||
|
- Update CHANGELOG.md. [Jamie]
|
||||||
|
|
||||||
|
### **Fixes**
|
||||||
|
|
||||||
|
- Fixed #2518. [TidusJar]
|
||||||
|
|
||||||
|
- Fixed #2522. [TidusJar]
|
||||||
|
|
||||||
|
- Fixed #2485. [TidusJar]
|
||||||
|
|
||||||
|
- Fixed #2516. [TidusJar]
|
||||||
|
|
||||||
|
- Fix bug in which requested TV wasn't logging for some users. [Kenton Royal]
|
||||||
|
|
||||||
|
- Add to translations. [Kenton Royal]
|
||||||
|
|
||||||
|
- Add html for displaying remaining requests on users page. [Kenton Royal]
|
||||||
|
|
||||||
|
- Add quota fields to user view model. [Kenton Royal]
|
||||||
|
|
||||||
|
- Users can now see the music search tab #2493. [TidusJar]
|
||||||
|
|
||||||
|
- Add href to a tags so that a pointer cursor shows on requests page. [Stephen Panzer]
|
||||||
|
|
||||||
|
- Allow Lidarr to specify if we should search for the album. [TidusJar]
|
||||||
|
|
||||||
|
- Fixed the issue if in Radarr we only want to add and monitor, if the movie already exists we search for it. [TidusJar]
|
||||||
|
|
||||||
|
- Fix bug causing wrong time to be displayed for next request. [Kenton Royal]
|
||||||
|
|
||||||
|
- Bodge fix test to prevent compile error. [Kenton Royal]
|
||||||
|
|
||||||
|
- Fix displaying year in issue dialog. [Stephen Panzer]
|
||||||
|
|
||||||
|
- Add clearfix class. Closes #2486. [Stephen Panzer]
|
||||||
|
|
||||||
|
- Correct path of lidarr component import for unix systems. [Kenton Royal]
|
||||||
|
|
||||||
|
- Refactor code. [Kenton Royal]
|
||||||
|
|
||||||
|
- Fix formatting error. [Kenton Royal]
|
||||||
|
|
||||||
|
- Revert "Revert request.service.ts to version on upstream/develop" [Kenton Royal]
|
||||||
|
|
||||||
|
- Revert request.service.ts to version on upstream/develop. [Kenton Royal]
|
||||||
|
|
||||||
|
- Fix lint errors. [Kenton Royal]
|
||||||
|
|
||||||
|
- Move logic for notifying when reuqest is complete. [Kenton Royal]
|
||||||
|
|
||||||
|
- Remove import. [Kenton Royal]
|
||||||
|
|
||||||
|
- Remove unused module. [Kenton Royal]
|
||||||
|
|
||||||
|
- Refactor code. [Kenton Royal]
|
||||||
|
|
||||||
|
- Add text to translation file. [Kenton Royal]
|
||||||
|
|
||||||
|
- Fix query for fetching requested tv shows. [Kenton Royal]
|
||||||
|
|
||||||
|
- Add vscode to gitignore. [Kenton Royal]
|
||||||
|
|
||||||
|
- Fix lint errors. [Kenton Royal]
|
||||||
|
|
||||||
|
- Remove unused methods from SearchController. [Kenton Royal]
|
||||||
|
|
||||||
|
- Remove local vscode files. [Kenton Royal]
|
||||||
|
|
||||||
|
- Fix bug when submitting requests for multiple episodes accross multiple seasons. [Kenton Royal]
|
||||||
|
|
||||||
|
- Fix bug with TV requests in which requesting a seasion would treat request as single episode. [Kenton Royal]
|
||||||
|
|
||||||
|
- Fix issues with remaining count updating. [Kenton Royal]
|
||||||
|
|
||||||
|
- Trigger update of request limit on new request. [Kenton Royal]
|
||||||
|
|
||||||
|
- Add logic for movie request count. [Kenton Royal]
|
||||||
|
|
||||||
|
- Add logic for retriving request information. [Kenton Royal]
|
||||||
|
|
||||||
|
- Move to seperate component and display for both TV and movies. [Kenton Royal]
|
||||||
|
|
||||||
|
- Add dummy for request counter. [Kenton Royal]
|
||||||
|
|
||||||
|
- Fix scss import for unix systems. [Kenton Royal]
|
||||||
|
|
||||||
|
- Add methods to interface and add model class. [Kenton Royal]
|
||||||
|
|
||||||
|
- !fixed lint. [TidusJar]
|
||||||
|
|
||||||
|
- Fixed #2481. [TidusJar]
|
||||||
|
|
||||||
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Spanish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Portuguese, Brazilian) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Polish) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Norwegian) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Italian) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (German) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (French) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Dutch) [Jamie]
|
||||||
|
|
||||||
|
- New translations en.json (Danish) [Jamie]
|
||||||
|
|
||||||
|
- Fixed #2475. [Jamie]
|
||||||
|
|
||||||
|
- Stript out certain characters when sending a pushover message #2385. [TidusJar]
|
||||||
|
|
||||||
|
- Add default values for Priority and Sound. [David Pooley]
|
||||||
|
|
||||||
|
- Allow for the ability to set Pushover notification sound and priority from within Ombi. [David Pooley]
|
||||||
|
|
||||||
|
- It works now when we request an album when we do not have the artist in Lidarr. Waiting on https://github.com/lidarr/Lidarr/issues/459 to do when we have the artist. [Jamie]
|
||||||
|
|
||||||
|
- Fix non-Windows builds. Fixes #2453. [Joe Groocock]
|
||||||
|
|
||||||
|
|
||||||
## v3.0.3587 (2018-08-19)
|
## v3.0.3587 (2018-08-19)
|
||||||
|
|
||||||
### **New Features**
|
### **New Features**
|
||||||
|
@ -30,6 +177,12 @@
|
||||||
|
|
||||||
### **Fixes**
|
### **Fixes**
|
||||||
|
|
||||||
|
- Now include the release year in the issue title #2381. [TidusJar]
|
||||||
|
|
||||||
|
- Made the OAuth a Popout to work with Org. [Jamie]
|
||||||
|
|
||||||
|
- Fixed #2418. [TidusJar]
|
||||||
|
|
||||||
- #2408 Added the feature to delete comments on issues. [Jamie]
|
- #2408 Added the feature to delete comments on issues. [Jamie]
|
||||||
|
|
||||||
- New translations en.json (Swedish) [Jamie]
|
- New translations en.json (Swedish) [Jamie]
|
||||||
|
|
BIN
music-placeholder.psd
Normal file
BIN
music-placeholder.psd
Normal file
Binary file not shown.
27
src/Ombi.Api.Lidarr/ILidarrApi.cs
Normal file
27
src/Ombi.Api.Lidarr/ILidarrApi.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
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);
|
||||||
|
Task<LidarrStatus> Status(string apiKey, string baseUrl);
|
||||||
|
Task<CommandResult> AlbumSearch(int[] albumIds, string apiKey, string baseUrl);
|
||||||
|
}
|
||||||
|
}
|
170
src/Ombi.Api.Lidarr/LidarrApi.cs
Normal file
170
src/Ombi.Api.Lidarr/LidarrApi.cs
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<LidarrStatus> Status(string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/system/status", baseUrl, HttpMethod.Get);
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<LidarrStatus>(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<CommandResult> AlbumSearch(int[] albumIds, string apiKey, string baseUrl)
|
||||||
|
{
|
||||||
|
var request = new Request($"{ApiVersion}/command/AlbumSearch", baseUrl, HttpMethod.Post);
|
||||||
|
request.AddJsonBody(albumIds);
|
||||||
|
AddHeaders(request, apiKey);
|
||||||
|
return Api.Request<CommandResult>(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; }
|
||||||
|
}
|
||||||
|
}
|
15
src/Ombi.Api.Lidarr/Models/CommandResult.cs
Normal file
15
src/Ombi.Api.Lidarr/Models/CommandResult.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
|
||||||
|
public class CommandResult
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public DateTime startedOn { get; set; }
|
||||||
|
public DateTime stateChangeTime { get; set; }
|
||||||
|
public bool sendUpdatesToClient { get; set; }
|
||||||
|
public string state { get; set; }
|
||||||
|
public int id { 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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
src/Ombi.Api.Lidarr/Models/LidarrStatus.cs
Normal file
31
src/Ombi.Api.Lidarr/Models/LidarrStatus.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Lidarr.Models
|
||||||
|
{
|
||||||
|
public class LidarrStatus
|
||||||
|
{
|
||||||
|
public string version { get; set; }
|
||||||
|
public DateTime buildTime { get; set; }
|
||||||
|
public bool isDebug { get; set; }
|
||||||
|
public bool isProduction { get; set; }
|
||||||
|
public bool isAdmin { get; set; }
|
||||||
|
public bool isUserInteractive { get; set; }
|
||||||
|
public string startupPath { get; set; }
|
||||||
|
public string appData { get; set; }
|
||||||
|
public string osName { get; set; }
|
||||||
|
public string osVersion { get; set; }
|
||||||
|
public bool isMonoRuntime { get; set; }
|
||||||
|
public bool isMono { get; set; }
|
||||||
|
public bool isLinux { get; set; }
|
||||||
|
public bool isOsx { get; set; }
|
||||||
|
public bool isWindows { get; set; }
|
||||||
|
public string mode { get; set; }
|
||||||
|
public string branch { get; set; }
|
||||||
|
public string authentication { get; set; }
|
||||||
|
public string sqliteVersion { get; set; }
|
||||||
|
public int migrationVersion { get; set; }
|
||||||
|
public string urlBase { get; set; }
|
||||||
|
public string runtimeVersion { get; set; }
|
||||||
|
public string runtimeName { 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>
|
|
@ -5,6 +5,6 @@ namespace Ombi.Api.Pushover
|
||||||
{
|
{
|
||||||
public interface IPushoverApi
|
public interface IPushoverApi
|
||||||
{
|
{
|
||||||
Task<PushoverResponse> PushAsync(string accessToken, string message, string userToken);
|
Task<PushoverResponse> PushAsync(string accessToken, string message, string userToken, sbyte priority, string sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,13 +16,13 @@ namespace Ombi.Api.Pushover
|
||||||
private readonly IApi _api;
|
private readonly IApi _api;
|
||||||
private const string PushoverEndpoint = "https://api.pushover.net/1";
|
private const string PushoverEndpoint = "https://api.pushover.net/1";
|
||||||
|
|
||||||
public async Task<PushoverResponse> PushAsync(string accessToken, string message, string userToken)
|
public async Task<PushoverResponse> PushAsync(string accessToken, string message, string userToken, sbyte priority, string sound)
|
||||||
{
|
{
|
||||||
if (message.Contains("'"))
|
if (message.Contains("'"))
|
||||||
{
|
{
|
||||||
message = message.Replace("'", "'");
|
message = message.Replace("'", "'");
|
||||||
}
|
}
|
||||||
var request = new Request($"messages.json?token={accessToken}&user={userToken}&message={WebUtility.HtmlEncode(message)}", PushoverEndpoint, HttpMethod.Post);
|
var request = new Request($"messages.json?token={accessToken}&user={userToken}&priority={priority}&sound={sound}&message={WebUtility.HtmlEncode(message)}", PushoverEndpoint, HttpMethod.Post);
|
||||||
|
|
||||||
var result = await _api.Request<PushoverResponse>(request);
|
var result = await _api.Request<PushoverResponse>(request);
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Moq" Version="4.7.99" />
|
<PackageReference Include="Moq" Version="4.9.0" />
|
||||||
<PackageReference Include="Nunit" Version="3.8.1" />
|
<PackageReference Include="Nunit" Version="3.10.1" />
|
||||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.7.0" />
|
<PackageReference Include="NUnit.ConsoleRunner" Version="3.8.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.8.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.8.0"></packagereference>
|
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.8.0"></packagereference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
|
|
26
src/Ombi.Core.Tests/StringHelperTests.cs
Normal file
26
src/Ombi.Core.Tests/StringHelperTests.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class StringHelperTests
|
||||||
|
{
|
||||||
|
[TestCaseSource(nameof(StripCharsData))]
|
||||||
|
public string StripCharacters(string str, char[] chars)
|
||||||
|
{
|
||||||
|
return str.StripCharacters(chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TestCaseData> StripCharsData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData("this!is^a*string",new []{'!','^','*'}).Returns("thisisastring").SetName("Basic Strip Multipe Chars");
|
||||||
|
yield return new TestCaseData("What is this madness'",new []{'\'','^','*'}).Returns("What is this madness").SetName("Basic Strip Multipe Chars");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
27
src/Ombi.Core/Engine/IMusicRequestEngine.cs
Normal file
27
src/Ombi.Core/Engine/IMusicRequestEngine.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Core.Models;
|
||||||
|
using Ombi.Core.Models.Requests;
|
||||||
|
using Ombi.Core.Models.UI;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
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);
|
||||||
|
Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user = null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,5 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
Task<RequestEngineResult> ApproveMovie(MovieRequests request);
|
Task<RequestEngineResult> ApproveMovie(MovieRequests request);
|
||||||
Task<RequestEngineResult> ApproveMovieById(int requestId);
|
Task<RequestEngineResult> ApproveMovieById(int requestId);
|
||||||
Task<RequestEngineResult> DenyMovieById(int modelId);
|
Task<RequestEngineResult> DenyMovieById(int modelId);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Core.Models;
|
||||||
using Ombi.Core.Models.Requests;
|
using Ombi.Core.Models.Requests;
|
||||||
using Ombi.Core.Models.UI;
|
using Ombi.Core.Models.UI;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
|
@ -22,5 +23,6 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
Task<int> GetTotal();
|
Task<int> GetTotal();
|
||||||
Task UnSubscribeRequest(int requestId, RequestType type);
|
Task UnSubscribeRequest(int requestId, RequestType type);
|
||||||
Task SubscribeToRequest(int requestId, RequestType type);
|
Task SubscribeToRequest(int requestId, RequestType type);
|
||||||
|
Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,6 +19,7 @@ using Ombi.Core.Settings;
|
||||||
using Ombi.Settings.Settings.Models;
|
using Ombi.Settings.Settings.Models;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Core.Models;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
|
@ -336,6 +337,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);
|
||||||
|
@ -483,5 +485,49 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
return new RequestEngineResult {Result = true, Message = $"{movieName} has been successfully added!"};
|
return new RequestEngineResult {Result = true, Message = $"{movieName} has been successfully added!"};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user)
|
||||||
|
{
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
user = await GetUser();
|
||||||
|
|
||||||
|
// If user is still null after attempting to get the logged in user, return null.
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int limit = user.MovieRequestLimit ?? 0;
|
||||||
|
|
||||||
|
if (limit <= 0)
|
||||||
|
{
|
||||||
|
return new RequestQuotaCountModel()
|
||||||
|
{
|
||||||
|
HasLimit = false,
|
||||||
|
Limit = 0,
|
||||||
|
Remaining = 0,
|
||||||
|
NextRequest = DateTime.Now,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
IQueryable<RequestLog> log = _requestLog.GetAll().Where(x => x.UserId == user.Id && x.RequestType == RequestType.Movie);
|
||||||
|
|
||||||
|
int count = limit - await log.CountAsync(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7));
|
||||||
|
|
||||||
|
DateTime oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7))
|
||||||
|
.OrderBy(x => x.RequestDate)
|
||||||
|
.Select(x => x.RequestDate)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
return new RequestQuotaCountModel()
|
||||||
|
{
|
||||||
|
HasLimit = true,
|
||||||
|
Limit = limit,
|
||||||
|
Remaining = count,
|
||||||
|
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
503
src/Ombi.Core/Engine/MusicRequestEngine.cs
Normal file
503
src/Ombi.Core/Engine/MusicRequestEngine.cs
Normal file
|
@ -0,0 +1,503 @@
|
||||||
|
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;
|
||||||
|
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<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user)
|
||||||
|
{
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
user = await GetUser();
|
||||||
|
|
||||||
|
// If user is still null after attempting to get the logged in user, return null.
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int limit = user.MusicRequestLimit ?? 0;
|
||||||
|
|
||||||
|
if (limit <= 0)
|
||||||
|
{
|
||||||
|
return new RequestQuotaCountModel()
|
||||||
|
{
|
||||||
|
HasLimit = false,
|
||||||
|
Limit = 0,
|
||||||
|
Remaining = 0,
|
||||||
|
NextRequest = DateTime.Now,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
IQueryable<RequestLog> log = _requestLog.GetAll().Where(x => x.UserId == user.Id && x.RequestType == RequestType.Album);
|
||||||
|
|
||||||
|
int count = limit - await log.CountAsync(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7));
|
||||||
|
|
||||||
|
DateTime oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7))
|
||||||
|
.OrderBy(x => x.RequestDate)
|
||||||
|
.Select(x => x.RequestDate)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
return new RequestQuotaCountModel()
|
||||||
|
{
|
||||||
|
HasLimit = true,
|
||||||
|
Limit = limit,
|
||||||
|
Remaining = count,
|
||||||
|
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ using Ombi.Core.Settings;
|
||||||
using Ombi.Settings.Settings.Models;
|
using Ombi.Settings.Settings.Models;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Core.Models;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
|
@ -587,6 +588,15 @@ namespace Ombi.Core.Engine
|
||||||
NotificationHelper.NewRequest(model);
|
NotificationHelper.NewRequest(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await _requestLog.Add(new RequestLog
|
||||||
|
{
|
||||||
|
UserId = (await GetUser()).Id,
|
||||||
|
RequestDate = DateTime.UtcNow,
|
||||||
|
RequestId = model.Id,
|
||||||
|
RequestType = RequestType.TvShow,
|
||||||
|
EpisodeCount = model.SeasonRequests.Select(m => m.Episodes.Count).Sum(),
|
||||||
|
});
|
||||||
|
|
||||||
if (model.Approved)
|
if (model.Approved)
|
||||||
{
|
{
|
||||||
// Autosend
|
// Autosend
|
||||||
|
@ -602,15 +612,58 @@ namespace Ombi.Core.Engine
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
await _requestLog.Add(new RequestLog
|
|
||||||
{
|
|
||||||
UserId = (await GetUser()).Id,
|
|
||||||
RequestDate = DateTime.UtcNow,
|
|
||||||
RequestId = model.Id,
|
|
||||||
RequestType = RequestType.TvShow,
|
|
||||||
});
|
|
||||||
|
|
||||||
return new RequestEngineResult { Result = true };
|
return new RequestEngineResult { Result = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user)
|
||||||
|
{
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
user = await GetUser();
|
||||||
|
|
||||||
|
// If user is still null after attempting to get the logged in user, return null.
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int limit = user.EpisodeRequestLimit ?? 0;
|
||||||
|
|
||||||
|
if (limit <= 0)
|
||||||
|
{
|
||||||
|
return new RequestQuotaCountModel()
|
||||||
|
{
|
||||||
|
HasLimit = false,
|
||||||
|
Limit = 0,
|
||||||
|
Remaining = 0,
|
||||||
|
NextRequest = DateTime.Now,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
IQueryable<RequestLog> log = _requestLog.GetAll()
|
||||||
|
.Where(x => x.UserId == user.Id
|
||||||
|
&& x.RequestType == RequestType.TvShow
|
||||||
|
&& x.RequestDate >= DateTime.UtcNow.AddDays(-7));
|
||||||
|
|
||||||
|
// Needed, due to a bug which would cause all episode counts to be 0
|
||||||
|
int zeroEpisodeCount = await log.Where(x => x.EpisodeCount == 0).Select(x => x.EpisodeCount).CountAsync();
|
||||||
|
|
||||||
|
int episodeCount = await log.Where(x => x.EpisodeCount != 0).Select(x => x.EpisodeCount).SumAsync();
|
||||||
|
|
||||||
|
int count = limit - (zeroEpisodeCount + episodeCount);
|
||||||
|
|
||||||
|
DateTime oldestRequestedAt = await log.OrderBy(x => x.RequestDate)
|
||||||
|
.Select(x => x.RequestDate)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
return new RequestQuotaCountModel()
|
||||||
|
{
|
||||||
|
HasLimit = true,
|
||||||
|
Limit = limit,
|
||||||
|
Remaining = count,
|
||||||
|
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -54,7 +54,16 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
if (searchResult != null)
|
if (searchResult != null)
|
||||||
{
|
{
|
||||||
return await ProcessResults(searchResult);
|
var retVal = new List<SearchTvShowViewModel>();
|
||||||
|
foreach (var tvMazeSearch in searchResult)
|
||||||
|
{
|
||||||
|
if (tvMazeSearch.show.externals == null || !(tvMazeSearch.show.externals?.thetvdb.HasValue ?? false))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
retVal.Add(await ProcessResult(tvMazeSearch));
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -145,12 +154,16 @@ namespace Ombi.Core.Engine
|
||||||
var retVal = new List<SearchTvShowViewModel>();
|
var retVal = new List<SearchTvShowViewModel>();
|
||||||
foreach (var tvMazeSearch in items)
|
foreach (var tvMazeSearch in items)
|
||||||
{
|
{
|
||||||
var viewT = Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
retVal.Add(await ProcessResult(tvMazeSearch));
|
||||||
retVal.Add(await ProcessResult(viewT));
|
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<SearchTvShowViewModel> ProcessResult<T>(T tvMazeSearch)
|
||||||
|
{
|
||||||
|
return Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<SearchTvShowViewModel> ProcessResult(SearchTvShowViewModel item)
|
private async Task<SearchTvShowViewModel> ProcessResult(SearchTvShowViewModel item)
|
||||||
{
|
{
|
||||||
item.TheTvDbId = item.Id.ToString();
|
item.TheTvDbId = item.Id.ToString();
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
15
src/Ombi.Core/Models/RequestQuotaCountModel.cs
Normal file
15
src/Ombi.Core/Models/RequestQuotaCountModel.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models
|
||||||
|
{
|
||||||
|
public class RequestQuotaCountModel
|
||||||
|
{
|
||||||
|
public bool HasLimit { get; set; }
|
||||||
|
|
||||||
|
public int Limit { get; set; }
|
||||||
|
|
||||||
|
public int Remaining { get; set; }
|
||||||
|
|
||||||
|
public DateTime NextRequest { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
namespace Ombi.Core.Models.UI
|
namespace Ombi.Core.Models.UI
|
||||||
{
|
{
|
||||||
|
@ -16,6 +17,11 @@ namespace Ombi.Core.Models.UI
|
||||||
public UserType UserType { get; set; }
|
public UserType UserType { get; set; }
|
||||||
public int MovieRequestLimit { get; set; }
|
public int MovieRequestLimit { get; set; }
|
||||||
public int EpisodeRequestLimit { get; set; }
|
public int EpisodeRequestLimit { get; set; }
|
||||||
|
public RequestQuotaCountModel EpisodeRequestQuota { get; set; }
|
||||||
|
public RequestQuotaCountModel MovieRequestQuota { get; set; }
|
||||||
|
public RequestQuotaCountModel MusicRequestQuota { get; set; }
|
||||||
|
public int MusicRequestLimit { get; set; }
|
||||||
|
public UserQualityProfiles UserQualityProfiles { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ClaimCheckboxes
|
public class ClaimCheckboxes
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="3.2.0" />
|
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="3.2.0" />
|
||||||
<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.3" />
|
||||||
<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();
|
||||||
|
@ -81,19 +82,38 @@ namespace Ombi.Core.Rule.Rules.Request
|
||||||
// Get the count of requests to be made
|
// Get the count of requests to be made
|
||||||
foreach (var s in child.SeasonRequests)
|
foreach (var s in child.SeasonRequests)
|
||||||
{
|
{
|
||||||
requestCount = s.Episodes.Count;
|
requestCount += s.Episodes.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tvLogs = requestLog.Where(x => x.RequestType == RequestType.TvShow);
|
var tvLogs = requestLog.Where(x => x.RequestType == RequestType.TvShow);
|
||||||
|
|
||||||
// Count how many requests in the past 7 days
|
// Count how many requests in the past 7 days
|
||||||
var tv = tvLogs.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7));
|
var tv = tvLogs.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7));
|
||||||
var count = await tv.Select(x => x.EpisodeCount).CountAsync();
|
|
||||||
count += requestCount; // Add the amount of requests in
|
// Needed, due to a bug which would cause all episode counts to be 0
|
||||||
|
var zeroEpisodeCount = await tv.Where(x => x.EpisodeCount == 0).Select(x => x.EpisodeCount).CountAsync();
|
||||||
|
|
||||||
|
var episodeCount = await tv.Where(x => x.EpisodeCount != 0).Select(x => x.EpisodeCount).SumAsync();
|
||||||
|
|
||||||
|
var count = requestCount + episodeCount + zeroEpisodeCount; // Add the amount of requests in
|
||||||
if (count > episodeLimit)
|
if (count > episodeLimit)
|
||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ombi.Api.CouchPotato;
|
using Ombi.Api.CouchPotato;
|
||||||
using Ombi.Api.DogNzb.Models;
|
using Ombi.Api.DogNzb.Models;
|
||||||
|
@ -9,6 +10,8 @@ using Ombi.Helpers;
|
||||||
using Ombi.Settings.Settings.Models.External;
|
using Ombi.Settings.Settings.Models.External;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Api.DogNzb;
|
using Ombi.Api.DogNzb;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
namespace Ombi.Core.Senders
|
namespace Ombi.Core.Senders
|
||||||
{
|
{
|
||||||
|
@ -16,7 +19,7 @@ namespace Ombi.Core.Senders
|
||||||
{
|
{
|
||||||
public MovieSender(ISettingsService<RadarrSettings> radarrSettings, IRadarrApi api, ILogger<MovieSender> log,
|
public MovieSender(ISettingsService<RadarrSettings> radarrSettings, IRadarrApi api, ILogger<MovieSender> log,
|
||||||
ISettingsService<DogNzbSettings> dogSettings, IDogNzbApi dogApi, ISettingsService<CouchPotatoSettings> cpSettings,
|
ISettingsService<DogNzbSettings> dogSettings, IDogNzbApi dogApi, ISettingsService<CouchPotatoSettings> cpSettings,
|
||||||
ICouchPotatoApi cpApi)
|
ICouchPotatoApi cpApi, IRepository<UserQualityProfiles> userProfiles)
|
||||||
{
|
{
|
||||||
RadarrSettings = radarrSettings;
|
RadarrSettings = radarrSettings;
|
||||||
RadarrApi = api;
|
RadarrApi = api;
|
||||||
|
@ -25,6 +28,7 @@ namespace Ombi.Core.Senders
|
||||||
DogNzbApi = dogApi;
|
DogNzbApi = dogApi;
|
||||||
CouchPotatoSettings = cpSettings;
|
CouchPotatoSettings = cpSettings;
|
||||||
CouchPotatoApi = cpApi;
|
CouchPotatoApi = cpApi;
|
||||||
|
_userProfiles = userProfiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISettingsService<RadarrSettings> RadarrSettings { get; }
|
private ISettingsService<RadarrSettings> RadarrSettings { get; }
|
||||||
|
@ -34,6 +38,7 @@ namespace Ombi.Core.Senders
|
||||||
private ISettingsService<DogNzbSettings> DogNzbSettings { get; }
|
private ISettingsService<DogNzbSettings> DogNzbSettings { get; }
|
||||||
private ISettingsService<CouchPotatoSettings> CouchPotatoSettings { get; }
|
private ISettingsService<CouchPotatoSettings> CouchPotatoSettings { get; }
|
||||||
private ICouchPotatoApi CouchPotatoApi { get; }
|
private ICouchPotatoApi CouchPotatoApi { get; }
|
||||||
|
private readonly IRepository<UserQualityProfiles> _userProfiles;
|
||||||
|
|
||||||
public async Task<SenderResult> Send(MovieRequests model)
|
public async Task<SenderResult> Send(MovieRequests model)
|
||||||
{
|
{
|
||||||
|
@ -88,13 +93,33 @@ namespace Ombi.Core.Senders
|
||||||
|
|
||||||
private async Task<SenderResult> SendToRadarr(MovieRequests model, RadarrSettings settings)
|
private async Task<SenderResult> SendToRadarr(MovieRequests model, RadarrSettings settings)
|
||||||
{
|
{
|
||||||
|
|
||||||
var qualityToUse = int.Parse(settings.DefaultQualityProfile);
|
var qualityToUse = int.Parse(settings.DefaultQualityProfile);
|
||||||
|
|
||||||
|
var rootFolderPath = settings.DefaultRootPath;
|
||||||
|
|
||||||
|
var profiles = await _userProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == model.RequestedUserId);
|
||||||
|
if (profiles != null)
|
||||||
|
{
|
||||||
|
if (profiles.SonarrRootPathAnime > 0)
|
||||||
|
{
|
||||||
|
rootFolderPath = await RadarrRootPath(profiles.SonarrRootPathAnime, settings);
|
||||||
|
}
|
||||||
|
if (profiles.SonarrQualityProfileAnime > 0)
|
||||||
|
{
|
||||||
|
qualityToUse = profiles.SonarrQualityProfileAnime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overrides on the request take priority
|
||||||
if (model.QualityOverride > 0)
|
if (model.QualityOverride > 0)
|
||||||
{
|
{
|
||||||
qualityToUse = model.QualityOverride;
|
qualityToUse = model.QualityOverride;
|
||||||
}
|
}
|
||||||
|
if (model.RootPathOverride > 0)
|
||||||
var rootFolderPath = model.RootPathOverride <= 0 ? settings.DefaultRootPath : await RadarrRootPath(model.RootPathOverride, settings);
|
{
|
||||||
|
rootFolderPath = await RadarrRootPath(model.RootPathOverride, settings);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the movie already exists? Since it could be unmonitored
|
// Check if the movie already exists? Since it could be unmonitored
|
||||||
var movies = await RadarrApi.GetMovies(settings.ApiKey, settings.FullUri);
|
var movies = await RadarrApi.GetMovies(settings.ApiKey, settings.FullUri);
|
||||||
|
@ -123,7 +148,10 @@ namespace Ombi.Core.Senders
|
||||||
existingMovie.monitored = true;
|
existingMovie.monitored = true;
|
||||||
await RadarrApi.UpdateMovie(existingMovie, settings.ApiKey, settings.FullUri);
|
await RadarrApi.UpdateMovie(existingMovie, settings.ApiKey, settings.FullUri);
|
||||||
// Search for it
|
// Search for it
|
||||||
|
if (!settings.AddOnly)
|
||||||
|
{
|
||||||
await RadarrApi.MovieSearch(new[] {existingMovie.id}, settings.ApiKey, settings.FullUri);
|
await RadarrApi.MovieSearch(new[] {existingMovie.id}, settings.ApiKey, settings.FullUri);
|
||||||
|
}
|
||||||
|
|
||||||
return new SenderResult { Success = true, Sent = true };
|
return new SenderResult { Success = true, Sent = true };
|
||||||
}
|
}
|
||||||
|
|
130
src/Ombi.Core/Senders/MusicSender.cs
Normal file
130
src/Ombi.Core/Senders/MusicSender.cs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
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 (!settings.AddOnly)
|
||||||
|
{
|
||||||
|
await _lidarrApi.AlbumSearch(new[] {result.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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ombi.Api.DogNzb;
|
using Ombi.Api.DogNzb;
|
||||||
using Ombi.Api.DogNzb.Models;
|
using Ombi.Api.DogNzb.Models;
|
||||||
|
@ -12,7 +13,9 @@ using Ombi.Api.Sonarr.Models;
|
||||||
using Ombi.Core.Settings;
|
using Ombi.Core.Settings;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Settings.Settings.Models.External;
|
using Ombi.Settings.Settings.Models.External;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
namespace Ombi.Core.Senders
|
namespace Ombi.Core.Senders
|
||||||
{
|
{
|
||||||
|
@ -20,7 +23,7 @@ namespace Ombi.Core.Senders
|
||||||
{
|
{
|
||||||
public TvSender(ISonarrApi sonarrApi, ILogger<TvSender> log, ISettingsService<SonarrSettings> sonarrSettings,
|
public TvSender(ISonarrApi sonarrApi, ILogger<TvSender> log, ISettingsService<SonarrSettings> sonarrSettings,
|
||||||
ISettingsService<DogNzbSettings> dog, IDogNzbApi dogApi, ISettingsService<SickRageSettings> srSettings,
|
ISettingsService<DogNzbSettings> dog, IDogNzbApi dogApi, ISettingsService<SickRageSettings> srSettings,
|
||||||
ISickRageApi srApi)
|
ISickRageApi srApi, IRepository<UserQualityProfiles> userProfiles)
|
||||||
{
|
{
|
||||||
SonarrApi = sonarrApi;
|
SonarrApi = sonarrApi;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
@ -29,6 +32,7 @@ namespace Ombi.Core.Senders
|
||||||
DogNzbApi = dogApi;
|
DogNzbApi = dogApi;
|
||||||
SickRageSettings = srSettings;
|
SickRageSettings = srSettings;
|
||||||
SickRageApi = srApi;
|
SickRageApi = srApi;
|
||||||
|
UserQualityProfiles = userProfiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISonarrApi SonarrApi { get; }
|
private ISonarrApi SonarrApi { get; }
|
||||||
|
@ -38,6 +42,7 @@ namespace Ombi.Core.Senders
|
||||||
private ISettingsService<SonarrSettings> SonarrSettings { get; }
|
private ISettingsService<SonarrSettings> SonarrSettings { get; }
|
||||||
private ISettingsService<DogNzbSettings> DogNzbSettings { get; }
|
private ISettingsService<DogNzbSettings> DogNzbSettings { get; }
|
||||||
private ISettingsService<SickRageSettings> SickRageSettings { get; }
|
private ISettingsService<SickRageSettings> SickRageSettings { get; }
|
||||||
|
private IRepository<UserQualityProfiles> UserQualityProfiles { get; }
|
||||||
|
|
||||||
public async Task<SenderResult> Send(ChildRequests model)
|
public async Task<SenderResult> Send(ChildRequests model)
|
||||||
{
|
{
|
||||||
|
@ -122,13 +127,25 @@ namespace Ombi.Core.Senders
|
||||||
string rootFolderPath;
|
string rootFolderPath;
|
||||||
string seriesType;
|
string seriesType;
|
||||||
|
|
||||||
|
var profiles = await UserQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == model.RequestedUserId);
|
||||||
|
|
||||||
if (model.SeriesType == SeriesType.Anime)
|
if (model.SeriesType == SeriesType.Anime)
|
||||||
{
|
{
|
||||||
// Get the root path from the rootfolder selected.
|
// Get the root path from the rootfolder selected.
|
||||||
// For some reason, if we haven't got one use the first root folder in Sonarr
|
// For some reason, if we haven't got one use the first root folder in Sonarr
|
||||||
// TODO make this overrideable via the UI
|
|
||||||
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPathAnime), s);
|
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPathAnime), s);
|
||||||
int.TryParse(s.QualityProfileAnime, out qualityToUse);
|
int.TryParse(s.QualityProfileAnime, out qualityToUse);
|
||||||
|
if (profiles != null)
|
||||||
|
{
|
||||||
|
if (profiles.SonarrRootPathAnime > 0)
|
||||||
|
{
|
||||||
|
rootFolderPath = await GetSonarrRootPath(profiles.SonarrRootPathAnime, s);
|
||||||
|
}
|
||||||
|
if (profiles.SonarrQualityProfileAnime > 0)
|
||||||
|
{
|
||||||
|
qualityToUse = profiles.SonarrQualityProfileAnime;
|
||||||
|
}
|
||||||
|
}
|
||||||
seriesType = "anime";
|
seriesType = "anime";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -137,11 +154,22 @@ namespace Ombi.Core.Senders
|
||||||
int.TryParse(s.QualityProfile, out qualityToUse);
|
int.TryParse(s.QualityProfile, out qualityToUse);
|
||||||
// Get the root path from the rootfolder selected.
|
// Get the root path from the rootfolder selected.
|
||||||
// For some reason, if we haven't got one use the first root folder in Sonarr
|
// For some reason, if we haven't got one use the first root folder in Sonarr
|
||||||
// TODO make this overrideable via the UI
|
|
||||||
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s);
|
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s);
|
||||||
|
if (profiles != null)
|
||||||
|
{
|
||||||
|
if (profiles.SonarrRootPath > 0)
|
||||||
|
{
|
||||||
|
rootFolderPath = await GetSonarrRootPath(profiles.SonarrRootPath, s);
|
||||||
|
}
|
||||||
|
if (profiles.SonarrQualityProfile > 0)
|
||||||
|
{
|
||||||
|
qualityToUse = profiles.SonarrQualityProfile;
|
||||||
|
}
|
||||||
|
}
|
||||||
seriesType = "standard";
|
seriesType = "standard";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overrides on the request take priority
|
||||||
if (model.ParentRequest.QualityOverride.HasValue)
|
if (model.ParentRequest.QualityOverride.HasValue)
|
||||||
{
|
{
|
||||||
qualityToUse = model.ParentRequest.QualityOverride.Value;
|
qualityToUse = model.ParentRequest.QualityOverride.Value;
|
||||||
|
|
|
@ -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>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.1.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.1.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="2.1.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="2.1.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.1.1" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="EasyCrypto" Version="3.3.2" />
|
<PackageReference Include="EasyCrypto" Version="3.3.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.1.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
<PackageReference Include="Nito.AsyncEx" Version="5.0.0-pre-05" />
|
<PackageReference Include="Nito.AsyncEx" Version="5.0.0-pre-05" />
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,5 +75,14 @@ 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)
|
||||||
|
{
|
||||||
|
return string.Concat(str.Where(c => !chars.Contains(c)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,8 +20,9 @@ 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)
|
IRepository<UserNotificationPreferences> userPref)
|
||||||
|
: base(sn, r, m, t, s, log, sub, music, userPref)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
@ -130,12 +131,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,8 @@ 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,
|
||||||
|
IRepository<UserNotificationPreferences> userPref) : base(settings, r, m, t, c, log, sub, music, userPref)
|
||||||
{
|
{
|
||||||
EmailProvider = prov;
|
EmailProvider = prov;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -21,7 +21,8 @@ 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,
|
||||||
|
IRepository<UserNotificationPreferences> userPref) : base(sn, r, m, t, s, log, sub, music, userPref)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -22,7 +22,8 @@ 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,
|
||||||
|
IRepository<UserNotificationPreferences> userPref) : base(sn, r, m, t, s, log, sub, music, userPref)
|
||||||
{
|
{
|
||||||
_api = api;
|
_api = api;
|
||||||
_logger = log;
|
_logger = log;
|
||||||
|
|
|
@ -17,7 +17,8 @@ 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,
|
||||||
|
IRepository<UserNotificationPreferences> userPref) : base(sn, r, m, t, s, log, sub, music, userPref)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -18,7 +18,8 @@ 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,
|
||||||
|
IRepository<UserNotificationPreferences> userPref) : base(sn, r, m, t, s, log, sub, music, userPref)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
@ -177,7 +178,8 @@ namespace Ombi.Notifications.Agents
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Api.PushAsync(settings.AccessToken, model.Message, settings.UserToken);
|
//&+' < >
|
||||||
|
await Api.PushAsync(settings.AccessToken, model.Message.StripCharacters('&','+','<','>'), settings.UserToken, settings.Priority, settings.Sound);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,7 +18,8 @@ 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,
|
||||||
|
IRepository<UserNotificationPreferences> userPref) : base(sn, r, m, t, s, log, sub, music, userPref)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -19,7 +19,8 @@ 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,
|
||||||
|
IRepository<UserNotificationPreferences> userPref) : base(sn, r, m, t,s,log, sub, music, userPref)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
|
|
@ -19,7 +19,8 @@ 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,
|
||||||
|
IRepository<UserNotificationPreferences> notificationUserPreferences)
|
||||||
{
|
{
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
TemplateRepository = templateRepo;
|
TemplateRepository = templateRepo;
|
||||||
|
@ -30,19 +31,24 @@ namespace Ombi.Notifications.Interfaces
|
||||||
CustomizationSettings.ClearCache();
|
CustomizationSettings.ClearCache();
|
||||||
RequestSubscription = sub;
|
RequestSubscription = sub;
|
||||||
_log = log;
|
_log = log;
|
||||||
|
AlbumRepository = album;
|
||||||
|
UserNotificationPreferences = notificationUserPreferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
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; }
|
||||||
|
protected IRepository<UserNotificationPreferences> UserNotificationPreferences { get; set; }
|
||||||
private ISettingsService<CustomizationSettings> CustomizationSettings { get; }
|
private ISettingsService<CustomizationSettings> CustomizationSettings { get; }
|
||||||
private readonly ILogger<BaseNotification<T>> _log;
|
private readonly ILogger<BaseNotification<T>> _log;
|
||||||
|
|
||||||
|
|
||||||
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 +136,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()
|
||||||
|
@ -160,7 +170,7 @@ namespace Ombi.Notifications.Interfaces
|
||||||
{
|
{
|
||||||
return new NotificationMessageContent { Disabled = true };
|
return new NotificationMessageContent { Disabled = true };
|
||||||
}
|
}
|
||||||
var parsed = Parse(model, template);
|
var parsed = Parse(model, template, agent);
|
||||||
|
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
@ -171,20 +181,32 @@ namespace Ombi.Notifications.Interfaces
|
||||||
return subs.Select(x => x.User);
|
return subs.Select(x => x.User);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NotificationMessageContent Parse(NotificationOptions model, NotificationTemplates template)
|
protected UserNotificationPreferences GetUserPreference(string userId, NotificationAgent agent)
|
||||||
|
{
|
||||||
|
return UserNotificationPreferences.GetAll()
|
||||||
|
.FirstOrDefault(x => x.Enabled && x.Agent == agent && x.UserId == userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NotificationMessageContent Parse(NotificationOptions model, NotificationTemplates template, NotificationAgent agent)
|
||||||
{
|
{
|
||||||
var resolver = new NotificationMessageResolver();
|
var resolver = new NotificationMessageResolver();
|
||||||
var curlys = new NotificationMessageCurlys();
|
var curlys = new NotificationMessageCurlys();
|
||||||
|
var preference = GetUserPreference(model.UserId, agent);
|
||||||
if (model.RequestType == RequestType.Movie)
|
if (model.RequestType == RequestType.Movie)
|
||||||
{
|
{
|
||||||
_log.LogDebug("Notification options: {@model}, Req: {@MovieRequest}, Settings: {@Customization}", model, MovieRequest, Customization);
|
_log.LogDebug("Notification options: {@model}, Req: {@MovieRequest}, Settings: {@Customization}", model, MovieRequest, Customization);
|
||||||
|
|
||||||
curlys.Setup(model, MovieRequest, Customization);
|
curlys.Setup(model, MovieRequest, Customization, preference);
|
||||||
}
|
}
|
||||||
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, preference);
|
||||||
|
}
|
||||||
|
else if (model.RequestType == RequestType.Album)
|
||||||
|
{
|
||||||
|
_log.LogDebug("Notification options: {@model}, Req: {@AlbumRequest}, Settings: {@Customization}", model, AlbumRequest, Customization);
|
||||||
|
curlys.Setup(model, AlbumRequest, Customization, preference);
|
||||||
}
|
}
|
||||||
var parsed = resolver.ParseMessage(template, curlys);
|
var parsed = resolver.ParseMessage(template, curlys);
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,10 @@ namespace Ombi.Notifications
|
||||||
{
|
{
|
||||||
public class NotificationMessageCurlys
|
public class NotificationMessageCurlys
|
||||||
{
|
{
|
||||||
public void Setup(NotificationOptions opts, FullBaseRequest req, CustomizationSettings s)
|
public void Setup(NotificationOptions opts, FullBaseRequest req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||||
{
|
{
|
||||||
LoadIssues(opts);
|
LoadIssues(opts);
|
||||||
|
UserPreference = pref.Enabled ? pref.Value : string.Empty;
|
||||||
string title;
|
string title;
|
||||||
if (req == null)
|
if (req == null)
|
||||||
{
|
{
|
||||||
|
@ -58,6 +59,41 @@ namespace Ombi.Notifications
|
||||||
AdditionalInformation = opts?.AdditionalInformation ?? string.Empty;
|
AdditionalInformation = opts?.AdditionalInformation ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Setup(NotificationOptions opts, AlbumRequest req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||||
|
{
|
||||||
|
LoadIssues(opts);
|
||||||
|
UserPreference = pref.Enabled ? pref.Value : string.Empty;
|
||||||
|
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;
|
||||||
|
@ -67,9 +103,10 @@ namespace Ombi.Notifications
|
||||||
Alias = username.Alias.HasValue() ? username.Alias : username.UserName;
|
Alias = username.Alias.HasValue() ? username.Alias : username.UserName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s)
|
public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||||
{
|
{
|
||||||
LoadIssues(opts);
|
LoadIssues(opts);
|
||||||
|
UserPreference = pref.Enabled ? pref.Value : string.Empty;
|
||||||
string title;
|
string title;
|
||||||
if (req == null)
|
if (req == null)
|
||||||
{
|
{
|
||||||
|
@ -187,6 +224,7 @@ namespace Ombi.Notifications
|
||||||
public string IssueStatus { get; set; }
|
public string IssueStatus { get; set; }
|
||||||
public string IssueSubject { get; set; }
|
public string IssueSubject { get; set; }
|
||||||
public string NewIssueComment { get; set; }
|
public string NewIssueComment { get; set; }
|
||||||
|
public string UserPreference { get; set; }
|
||||||
|
|
||||||
// System Defined
|
// System Defined
|
||||||
private string LongDate => DateTime.Now.ToString("D");
|
private string LongDate => DateTime.Now.ToString("D");
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace Ombi.Schedule.Tests
|
||||||
var emailSettings = new Mock<ISettingsService<EmailNotificationSettings>>();
|
var emailSettings = new Mock<ISettingsService<EmailNotificationSettings>>();
|
||||||
var customziation = new Mock<ISettingsService<CustomizationSettings>>();
|
var customziation = new Mock<ISettingsService<CustomizationSettings>>();
|
||||||
var newsletterSettings = new Mock<ISettingsService<NewsletterSettings>>();
|
var newsletterSettings = new Mock<ISettingsService<NewsletterSettings>>();
|
||||||
var newsletter = new NewsletterJob(null, null, null, null, null, null, customziation.Object, emailSettings.Object, null, null, newsletterSettings.Object, null);
|
var newsletter = new NewsletterJob(null, null, null, null, null, null, customziation.Object, emailSettings.Object, null, null, newsletterSettings.Object, null, null, null, null);
|
||||||
|
|
||||||
var ep = new List<int>();
|
var ep = new List<int>();
|
||||||
foreach (var i in episodes)
|
foreach (var i in episodes)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.1.2" />
|
<PackageReference Include="Microsoft.AspNetCore" Version="2.1.3" />
|
||||||
<PackageReference Include="Moq" Version="4.7.99" />
|
<PackageReference Include="Moq" Version="4.7.99" />
|
||||||
<PackageReference Include="Nunit" Version="3.10.1" />
|
<PackageReference Include="Nunit" Version="3.10.1" />
|
||||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.8.0" />
|
<PackageReference Include="NUnit.ConsoleRunner" Version="3.8.0" />
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
16
src/Ombi.Settings/Settings/Models/External/LidarrSettings.cs
vendored
Normal file
16
src/Ombi.Settings/Settings/Models/External/LidarrSettings.cs
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
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; }
|
||||||
|
public bool AddOnly { 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>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,5 +8,7 @@ namespace Ombi.Settings.Settings.Models.Notifications
|
||||||
public bool Enabled { get; set; }
|
public bool Enabled { get; set; }
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
public string UserToken { get; set; }
|
public string UserToken { get; set; }
|
||||||
|
public sbyte Priority { get; set; } = 0;
|
||||||
|
public string Sound { get; set; } = "pushover";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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,11 +45,14 @@ 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; }
|
||||||
public DbSet<RequestSubscription> RequestSubscription { get; set; }
|
public DbSet<RequestSubscription> RequestSubscription { get; set; }
|
||||||
|
public DbSet<UserNotificationPreferences> UserNotificationPreferences { get; set; }
|
||||||
|
public DbSet<UserQualityProfiles> UserQualityProfileses { get; set; }
|
||||||
public DbSet<ApplicationConfiguration> ApplicationConfigurations { get; set; }
|
public DbSet<ApplicationConfiguration> ApplicationConfigurations { get; set; }
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
@ -117,8 +121,8 @@ namespace Ombi.Store.Context
|
||||||
Database.ExecuteSqlCommand("VACUUM;");
|
Database.ExecuteSqlCommand("VACUUM;");
|
||||||
|
|
||||||
// Make sure we have the roles
|
// Make sure we have the roles
|
||||||
var roles = Roles.Where(x => x.Name == OmbiRoles.ReceivesNewsletter);
|
var newsletterRole = Roles.Where(x => x.Name == OmbiRoles.ReceivesNewsletter);
|
||||||
if (!roles.Any())
|
if (!newsletterRole.Any())
|
||||||
{
|
{
|
||||||
Roles.Add(new IdentityRole(OmbiRoles.ReceivesNewsletter)
|
Roles.Add(new IdentityRole(OmbiRoles.ReceivesNewsletter)
|
||||||
{
|
{
|
||||||
|
@ -126,6 +130,19 @@ namespace Ombi.Store.Context
|
||||||
});
|
});
|
||||||
SaveChanges();
|
SaveChanges();
|
||||||
}
|
}
|
||||||
|
var requestMusicRole = Roles.Where(x => x.Name == OmbiRoles.RequestMusic);
|
||||||
|
if (!requestMusicRole.Any())
|
||||||
|
{
|
||||||
|
Roles.Add(new IdentityRole(OmbiRoles.RequestMusic)
|
||||||
|
{
|
||||||
|
NormalizedName = OmbiRoles.RequestMusic.ToUpper()
|
||||||
|
});
|
||||||
|
Roles.Add(new IdentityRole(OmbiRoles.AutoApproveMusic)
|
||||||
|
{
|
||||||
|
NormalizedName = OmbiRoles.AutoApproveMusic.ToUpper()
|
||||||
|
});
|
||||||
|
SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure we have the API User
|
// Make sure we have the API User
|
||||||
var apiUserExists = Users.Any(x => x.UserName.Equals("Api", StringComparison.CurrentCultureIgnoreCase));
|
var apiUserExists = Users.Any(x => x.UserName.Equals("Api", StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
|
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;
|
||||||
|
}
|
||||||
|
}
|
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