mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-16 02:02:55 -07:00
Merge branch 'feature/v4' of https://github.com/tidusjar/Ombi into feature/v4
This commit is contained in:
commit
ec674d5682
107 changed files with 1308 additions and 327 deletions
|
@ -9,6 +9,15 @@ ____
|
|||
[](https://patreon.com/tidusjar/Ombi)
|
||||
[](https://paypal.me/PlexRequestsNet)
|
||||
|
||||
___
|
||||
|
||||
[](https://twitter.com/intent/follow?screen_name=tidusjar)
|
||||
|
||||
Follow me developing Ombi!
|
||||
|
||||
[](https://www.twitch.tv/tidusjar)
|
||||
|
||||
|
||||
___
|
||||
<a href='https://play.google.com/store/apps/details?id=com.tidusjar.Ombi&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img width="150" alt='Get it on Google Play' src='https://play.google.com/intl/en_gb/badges/images/generic/en_badge_web_generic.png'/></a>
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ build_script:
|
|||
skip_commits:
|
||||
files:
|
||||
- '**/*.md'
|
||||
|
||||
|
||||
after_build:
|
||||
- ps: |
|
||||
$deployBranches =
|
||||
|
@ -52,8 +52,8 @@ after_build:
|
|||
If(($env:APPVEYOR_REPO_BRANCH -in $deployBranches -Or $env:APPVEYOR_REPO_COMMIT_MESSAGE -Match '!deploy') -And $env:APPVEYOR_REPO_COMMIT_MESSAGE -NotMatch '!build')
|
||||
{
|
||||
Write-Output "Deploying!"
|
||||
Get-ChildItem .\**\*.zip | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
Get-ChildItem .\**\*.gz | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
Get-ChildItem -Recurse .\*.zip | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
Get-ChildItem -Recurse .\*.gz | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
}
|
||||
Else
|
||||
{
|
||||
|
|
|
@ -23,5 +23,6 @@ namespace Ombi.Api.Lidarr
|
|||
Task<List<LanguageProfiles>> GetLanguageProfile(string apiKey, string baseUrl);
|
||||
Task<LidarrStatus> Status(string apiKey, string baseUrl);
|
||||
Task<CommandResult> AlbumSearch(int[] albumIds, string apiKey, string baseUrl);
|
||||
Task<AlbumResponse> AlbumInformation(string albumId, string apiKey, string baseUrl);
|
||||
}
|
||||
}
|
|
@ -105,6 +105,32 @@ namespace Ombi.Api.Lidarr
|
|||
return Api.Request<List<AlbumResponse>>(request);
|
||||
}
|
||||
|
||||
public async Task<AlbumResponse> AlbumInformation(string albumId, string apiKey, string baseUrl)
|
||||
{
|
||||
var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get);
|
||||
request.AddQueryString("foreignAlbumId", albumId);
|
||||
AddHeaders(request, apiKey);
|
||||
var albums = await Api.Request<List<AlbumResponse>>(request);
|
||||
return albums.Where(x => x.foreignAlbumId.Equals(albumId, StringComparison.InvariantCultureIgnoreCase))
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// THIS ONLY SUPPORTS ALBUMS THAT THE ARTIST IS IN LIDARR
|
||||
/// </summary>
|
||||
/// <param name="albumId"></param>
|
||||
/// <param name="apiKey"></param>
|
||||
/// <param name="baseUrl"></param>
|
||||
/// <returns></returns>
|
||||
public Task<List<LidarrTrack>> GetTracksForAlbum(int albumId, string apiKey, string baseUrl)
|
||||
{
|
||||
var request = new Request($"{ApiVersion}/album", baseUrl, HttpMethod.Get);
|
||||
request.AddQueryString("albumId", albumId.ToString());
|
||||
AddHeaders(request, apiKey);
|
||||
return Api.Request<List<LidarrTrack>>(request);
|
||||
}
|
||||
|
||||
public Task<ArtistResult> AddArtist(ArtistAdd artist, string apiKey, string baseUrl)
|
||||
{
|
||||
var request = new Request($"{ApiVersion}/artist", baseUrl, HttpMethod.Post);
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Api.Lidarr.Models
|
||||
{
|
||||
public class AlbumLookup
|
||||
{
|
||||
public string title { get; set; }
|
||||
public string status { get; set; }
|
||||
public string artistType { get; set; }
|
||||
public string disambiguation { get; set; }
|
||||
public List<LidarrLinks> links { get; set; }
|
||||
public int artistId { get; set; }
|
||||
public string foreignAlbumId { get; set; }
|
||||
public bool monitored { get; set; }
|
||||
|
|
12
src/Ombi.Api.Lidarr/Models/LidarrLinks.cs
Normal file
12
src/Ombi.Api.Lidarr/Models/LidarrLinks.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ombi.Api.Lidarr.Models
|
||||
{
|
||||
public class LidarrLinks
|
||||
{
|
||||
public string url { get; set; }
|
||||
public string name { get; set; }
|
||||
}
|
||||
}
|
8
src/Ombi.Api.Lidarr/Models/LidarrRatings.cs
Normal file
8
src/Ombi.Api.Lidarr/Models/LidarrRatings.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ombi.Api.Lidarr.Models
|
||||
{
|
||||
public class LidarrRatings
|
||||
{
|
||||
public int votes { get; set; }
|
||||
public decimal value { get; set; }
|
||||
}
|
||||
}
|
22
src/Ombi.Api.Lidarr/Models/LidarrTrack.cs
Normal file
22
src/Ombi.Api.Lidarr/Models/LidarrTrack.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ombi.Api.Lidarr.Models
|
||||
{
|
||||
public class LidarrTrack
|
||||
{
|
||||
public int artistId { get; set; }
|
||||
public int trackFileId { get; set; }
|
||||
public int albumId { get; set; }
|
||||
public bool _explicit { get; set; }
|
||||
public int absoluteTrackNumber { get; set; }
|
||||
public string trackNumber { get; set; }
|
||||
public string title { get; set; }
|
||||
public int duration { get; set; }
|
||||
public int mediumNumber { get; set; }
|
||||
public bool hasFile { get; set; }
|
||||
public bool monitored { get; set; }
|
||||
public int id { get; set; }
|
||||
}
|
||||
}
|
|
@ -12,5 +12,6 @@ namespace Ombi.Core.Engine
|
|||
Task<IEnumerable<SearchAlbumViewModel>> GetArtistAlbums(string foreignArtistId);
|
||||
Task<IEnumerable<SearchAlbumViewModel>> SearchAlbum(string search);
|
||||
Task<IEnumerable<SearchArtistViewModel>> SearchArtist(string search);
|
||||
Task<SearchAlbumViewModel> GetAlbumInformation(string foreignAlbumId);
|
||||
}
|
||||
}
|
|
@ -60,6 +60,18 @@ namespace Ombi.Core.Engine
|
|||
return vm;
|
||||
}
|
||||
|
||||
public async Task<SearchAlbumViewModel> GetAlbumInformation(string foreignAlbumId)
|
||||
{
|
||||
var settings = await GetSettings();
|
||||
var result = await _lidarrApi.AlbumInformation(foreignAlbumId, settings.ApiKey, settings.FullUri);
|
||||
|
||||
|
||||
var vm = await MapIntoAlbumVm(result, settings);
|
||||
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the specified artist
|
||||
/// </summary>
|
||||
|
@ -143,6 +155,48 @@ namespace Ombi.Core.Engine
|
|||
return vm;
|
||||
}
|
||||
|
||||
|
||||
// TODO
|
||||
private async Task<SearchAlbumViewModel> MapIntoAlbumVm(AlbumResponse 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?.Replace("http", "https"),
|
||||
Genres = a.genres
|
||||
};
|
||||
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.artistId?.foreignArtistId;
|
||||
//vm.ArtistName = a.artist?.artistName;
|
||||
}
|
||||
|
||||
vm.Cover = a.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url?.Replace("http", "https");
|
||||
if (vm.Cover.IsNullOrEmpty())
|
||||
{
|
||||
//vm.Cover = a.remoteCover;
|
||||
}
|
||||
|
||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum);
|
||||
|
||||
await RunSearchRules(vm);
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
||||
private async Task<SearchAlbumViewModel> MapIntoAlbumVm(AlbumLookup a, LidarrSettings settings)
|
||||
{
|
||||
var vm = new SearchAlbumViewModel
|
||||
|
@ -152,7 +206,8 @@ namespace Ombi.Core.Engine
|
|||
Rating = a.ratings?.value ?? 0m,
|
||||
ReleaseDate = a.releaseDate,
|
||||
Title = a.title,
|
||||
Disk = a.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url
|
||||
Disk = a.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url?.Replace("http", "https"),
|
||||
Genres = a.genres
|
||||
};
|
||||
if (a.artistId > 0)
|
||||
{
|
||||
|
@ -169,7 +224,7 @@ namespace Ombi.Core.Engine
|
|||
vm.ArtistName = a.artist?.artistName;
|
||||
}
|
||||
|
||||
vm.Cover = a.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url;
|
||||
vm.Cover = a.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url?.Replace("http", "https");
|
||||
if (vm.Cover.IsNullOrEmpty())
|
||||
{
|
||||
vm.Cover = a.remoteCover;
|
||||
|
|
|
@ -16,8 +16,13 @@ namespace Ombi.Core.Models.Search
|
|||
public string Cover { get; set; }
|
||||
public string Disk { get; set; }
|
||||
public decimal PercentOfTracks { get; set; }
|
||||
public object[] Genres { get; set; }
|
||||
public override RequestType Type => RequestType.Album;
|
||||
public bool PartiallyAvailable => PercentOfTracks != 100 && PercentOfTracks > 0;
|
||||
public bool FullyAvailable => PercentOfTracks == 100;
|
||||
|
||||
|
||||
// Below is from the INFO call NEED A SEPERATE VM FOR THIS IN V4 TODO
|
||||
// TODO ADD TRACK COUNT
|
||||
}
|
||||
}
|
|
@ -36,4 +36,10 @@
|
|||
<ProjectReference Include="..\Ombi.TheMovieDbApi\Ombi.Api.TheMovieDb.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AspNetCore.SignalR.Core">
|
||||
<HintPath>..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.signalr.core\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Core.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EnsureThat;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Lidarr;
|
||||
using Ombi.Api.Lidarr.Models;
|
||||
|
@ -87,6 +88,11 @@ namespace Ombi.Core.Senders
|
|||
|
||||
if (artist == null || artist.id <= 0)
|
||||
{
|
||||
EnsureArg.IsNotNullOrEmpty(model.ForeignArtistId, nameof(model.ForeignArtistId));
|
||||
EnsureArg.IsNotNullOrEmpty(model.ForeignAlbumId, nameof(model.ForeignAlbumId));
|
||||
EnsureArg.IsNotNullOrEmpty(model.ArtistName, nameof(model.ArtistName));
|
||||
EnsureArg.IsNotNullOrEmpty(rootFolderPath, nameof(rootFolderPath));
|
||||
|
||||
// Create artist
|
||||
var newArtist = new ArtistAdd
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Security.Principal;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using Ombi.Api.Discord;
|
||||
|
@ -60,6 +61,8 @@ using Ombi.Schedule.Jobs.Lidarr;
|
|||
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
||||
using Ombi.Schedule.Jobs.SickRage;
|
||||
using Ombi.Schedule.Processor;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz.Spi;
|
||||
|
||||
namespace Ombi.DependencyInjection
|
||||
{
|
||||
|
@ -189,6 +192,7 @@ namespace Ombi.DependencyInjection
|
|||
|
||||
public static void RegisterJobs(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IJobFactory, IoCJobFactory>(provider => new IoCJobFactory(provider));
|
||||
services.AddTransient<IBackgroundJobClient, BackgroundJobClient>();
|
||||
|
||||
services.AddTransient<IPlexContentSync, PlexContentSync>();
|
||||
|
@ -209,7 +213,6 @@ namespace Ombi.DependencyInjection
|
|||
services.AddTransient<ISickRageSync, SickRageSync>();
|
||||
services.AddTransient<IRefreshMetadata, RefreshMetadata>();
|
||||
services.AddTransient<INewsletterJob, NewsletterJob>();
|
||||
services.AddTransient<IPlexRecentlyAddedSync, PlexRecentlyAddedSync>();
|
||||
services.AddTransient<ILidarrAlbumSync, LidarrAlbumSync>();
|
||||
services.AddTransient<ILidarrArtistSync, LidarrArtistSync>();
|
||||
services.AddTransient<ILidarrAvailabilityChecker, LidarrAvailabilityChecker>();
|
||||
|
|
|
@ -41,4 +41,10 @@
|
|||
<ProjectReference Include="..\Ombi.Settings\Ombi.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AspNetCore.SignalR.Core">
|
||||
<HintPath>..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.signalr.core\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Core.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -28,18 +28,15 @@ namespace Ombi.Helpers
|
|||
return result;
|
||||
}
|
||||
|
||||
//using (await _mutex.LockAsync())
|
||||
if (_memoryCache.TryGetValue(cacheKey, out result))
|
||||
{
|
||||
if (_memoryCache.TryGetValue(cacheKey, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = await factory();
|
||||
_memoryCache.Set(cacheKey, result, absoluteExpiration);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result = await factory();
|
||||
_memoryCache.Set(cacheKey, result, absoluteExpiration);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Remove(string key)
|
||||
|
@ -47,34 +44,34 @@ namespace Ombi.Helpers
|
|||
_memoryCache.Remove(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public T GetOrAdd<T>(string cacheKey, Func<T> factory, DateTime absoluteExpiration)
|
||||
|
||||
|
||||
public T GetOrAdd<T>(string cacheKey, Func<T> factory, DateTime absoluteExpiration)
|
||||
{
|
||||
// locks get and set internally
|
||||
if (_memoryCache.TryGetValue<T>(cacheKey, out var result))
|
||||
{
|
||||
// locks get and set internally
|
||||
if (_memoryCache.TryGetValue<T>(cacheKey, out var result))
|
||||
return result;
|
||||
}
|
||||
|
||||
lock (TypeLock<T>.Lock)
|
||||
{
|
||||
if (_memoryCache.TryGetValue(cacheKey, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
lock (TypeLock<T>.Lock)
|
||||
{
|
||||
if (_memoryCache.TryGetValue(cacheKey, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result = factory();
|
||||
_memoryCache.Set(cacheKey, result, absoluteExpiration);
|
||||
|
||||
result = factory();
|
||||
_memoryCache.Set(cacheKey, result, absoluteExpiration);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TypeLock<T>
|
||||
{
|
||||
public static object Lock { get; } = new object();
|
||||
}
|
||||
|
||||
private static class TypeLock<T>
|
||||
{
|
||||
public static object Lock { get; } = new object();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
/// <summary>
|
||||
/// Helper class that provides common values for the cron expressions.
|
||||
/// </summary>
|
||||
|
@ -44,7 +43,7 @@
|
|||
/// <param name="minute">The minute in which the schedule will be activated (0-59).</param>
|
||||
public static string Hourly(int minute)
|
||||
{
|
||||
return $"{minute} * * * *";
|
||||
return $"0 {minute} 0/1 1/1 * ? *";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -73,7 +72,7 @@
|
|||
/// <param name="minute">The minute in which the schedule will be activated (0-59).</param>
|
||||
public static string Daily(int hour, int minute)
|
||||
{
|
||||
return $"{minute} {hour} * * *";
|
||||
return $"0 {minute} {hour} 1/1 * ? *";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -114,7 +113,7 @@
|
|||
/// <param name="minute">The minute in which the schedule will be activated (0-59).</param>
|
||||
public static string Weekly(DayOfWeek dayOfWeek, int hour, int minute)
|
||||
{
|
||||
return $"{minute} {hour} * * {(int)dayOfWeek}";
|
||||
return $"0 {minute} {hour} ? * {(int)dayOfWeek} *";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -219,7 +218,7 @@
|
|||
/// <param name="interval">The number of minutes to wait between every activation.</param>
|
||||
public static string MinuteInterval(int interval)
|
||||
{
|
||||
return $"*/{interval} * * * *";
|
||||
return $"0 0/{interval} * 1/1 * ? *";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -228,7 +227,7 @@
|
|||
/// <param name="interval">The number of hours to wait between every activation.</param>
|
||||
public static string HourInterval(int interval)
|
||||
{
|
||||
return $"0 */{interval} * * *";
|
||||
return $"0 0 0/{interval} 1/1 * ? *";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -237,7 +236,7 @@
|
|||
/// <param name="interval">The number of days to wait between every activation.</param>
|
||||
public static string DayInterval(int interval)
|
||||
{
|
||||
return $"0 0 */{interval} * *";
|
||||
return $"0 0 12 1/{interval} * ? *";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -249,4 +248,39 @@
|
|||
return $"0 0 1 */{interval} *";
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Summary:
|
||||
// Specifies the day of the week.
|
||||
public enum DayOfWeek
|
||||
{
|
||||
//
|
||||
// Summary:
|
||||
// Indicates Sunday.
|
||||
Sunday = 1,
|
||||
//
|
||||
// Summary:
|
||||
// Indicates Monday.
|
||||
Monday = 2,
|
||||
//
|
||||
// Summary:
|
||||
// Indicates Tuesday.
|
||||
Tuesday = 3,
|
||||
//
|
||||
// Summary:
|
||||
// Indicates Wednesday.
|
||||
Wednesday = 4,
|
||||
//
|
||||
// Summary:
|
||||
// Indicates Thursday.
|
||||
Thursday = 5,
|
||||
//
|
||||
// Summary:
|
||||
// Indicates Friday.
|
||||
Friday = 6,
|
||||
//
|
||||
// Summary:
|
||||
// Indicates Saturday.
|
||||
Saturday = 7
|
||||
}
|
||||
}
|
73
src/Ombi.Hubs/NotificationHub.cs
Normal file
73
src/Ombi.Hubs/NotificationHub.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Helpers;
|
||||
|
||||
namespace Ombi.Hubs
|
||||
{
|
||||
public class NotificationHub : Hub
|
||||
{
|
||||
public NotificationHub(OmbiUserManager um)
|
||||
{
|
||||
_userManager = um;
|
||||
}
|
||||
|
||||
public static ConcurrentDictionary<string, HubUsers> UsersOnline = new ConcurrentDictionary<string, HubUsers>();
|
||||
|
||||
public static List<string> AdminConnectionIds
|
||||
{
|
||||
get
|
||||
{
|
||||
return UsersOnline.Where(x => x.Value.Roles.Contains(OmbiRoles.Admin)).Select(x => x.Key).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public const string NotificationEvent = "Notification";
|
||||
|
||||
private readonly OmbiUserManager _userManager;
|
||||
|
||||
public override async Task OnConnectedAsync()
|
||||
{
|
||||
var identity = (ClaimsIdentity) Context.User.Identity;
|
||||
var userIdClaim = identity.Claims.FirstOrDefault(x => x.Type.Equals("Id", StringComparison.InvariantCultureIgnoreCase));
|
||||
if (userIdClaim == null)
|
||||
{
|
||||
await base.OnConnectedAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var user = await _userManager.Users.
|
||||
FirstOrDefaultAsync(x => x.Id.Equals(userIdClaim.Value, StringComparison.InvariantCultureIgnoreCase));
|
||||
var claims = await _userManager.GetRolesAsync(user);
|
||||
UsersOnline.TryAdd(Context.ConnectionId, new HubUsers
|
||||
{
|
||||
UserId = userIdClaim.Value,
|
||||
Roles = claims
|
||||
});
|
||||
await base.OnConnectedAsync();
|
||||
}
|
||||
|
||||
public override Task OnDisconnectedAsync(Exception exception)
|
||||
{
|
||||
UsersOnline.TryRemove(Context.ConnectionId, out _);
|
||||
return base.OnDisconnectedAsync(exception);
|
||||
}
|
||||
|
||||
public Task Notification(string data)
|
||||
{
|
||||
return Clients.All.SendAsync(NotificationEvent, data);
|
||||
}
|
||||
}
|
||||
|
||||
public class HubUsers
|
||||
{
|
||||
public string UserId { get; set; }
|
||||
public IList<string> Roles { get; set; } = new List<string>();
|
||||
}
|
||||
}
|
21
src/Ombi.Hubs/Ombi.Hubs.csproj
Normal file
21
src/Ombi.Hubs/Ombi.Hubs.csproj
Normal file
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNet.SignalR" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AspNetCore.SignalR.Core">
|
||||
<HintPath>..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.signalr.core\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Core.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -32,7 +32,7 @@ namespace Ombi.Schedule.Tests
|
|||
[Test]
|
||||
public async Task DoesNotRun_WhenDisabled()
|
||||
{
|
||||
await Job.Start();
|
||||
await Job.Execute(null);
|
||||
Repo.Verify(x => x.GetAll(),Times.Never);
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,8 @@ namespace Ombi.Schedule.Tests
|
|||
};
|
||||
|
||||
Settings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new IssueSettings { DeleteIssues = true, DaysAfterResolvedToDelete = 5 });
|
||||
Repo.Setup(x => x.GetAll()).Returns(issues.AsQueryable());
|
||||
await Job.Start();
|
||||
Repo.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Issues>(issues));
|
||||
await Job.Execute(null);
|
||||
|
||||
Assert.That(issues.First().Status, Is.EqualTo(IssueStatus.Deleted));
|
||||
Repo.Verify(x => x.SaveChangesAsync(), Times.Once);
|
||||
|
@ -75,7 +75,7 @@ namespace Ombi.Schedule.Tests
|
|||
|
||||
Settings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new IssueSettings { DeleteIssues = true, DaysAfterResolvedToDelete = 5 });
|
||||
Repo.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Issues>(issues));
|
||||
await Job.Start();
|
||||
await Job.Execute(null);
|
||||
|
||||
Assert.That(issues[0].Status, Is.Not.EqualTo(IssueStatus.Deleted));
|
||||
Assert.That(issues[1].Status, Is.EqualTo(IssueStatus.Deleted));
|
||||
|
@ -101,7 +101,7 @@ namespace Ombi.Schedule.Tests
|
|||
|
||||
Settings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new IssueSettings { DeleteIssues = true, DaysAfterResolvedToDelete = 5 });
|
||||
Repo.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Issues>(issues));
|
||||
await Job.Start();
|
||||
await Job.Execute(null);
|
||||
|
||||
Assert.That(issues[0].Status, Is.Not.EqualTo(IssueStatus.Deleted));
|
||||
Assert.That(issues[1].Status, Is.Not.EqualTo(IssueStatus.Deleted));
|
||||
|
|
|
@ -18,4 +18,10 @@
|
|||
<ProjectReference Include="..\Ombi.Schedule\Ombi.Schedule.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AspNetCore.SignalR.Core">
|
||||
<HintPath>..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.signalr.core\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Core.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
36
src/Ombi.Schedule.Tests/OmbiQuartzTests.cs
Normal file
36
src/Ombi.Schedule.Tests/OmbiQuartzTests.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Quartz;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Schedule.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class OmbiQuartzTests
|
||||
{
|
||||
|
||||
[Test]
|
||||
[Ignore("Cannot get this to work")]
|
||||
public async Task Test()
|
||||
{
|
||||
var scheduleMock = new Mock<IScheduler>();
|
||||
scheduleMock.Setup(x => x.TriggerJob(It.IsAny<JobKey>(),
|
||||
It.IsAny<CancellationToken>()));
|
||||
var sut = new QuartzMock(scheduleMock);
|
||||
|
||||
//await QuartzMock.TriggerJob("ABC");
|
||||
|
||||
scheduleMock.Verify(x => x.TriggerJob(It.Is<JobKey>(j => j.Name == "ABC"),
|
||||
default(CancellationToken)), Times.Once);
|
||||
}
|
||||
}
|
||||
public class QuartzMock : OmbiQuartz
|
||||
{
|
||||
public QuartzMock(Mock<IScheduler> mock)
|
||||
{
|
||||
_instance = this;
|
||||
_scheduler = mock.Object;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,13 +2,16 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Castle.Components.DictionaryAdapter;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Moq;
|
||||
using MockQueryable.Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Notifications;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Schedule.Jobs.Plex;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
|
@ -18,6 +21,7 @@ using Ombi.Store.Repository.Requests;
|
|||
namespace Ombi.Schedule.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Ignore("Need to work out how to mockout the hub context")]
|
||||
public class PlexAvailabilityCheckerTests
|
||||
{
|
||||
[SetUp]
|
||||
|
@ -27,7 +31,11 @@ namespace Ombi.Schedule.Tests
|
|||
_tv = new Mock<ITvRequestRepository>();
|
||||
_movie = new Mock<IMovieRequestRepository>();
|
||||
_notify = new Mock<INotificationService>();
|
||||
Checker = new PlexAvailabilityChecker(_repo.Object, _tv.Object, _movie.Object, _notify.Object, new Mock<IBackgroundJobClient>().Object, null);
|
||||
var hub = new Mock<IHubContext<NotificationHub>>();
|
||||
hub.Setup(x =>
|
||||
x.Clients.Clients(It.IsAny<IReadOnlyList<string>>()).SendCoreAsync(It.IsAny<string>(), It.IsAny<object[]>(), It.IsAny<CancellationToken>()));
|
||||
NotificationHub.UsersOnline.TryAdd("A", new HubUsers());
|
||||
Checker = new PlexAvailabilityChecker(_repo.Object, _tv.Object, _movie.Object, _notify.Object, new Mock<IBackgroundJobClient>().Object, null, hub.Object);
|
||||
}
|
||||
|
||||
|
||||
|
@ -47,7 +55,7 @@ namespace Ombi.Schedule.Tests
|
|||
_movie.Setup(x => x.GetAll()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
||||
_repo.Setup(x => x.Get("test")).ReturnsAsync(new PlexServerContent());
|
||||
|
||||
await Checker.Start();
|
||||
await Checker.Execute(null);
|
||||
|
||||
_movie.Verify(x => x.Save(), Times.Once);
|
||||
|
||||
|
@ -63,8 +71,8 @@ namespace Ombi.Schedule.Tests
|
|||
};
|
||||
_movie.Setup(x => x.GetAll()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
||||
|
||||
await Checker.Start();
|
||||
|
||||
await Checker.Execute(null);
|
||||
|
||||
Assert.False(request.Available);
|
||||
}
|
||||
|
||||
|
@ -111,7 +119,7 @@ namespace Ombi.Schedule.Tests
|
|||
}.AsQueryable().BuildMock().Object);
|
||||
_repo.Setup(x => x.Include(It.IsAny<IQueryable<PlexEpisode>>(),It.IsAny<Expression<Func<PlexEpisode, PlexServerContent>>>()));
|
||||
|
||||
await Checker.Start();
|
||||
await Checker.Execute(null);
|
||||
|
||||
_tv.Verify(x => x.Save(), Times.Once);
|
||||
|
||||
|
|
32
src/Ombi.Schedule/IocJobFactory.cs
Normal file
32
src/Ombi.Schedule/IocJobFactory.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Quartz;
|
||||
using Quartz.Spi;
|
||||
|
||||
namespace Ombi.Schedule
|
||||
{
|
||||
public class IoCJobFactory : IJobFactory
|
||||
{
|
||||
private readonly IServiceProvider _factory;
|
||||
|
||||
public IoCJobFactory(IServiceProvider factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
|
||||
{
|
||||
var scopeFactory = _factory.GetService<IServiceScopeFactory>();
|
||||
var scope = scopeFactory.CreateScope();
|
||||
var scopedContainer = scope.ServiceProvider;
|
||||
|
||||
var implementation = scopedContainer.GetRequiredService(bundle.JobDetail.JobType) as IJob;
|
||||
return implementation;
|
||||
}
|
||||
|
||||
public void ReturnJob(IJob job)
|
||||
{
|
||||
var disposable = job as IDisposable;
|
||||
disposable?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -65,24 +65,24 @@ namespace Ombi.Schedule
|
|||
{
|
||||
var s = _jobSettings.GetSettings();
|
||||
|
||||
RecurringJob.AddOrUpdate(() => _embyContentSync.Start(), JobSettingsHelper.EmbyContent(s));
|
||||
RecurringJob.AddOrUpdate(() => _sonarrSync.Start(), JobSettingsHelper.Sonarr(s));
|
||||
RecurringJob.AddOrUpdate(() => _radarrSync.CacheContent(), JobSettingsHelper.Radarr(s));
|
||||
RecurringJob.AddOrUpdate(() => _plexContentSync.CacheContent(false), JobSettingsHelper.PlexContent(s));
|
||||
RecurringJob.AddOrUpdate(() => _plexRecentlyAddedSync.Start(), JobSettingsHelper.PlexRecentlyAdded(s));
|
||||
RecurringJob.AddOrUpdate(() => _cpCache.Start(), JobSettingsHelper.CouchPotato(s));
|
||||
RecurringJob.AddOrUpdate(() => _srSync.Start(), JobSettingsHelper.SickRageSync(s));
|
||||
RecurringJob.AddOrUpdate(() => _refreshMetadata.Start(), JobSettingsHelper.RefreshMetadata(s));
|
||||
RecurringJob.AddOrUpdate(() => _lidarrArtistSync.CacheContent(), JobSettingsHelper.LidarrArtistSync(s));
|
||||
RecurringJob.AddOrUpdate(() => _issuesPurge.Start(), JobSettingsHelper.IssuePurge(s));
|
||||
// RecurringJob.AddOrUpdate(() => _embyContentSync.Start(), JobSettingsHelper.EmbyContent(s));
|
||||
// RecurringJob.AddOrUpdate(() => _sonarrSync.Start(), JobSettingsHelper.Sonarr(s));
|
||||
// RecurringJob.AddOrUpdate(() => _radarrSync.CacheContent(), JobSettingsHelper.Radarr(s));
|
||||
// //RecurringJob.AddOrUpdate(() => _plexContentSync.Execute(null), JobSettingsHelper.PlexContent(s));
|
||||
// //RecurringJob.AddOrUpdate(() => _plexRecentlyAddedSync.Start(), JobSettingsHelper.PlexRecentlyAdded(s));
|
||||
// RecurringJob.AddOrUpdate(() => _cpCache.Start(), JobSettingsHelper.CouchPotato(s));
|
||||
// RecurringJob.AddOrUpdate(() => _srSync.Start(), JobSettingsHelper.SickRageSync(s));
|
||||
// RecurringJob.AddOrUpdate(() => _refreshMetadata.Start(), JobSettingsHelper.RefreshMetadata(s));
|
||||
// RecurringJob.AddOrUpdate(() => _lidarrArtistSync.CacheContent(), JobSettingsHelper.LidarrArtistSync(s));
|
||||
// RecurringJob.AddOrUpdate(() => _issuesPurge.Start(), JobSettingsHelper.IssuePurge(s));
|
||||
|
||||
RecurringJob.AddOrUpdate(() => _updater.Update(null), JobSettingsHelper.Updater(s));
|
||||
// RecurringJob.AddOrUpdate(() => _updater.Update(null), JobSettingsHelper.Updater(s));
|
||||
|
||||
RecurringJob.AddOrUpdate(() => _embyUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||
RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||
RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
||||
RecurringJob.AddOrUpdate(() => _resender.Start(), JobSettingsHelper.ResendFailedRequests(s));
|
||||
RecurringJob.AddOrUpdate(() => _mediaDatabaseRefresh.Start(), JobSettingsHelper.MediaDatabaseRefresh(s));
|
||||
// RecurringJob.AddOrUpdate(() => _embyUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||
// RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||
// RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
||||
//// RecurringJob.AddOrUpdate(() => _resender.Start(), JobSettingsHelper.ResendFailedRequests(s));
|
||||
// RecurringJob.AddOrUpdate(() => _mediaDatabaseRefresh.Start(), JobSettingsHelper.MediaDatabaseRefresh(s));
|
||||
}
|
||||
|
||||
private bool _disposed;
|
||||
|
@ -93,7 +93,6 @@ namespace Ombi.Schedule
|
|||
|
||||
if (disposing)
|
||||
{
|
||||
_plexContentSync?.Dispose();
|
||||
_radarrSync?.Dispose();
|
||||
_updater?.Dispose();
|
||||
_plexUserImporter?.Dispose();
|
||||
|
|
|
@ -28,26 +28,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.CouchPotato;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Couchpotato
|
||||
{
|
||||
public class CouchPotatoSync : ICouchPotatoSync
|
||||
{
|
||||
public CouchPotatoSync(ISettingsService<CouchPotatoSettings> cpSettings,
|
||||
ICouchPotatoApi api, ILogger<CouchPotatoSync> log, IExternalContext ctx)
|
||||
ICouchPotatoApi api, ILogger<CouchPotatoSync> log, IExternalContext ctx, IHubContext<NotificationHub> hub)
|
||||
{
|
||||
_settings = cpSettings;
|
||||
_api = api;
|
||||
_log = log;
|
||||
_ctx = ctx;
|
||||
_notification = hub;
|
||||
_settings.ClearCache();
|
||||
}
|
||||
|
||||
|
@ -55,8 +59,9 @@ namespace Ombi.Schedule.Jobs.Couchpotato
|
|||
private readonly ICouchPotatoApi _api;
|
||||
private readonly ILogger<CouchPotatoSync> _log;
|
||||
private readonly IExternalContext _ctx;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
var settings = await _settings.GetSettingsAsync();
|
||||
if (!settings.Enabled)
|
||||
|
@ -64,6 +69,8 @@ namespace Ombi.Schedule.Jobs.Couchpotato
|
|||
return;
|
||||
}
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Couch Potato Sync Started");
|
||||
try
|
||||
{
|
||||
_log.LogInformation(LoggingEvents.CouchPotatoCacher, "Getting all active movies from CP");
|
||||
|
@ -94,10 +101,15 @@ namespace Ombi.Schedule.Jobs.Couchpotato
|
|||
await _ctx.CouchPotatoCache.AddRangeAsync(movieIds);
|
||||
|
||||
await _ctx.SaveChangesAsync();
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Couch Potato Sync Finished");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Couch Potato Sync Failed");
|
||||
_log.LogError(LoggingEvents.CouchPotatoCacher, e, "error when trying to get movies from CP");
|
||||
throw;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,5 @@ namespace Ombi.Schedule.Jobs.Couchpotato
|
|||
{
|
||||
public interface ICouchPotatoSync : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -29,27 +29,31 @@ using System;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Core.Notifications;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Emby
|
||||
{
|
||||
public class EmbyAvaliabilityChecker : IEmbyAvaliabilityChecker
|
||||
{
|
||||
public EmbyAvaliabilityChecker(IEmbyContentRepository repo, ITvRequestRepository t, IMovieRequestRepository m,
|
||||
INotificationService n, ILogger<EmbyAvaliabilityChecker> log)
|
||||
INotificationService n, ILogger<EmbyAvaliabilityChecker> log, IHubContext<NotificationHub> notification)
|
||||
{
|
||||
_repo = repo;
|
||||
_tvRepo = t;
|
||||
_movieRepo = m;
|
||||
_notificationService = n;
|
||||
_log = log;
|
||||
_notification = notification;
|
||||
}
|
||||
|
||||
private readonly ITvRequestRepository _tvRepo;
|
||||
|
@ -57,11 +61,17 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
private readonly IEmbyContentRepository _repo;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly ILogger<EmbyAvaliabilityChecker> _log;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Emby Availability Checker Started");
|
||||
await ProcessMovies();
|
||||
await ProcessTv();
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Emby Availability Checker Finished");
|
||||
}
|
||||
|
||||
private async Task ProcessMovies()
|
||||
|
|
|
@ -3,15 +3,18 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Emby;
|
||||
using Ombi.Api.Emby.Models.Movie;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Schedule.Jobs.Ombi;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
using Serilog;
|
||||
using EmbyMediaType = Ombi.Store.Entities.EmbyMediaType;
|
||||
|
||||
|
@ -20,30 +23,31 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
public class EmbyContentSync : IEmbyContentSync
|
||||
{
|
||||
public EmbyContentSync(ISettingsService<EmbySettings> settings, IEmbyApi api, ILogger<EmbyContentSync> logger,
|
||||
IEmbyContentRepository repo, IEmbyEpisodeSync epSync, IRefreshMetadata metadata)
|
||||
IEmbyContentRepository repo, IHubContext<NotificationHub> notification)
|
||||
{
|
||||
_logger = logger;
|
||||
_settings = settings;
|
||||
_api = api;
|
||||
_repo = repo;
|
||||
_episodeSync = epSync;
|
||||
_metadata = metadata;
|
||||
_notification = notification;
|
||||
}
|
||||
|
||||
private readonly ILogger<EmbyContentSync> _logger;
|
||||
private readonly ISettingsService<EmbySettings> _settings;
|
||||
private readonly IEmbyApi _api;
|
||||
private readonly IEmbyContentRepository _repo;
|
||||
private readonly IEmbyEpisodeSync _episodeSync;
|
||||
private readonly IRefreshMetadata _metadata;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
var embySettings = await _settings.GetSettingsAsync();
|
||||
if (!embySettings.Enable)
|
||||
return;
|
||||
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Emby Content Sync Started");
|
||||
|
||||
foreach (var server in embySettings.Servers)
|
||||
{
|
||||
try
|
||||
|
@ -52,13 +56,18 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Emby Content Sync Failed");
|
||||
_logger.LogError(e, "Exception when caching Emby for server {0}", server.Name);
|
||||
}
|
||||
}
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Emby Content Sync Finished");
|
||||
// Episodes
|
||||
BackgroundJob.Enqueue(() => _episodeSync.Start());
|
||||
BackgroundJob.Enqueue(() => _metadata.Start());
|
||||
|
||||
await OmbiQuartz.TriggerJob(nameof(IEmbyEpisodeSync), "Emby");
|
||||
await OmbiQuartz.TriggerJob(nameof(IRefreshMetadata), "Emby");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,44 +30,52 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Emby;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Emby
|
||||
{
|
||||
public class EmbyEpisodeSync : IEmbyEpisodeSync
|
||||
{
|
||||
public EmbyEpisodeSync(ISettingsService<EmbySettings> s, IEmbyApi api, ILogger<EmbyEpisodeSync> l, IEmbyContentRepository repo,
|
||||
IEmbyAvaliabilityChecker checker)
|
||||
public EmbyEpisodeSync(ISettingsService<EmbySettings> s, IEmbyApi api, ILogger<EmbyEpisodeSync> l, IEmbyContentRepository repo
|
||||
, IHubContext<NotificationHub> notification)
|
||||
{
|
||||
_api = api;
|
||||
_logger = l;
|
||||
_settings = s;
|
||||
_repo = repo;
|
||||
_avaliabilityChecker = checker;
|
||||
_notification = notification;
|
||||
}
|
||||
|
||||
private readonly ISettingsService<EmbySettings> _settings;
|
||||
private readonly IEmbyApi _api;
|
||||
private readonly ILogger<EmbyEpisodeSync> _logger;
|
||||
private readonly IEmbyContentRepository _repo;
|
||||
private readonly IEmbyAvaliabilityChecker _avaliabilityChecker;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
var settings = await _settings.GetSettingsAsync();
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Emby Episode Sync Started");
|
||||
foreach (var server in settings.Servers)
|
||||
{
|
||||
await CacheEpisodes(server);
|
||||
}
|
||||
|
||||
BackgroundJob.Enqueue(() => _avaliabilityChecker.Start());
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Emby Episode Sync Finished");
|
||||
await OmbiQuartz.TriggerJob(nameof(IEmbyAvaliabilityChecker), "Emby");
|
||||
}
|
||||
|
||||
private async Task CacheEpisodes(EmbyServers server)
|
||||
|
@ -142,7 +150,6 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
{
|
||||
_settings?.Dispose();
|
||||
_repo?.Dispose();
|
||||
_avaliabilityChecker?.Dispose();
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
|
|
|
@ -29,27 +29,31 @@ using System;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Emby;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Emby
|
||||
{
|
||||
public class EmbyUserImporter : IEmbyUserImporter
|
||||
{
|
||||
public EmbyUserImporter(IEmbyApi api, UserManager<OmbiUser> um, ILogger<EmbyUserImporter> log,
|
||||
ISettingsService<EmbySettings> embySettings, ISettingsService<UserManagementSettings> ums)
|
||||
ISettingsService<EmbySettings> embySettings, ISettingsService<UserManagementSettings> ums, IHubContext<NotificationHub> notification)
|
||||
{
|
||||
_api = api;
|
||||
_userManager = um;
|
||||
_log = log;
|
||||
_embySettings = embySettings;
|
||||
_userManagementSettings = ums;
|
||||
_notification = notification;
|
||||
}
|
||||
|
||||
private readonly IEmbyApi _api;
|
||||
|
@ -57,8 +61,9 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
private readonly ILogger<EmbyUserImporter> _log;
|
||||
private readonly ISettingsService<EmbySettings> _embySettings;
|
||||
private readonly ISettingsService<UserManagementSettings> _userManagementSettings;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
var userManagementSettings = await _userManagementSettings.GetSettingsAsync();
|
||||
if (!userManagementSettings.ImportEmbyUsers)
|
||||
|
@ -70,6 +75,9 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Emby User Importer Started");
|
||||
var allUsers = await _userManager.Users.Where(x => x.UserType == UserType.EmbyUser).ToListAsync();
|
||||
foreach (var server in settings.Servers)
|
||||
{
|
||||
|
@ -147,6 +155,9 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Emby User Importer Finished");
|
||||
}
|
||||
|
||||
private bool _disposed;
|
||||
|
|
|
@ -4,6 +4,5 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
{
|
||||
public interface IEmbyAvaliabilityChecker : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -4,6 +4,5 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
{
|
||||
public interface IEmbyContentSync : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -4,6 +4,5 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
{
|
||||
public interface IEmbyEpisodeSync : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -4,6 +4,5 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
{
|
||||
public interface IEmbyUserImporter : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -25,11 +25,12 @@
|
|||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using Quartz;
|
||||
using System;
|
||||
|
||||
namespace Ombi.Schedule
|
||||
{
|
||||
public interface IBaseJob : IDisposable
|
||||
public interface IBaseJob : IJob, IDisposable
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Lidarr
|
||||
{
|
||||
public interface ILidarrAlbumSync
|
||||
public interface ILidarrAlbumSync : IJob
|
||||
{
|
||||
Task CacheContent();
|
||||
void Dispose();
|
||||
Task<IEnumerable<LidarrAlbumCache>> GetCachedContent();
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Lidarr
|
||||
{
|
||||
public interface ILidarrArtistSync
|
||||
public interface ILidarrArtistSync : IJob
|
||||
{
|
||||
Task CacheContent();
|
||||
void Dispose();
|
||||
Task<IEnumerable<LidarrArtistCache>> GetCachedContent();
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using System.Threading.Tasks;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Lidarr
|
||||
{
|
||||
public interface ILidarrAvailabilityChecker
|
||||
public interface ILidarrAvailabilityChecker : IJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -2,15 +2,18 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Lidarr;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Lidarr
|
||||
|
@ -18,7 +21,7 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
|||
public class LidarrAlbumSync : ILidarrAlbumSync
|
||||
{
|
||||
public LidarrAlbumSync(ISettingsService<LidarrSettings> lidarr, ILidarrApi lidarrApi, ILogger<LidarrAlbumSync> log, IExternalContext ctx,
|
||||
IBackgroundJobClient job, ILidarrAvailabilityChecker availability)
|
||||
IBackgroundJobClient job, ILidarrAvailabilityChecker availability, IHubContext<NotificationHub> notification)
|
||||
{
|
||||
_lidarrSettings = lidarr;
|
||||
_lidarrApi = lidarrApi;
|
||||
|
@ -26,6 +29,7 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
|||
_ctx = ctx;
|
||||
_job = job;
|
||||
_availability = availability;
|
||||
_notification = notification;
|
||||
}
|
||||
|
||||
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||
|
@ -34,14 +38,18 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
|||
private readonly IExternalContext _ctx;
|
||||
private readonly IBackgroundJobClient _job;
|
||||
private readonly ILidarrAvailabilityChecker _availability;
|
||||
|
||||
public async Task CacheContent()
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
public async Task Execute(IJobExecutionContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await _lidarrSettings.GetSettingsAsync();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Lidarr Album Sync Started");
|
||||
try
|
||||
{
|
||||
var albums = await _lidarrApi.GetAllAlbums(settings.ApiKey, settings.FullUri);
|
||||
|
@ -75,10 +83,15 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
|||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Lidarr Album Sync Failed");
|
||||
_logger.LogError(LoggingEvents.Cacher, ex, "Failed caching queued items from Lidarr Album");
|
||||
}
|
||||
|
||||
_job.Enqueue(() => _availability.Start());
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Lidarr Album Sync Finished");
|
||||
|
||||
await OmbiQuartz.TriggerJob(nameof(ILidarrAvailabilityChecker), "DVR");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
|
|
|
@ -2,46 +2,50 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Lidarr;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz;
|
||||
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, IExternalContext ctx,
|
||||
IBackgroundJobClient background, ILidarrAlbumSync album)
|
||||
public LidarrArtistSync(ISettingsService<LidarrSettings> lidarr, ILidarrApi lidarrApi, ILogger<LidarrArtistSync> log, IExternalContext ctx
|
||||
, IHubContext<NotificationHub> notification)
|
||||
{
|
||||
_lidarrSettings = lidarr;
|
||||
_lidarrApi = lidarrApi;
|
||||
_logger = log;
|
||||
_ctx = ctx;
|
||||
_job = background;
|
||||
_albumSync = album;
|
||||
_notification = notification;
|
||||
}
|
||||
|
||||
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||
private readonly ILidarrApi _lidarrApi;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IExternalContext _ctx;
|
||||
private readonly IBackgroundJobClient _job;
|
||||
private readonly ILidarrAlbumSync _albumSync;
|
||||
|
||||
public async Task CacheContent()
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await _lidarrSettings.GetSettingsAsync();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Lidarr Artist Sync Started");
|
||||
try
|
||||
{
|
||||
var artists = await _lidarrApi.GetArtists(settings.ApiKey, settings.FullUri);
|
||||
|
@ -71,10 +75,15 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Lidarr Artist Sync Failed");
|
||||
_logger.LogError(LoggingEvents.Cacher, ex, "Failed caching queued items from Lidarr");
|
||||
}
|
||||
|
||||
_job.Enqueue(() => _albumSync.CacheContent());
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Lidarr Artist Sync Finished");
|
||||
|
||||
await OmbiQuartz.TriggerJob(nameof(ILidarrAlbumSync), "DVR");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
|
|
|
@ -3,28 +3,32 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Core.Notifications;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Lidarr
|
||||
{
|
||||
public class LidarrAvailabilityChecker : ILidarrAvailabilityChecker
|
||||
{
|
||||
public LidarrAvailabilityChecker(IMusicRequestRepository requests, IRepository<LidarrAlbumCache> albums, ILogger<LidarrAvailabilityChecker> log,
|
||||
IBackgroundJobClient job, INotificationService notification)
|
||||
IBackgroundJobClient job, INotificationService notification, IHubContext<NotificationHub> notificationHub)
|
||||
{
|
||||
_cachedAlbums = albums;
|
||||
_requestRepository = requests;
|
||||
_logger = log;
|
||||
_job = job;
|
||||
_notificationService = notification;
|
||||
_notification = notificationHub;
|
||||
}
|
||||
|
||||
private readonly IMusicRequestRepository _requestRepository;
|
||||
|
@ -32,9 +36,13 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
|||
private readonly ILogger _logger;
|
||||
private readonly IBackgroundJobClient _job;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext ctx)
|
||||
{
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Lidarr Availability Check Started");
|
||||
var allAlbumRequests = _requestRepository.GetAll().Include(x => x.RequestedUser).Where(x => !x.Available);
|
||||
var albumsToUpdate = new List<AlbumRequest>();
|
||||
foreach (var request in allAlbumRequests)
|
||||
|
@ -68,6 +76,9 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
|||
Recipient = recipient,
|
||||
}));
|
||||
}
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Lidarr Availability Check Finished");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Ombi.Schedule.Jobs.Ombi
|
||||
{
|
||||
public interface IIssuesPurge : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
{
|
||||
}
|
||||
}
|
|
@ -4,6 +4,5 @@ namespace Ombi.Schedule.Jobs.Plex.Interfaces
|
|||
{
|
||||
public interface IMediaDatabaseRefresh : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
public interface INewsletterJob : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
Task Start(NewsletterSettings settings, bool test);
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
public interface IOmbiAutomaticUpdater : IBaseJob
|
||||
{
|
||||
Task Update(PerformContext context);
|
||||
string[] GetVersion();
|
||||
Task<bool> UpdateAvailable(string branch, string currentVersion);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
public interface IRefreshMetadata : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
Task ProcessPlexServerContent(IEnumerable<int> contentIds);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
using System.Threading.Tasks;
|
||||
using Quartz;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Ombi
|
||||
{
|
||||
public interface IResendFailedRequests
|
||||
public interface IResendFailedRequests : IJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using Ombi.Store.Entities;
|
|||
|
||||
namespace Ombi.Schedule.Jobs.Ombi
|
||||
{
|
||||
public interface IWelcomeEmail : IBaseJob
|
||||
public interface IWelcomeEmail
|
||||
{
|
||||
Task SendEmail(OmbiUser user);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using Ombi.Core.Settings;
|
|||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Ombi
|
||||
{
|
||||
|
@ -20,7 +21,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
private readonly IRepository<Issues> _issuesRepository;
|
||||
private readonly ISettingsService<IssueSettings> _settings;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
var settings = await _settings.GetSettingsAsync();
|
||||
if (!settings.DeleteIssues)
|
||||
|
|
|
@ -9,28 +9,28 @@ using Ombi.Helpers;
|
|||
using Ombi.Schedule.Jobs.Emby;
|
||||
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Ombi
|
||||
{
|
||||
public class MediaDatabaseRefresh : IMediaDatabaseRefresh
|
||||
{
|
||||
public MediaDatabaseRefresh(ISettingsService<PlexSettings> s, ILogger<MediaDatabaseRefresh> log,
|
||||
IPlexContentRepository plexRepo, IEmbyContentRepository embyRepo, IEmbyContentSync embySync)
|
||||
IPlexContentRepository plexRepo, IEmbyContentRepository embyRepo)
|
||||
{
|
||||
_settings = s;
|
||||
_log = log;
|
||||
_plexRepo = plexRepo;
|
||||
_embyRepo = embyRepo;
|
||||
_embyContentSync = embySync;
|
||||
_settings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly ISettingsService<PlexSettings> _settings;
|
||||
private readonly ILogger _log;
|
||||
private readonly IPlexContentRepository _plexRepo;
|
||||
private readonly IEmbyContentRepository _embyRepo;
|
||||
private readonly IEmbyContentSync _embyContentSync;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
await _embyRepo.ExecuteSql(episodeSQL);
|
||||
await _embyRepo.ExecuteSql(mainSql);
|
||||
|
||||
BackgroundJob.Enqueue(() => _embyContentSync.Start());
|
||||
await OmbiQuartz.TriggerJob(nameof(IEmbyContentSync), "Emby");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using MailKit;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MimeKit;
|
||||
|
@ -18,6 +19,7 @@ using Ombi.Api.TvMaze;
|
|||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Notifications;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Notifications.Templates;
|
||||
|
@ -26,6 +28,7 @@ using Ombi.Settings.Settings.Models.External;
|
|||
using Ombi.Settings.Settings.Models.Notifications;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
using ContentType = Ombi.Store.Entities.ContentType;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Ombi
|
||||
|
@ -37,7 +40,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
ISettingsService<EmailNotificationSettings> emailSettings, INotificationTemplatesRepository templateRepo,
|
||||
UserManager<OmbiUser> um, ISettingsService<NewsletterSettings> newsletter, ILogger<NewsletterJob> log,
|
||||
ILidarrApi lidarrApi, IRepository<LidarrAlbumCache> albumCache, ISettingsService<LidarrSettings> lidarrSettings,
|
||||
ISettingsService<OmbiSettings> ombiSettings, ISettingsService<PlexSettings> plexSettings, ISettingsService<EmbySettings> embySettings)
|
||||
ISettingsService<OmbiSettings> ombiSettings, ISettingsService<PlexSettings> plexSettings, ISettingsService<EmbySettings> embySettings
|
||||
, IHubContext<NotificationHub> notification)
|
||||
{
|
||||
_plex = plex;
|
||||
_emby = emby;
|
||||
|
@ -57,6 +61,11 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
_ombiSettings = ombiSettings;
|
||||
_plexSettings = plexSettings;
|
||||
_embySettings = embySettings;
|
||||
_notification = notification;
|
||||
_ombiSettings.ClearCache();
|
||||
_plexSettings.ClearCache();
|
||||
_emailSettings.ClearCache();
|
||||
_customizationSettings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly IPlexContentRepository _plex;
|
||||
|
@ -77,6 +86,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||
private readonly ISettingsService<PlexSettings> _plexSettings;
|
||||
private readonly ISettingsService<EmbySettings> _embySettings;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
public async Task Start(NewsletterSettings settings, bool test)
|
||||
{
|
||||
|
@ -90,9 +100,13 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
return;
|
||||
}
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Newsletter Started");
|
||||
var emailSettings = await _emailSettings.GetSettingsAsync();
|
||||
if (!ValidateConfiguration(emailSettings))
|
||||
{
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Newsletter Email Settings Not Configured");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -279,12 +293,17 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Newsletter Failed");
|
||||
_log.LogError(e, "Error when attempting to create newsletter");
|
||||
throw;
|
||||
}
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Newsletter Finished");
|
||||
}
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
var newsletterSettings = await _newsletterSettings.GetSettingsAsync();
|
||||
await Start(newsletterSettings, false);
|
||||
|
|
|
@ -20,6 +20,7 @@ using Ombi.Settings.Settings.Models;
|
|||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Updater;
|
||||
using Quartz;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Tar;
|
||||
|
||||
|
@ -41,7 +42,6 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
private IChangeLogProcessor Processor { get; }
|
||||
private ISettingsService<UpdateSettings> Settings { get; }
|
||||
private readonly IProcessProvider _processProvider;
|
||||
private static PerformContext Ctx { get; set; }
|
||||
private readonly IApplicationConfigRepository _appConfig;
|
||||
|
||||
public string[] GetVersion()
|
||||
|
@ -59,10 +59,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
|
||||
}
|
||||
|
||||
[AutomaticRetry(Attempts = 1)]
|
||||
public async Task Update(PerformContext c)
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
Ctx = c;
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Starting Update job");
|
||||
|
||||
var settings = await Settings.GetSettingsAsync();
|
||||
|
@ -182,7 +180,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
}
|
||||
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Starting Download");
|
||||
await DownloadAsync(download.Url, zipDir, c);
|
||||
await DownloadAsync(download.Url, zipDir);
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Finished Download");
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -321,7 +319,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
}
|
||||
}
|
||||
|
||||
public async Task DownloadAsync(string requestUri, string filename, PerformContext ctx)
|
||||
public async Task DownloadAsync(string requestUri, string filename)
|
||||
{
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Starting the DownloadAsync");
|
||||
using (var client = new WebClient())
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Emby;
|
||||
using Ombi.Api.TheMovieDb;
|
||||
|
@ -11,10 +12,12 @@ using Ombi.Api.TvMaze;
|
|||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Schedule.Jobs.Emby;
|
||||
using Ombi.Schedule.Jobs.Plex;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Ombi
|
||||
{
|
||||
|
@ -22,8 +25,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
public RefreshMetadata(IPlexContentRepository plexRepo, IEmbyContentRepository embyRepo,
|
||||
ILogger<RefreshMetadata> log, ITvMazeApi tvApi, ISettingsService<PlexSettings> plexSettings,
|
||||
IMovieDbApi movieApi, ISettingsService<EmbySettings> embySettings, IPlexAvailabilityChecker plexAvailability, IEmbyAvaliabilityChecker embyAvaliability,
|
||||
IEmbyApi embyApi)
|
||||
IMovieDbApi movieApi, ISettingsService<EmbySettings> embySettings, IEmbyApi embyApi, IHubContext<NotificationHub> notification)
|
||||
{
|
||||
_plexRepo = plexRepo;
|
||||
_embyRepo = embyRepo;
|
||||
|
@ -32,25 +34,26 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
_tvApi = tvApi;
|
||||
_plexSettings = plexSettings;
|
||||
_embySettings = embySettings;
|
||||
_plexAvailabilityChecker = plexAvailability;
|
||||
_embyAvaliabilityChecker = embyAvaliability;
|
||||
_embyApi = embyApi;
|
||||
_notification = notification;
|
||||
}
|
||||
|
||||
private readonly IPlexContentRepository _plexRepo;
|
||||
private readonly IEmbyContentRepository _embyRepo;
|
||||
private readonly IPlexAvailabilityChecker _plexAvailabilityChecker;
|
||||
private readonly IEmbyAvaliabilityChecker _embyAvaliabilityChecker;
|
||||
private readonly ILogger _log;
|
||||
private readonly IMovieDbApi _movieApi;
|
||||
private readonly ITvMazeApi _tvApi;
|
||||
private readonly ISettingsService<PlexSettings> _plexSettings;
|
||||
private readonly ISettingsService<EmbySettings> _embySettings;
|
||||
private readonly IEmbyApi _embyApi;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
_log.LogInformation("Starting the Metadata refresh");
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Metadata Refresh Started");
|
||||
try
|
||||
{
|
||||
var settings = await _plexSettings.GetSettingsAsync();
|
||||
|
@ -68,8 +71,14 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
catch (Exception e)
|
||||
{
|
||||
_log.LogError(e, "Exception when refreshing the Plex Metadata");
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Metadata Refresh Failed");
|
||||
throw;
|
||||
}
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Metadata Refresh Finished");
|
||||
}
|
||||
|
||||
public async Task ProcessPlexServerContent(IEnumerable<int> contentIds)
|
||||
|
@ -93,12 +102,12 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
if (plexSettings.Enable)
|
||||
{
|
||||
BackgroundJob.Enqueue(() => _plexAvailabilityChecker.Start());
|
||||
await OmbiQuartz.TriggerJob(nameof(IPlexAvailabilityChecker), "Plex");
|
||||
}
|
||||
|
||||
if (embySettings.Enable)
|
||||
{
|
||||
BackgroundJob.Enqueue(() => _embyAvaliabilityChecker.Start());
|
||||
await OmbiQuartz.TriggerJob(nameof(IEmbyAvaliabilityChecker), "Emby");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using Ombi.Core.Senders;
|
|||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Ombi
|
||||
{
|
||||
|
@ -32,7 +33,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
private readonly ITvRequestRepository _tvRequestRepository;
|
||||
private readonly IMusicRequestRepository _musicRequestRepository;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
// Get all the failed ones!
|
||||
var failedRequests = _requestQueue.GetAll().Where(x => !x.Completed.HasValue);
|
||||
|
|
|
@ -5,6 +5,5 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
{
|
||||
public interface IPlexAvailabilityChecker : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
using System.Threading.Tasks;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs
|
||||
{
|
||||
public interface IPlexContentSync : IBaseJob
|
||||
public interface IPlexContentSync : IJob
|
||||
{
|
||||
Task CacheContent(bool recentlyAddedSearch = false);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ namespace Ombi.Schedule.Jobs.Plex.Interfaces
|
|||
{
|
||||
public interface IPlexEpisodeSync : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
Task<HashSet<PlexEpisode>> ProcessEpsiodes(Metadata[] episodes, IQueryable<PlexEpisode> currentEpisodes);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,5 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
{
|
||||
public interface IPlexUserImporter : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -3,22 +3,25 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Core.Notifications;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Plex
|
||||
{
|
||||
public class PlexAvailabilityChecker : IPlexAvailabilityChecker
|
||||
{
|
||||
public PlexAvailabilityChecker(IPlexContentRepository repo, ITvRequestRepository tvRequest, IMovieRequestRepository movies,
|
||||
INotificationService notification, IBackgroundJobClient background, ILogger<PlexAvailabilityChecker> log)
|
||||
INotificationService notification, IBackgroundJobClient background, ILogger<PlexAvailabilityChecker> log, IHubContext<NotificationHub> hub)
|
||||
{
|
||||
_tvRepo = tvRequest;
|
||||
_repo = repo;
|
||||
|
@ -26,6 +29,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
_notificationService = notification;
|
||||
_backgroundJobClient = background;
|
||||
_log = log;
|
||||
_notification = hub;
|
||||
}
|
||||
|
||||
private readonly ITvRequestRepository _tvRepo;
|
||||
|
@ -34,18 +38,27 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
private readonly INotificationService _notificationService;
|
||||
private readonly IBackgroundJobClient _backgroundJobClient;
|
||||
private readonly ILogger _log;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Plex Availability Check Started");
|
||||
await ProcessMovies();
|
||||
await ProcessTv();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Plex Availability Check Failed");
|
||||
_log.LogError(e, "Exception thrown in Plex availbility checker");
|
||||
}
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Plex Availability Check Finished");
|
||||
}
|
||||
|
||||
private Task ProcessTv()
|
||||
|
|
|
@ -30,6 +30,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Plex;
|
||||
|
@ -37,18 +38,20 @@ using Ombi.Api.Plex.Models;
|
|||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Schedule.Jobs.Ombi;
|
||||
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
||||
using Ombi.Schedule.Jobs.Plex.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Plex
|
||||
{
|
||||
public class PlexContentSync : IPlexContentSync
|
||||
{
|
||||
public PlexContentSync(ISettingsService<PlexSettings> plex, IPlexApi plexApi, ILogger<PlexContentSync> logger, IPlexContentRepository repo,
|
||||
IPlexEpisodeSync epsiodeSync, IRefreshMetadata metadataRefresh, IPlexAvailabilityChecker checker)
|
||||
IPlexEpisodeSync epsiodeSync, IRefreshMetadata metadataRefresh, IPlexAvailabilityChecker checker, IHubContext<NotificationHub> hub)
|
||||
{
|
||||
Plex = plex;
|
||||
PlexApi = plexApi;
|
||||
|
@ -57,6 +60,8 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
EpisodeSync = epsiodeSync;
|
||||
Metadata = metadataRefresh;
|
||||
Checker = checker;
|
||||
Notification = hub;
|
||||
Plex.ClearCache();
|
||||
}
|
||||
|
||||
private ISettingsService<PlexSettings> Plex { get; }
|
||||
|
@ -66,17 +71,25 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
private IPlexEpisodeSync EpisodeSync { get; }
|
||||
private IRefreshMetadata Metadata { get; }
|
||||
private IPlexAvailabilityChecker Checker { get; }
|
||||
private IHubContext<NotificationHub> Notification { get; set; }
|
||||
|
||||
public async Task CacheContent(bool recentlyAddedSearch = false)
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
JobDataMap dataMap = context.JobDetail.JobDataMap;
|
||||
var recentlyAddedSearch = dataMap.GetBooleanValueFromString("recentlyAddedSearch");
|
||||
|
||||
var plexSettings = await Plex.GetSettingsAsync();
|
||||
if (!plexSettings.Enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await Notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, recentlyAddedSearch ? "Plex Recently Added Sync Started" : "Plex Content Sync Started");
|
||||
if (!ValidateSettings(plexSettings))
|
||||
{
|
||||
Logger.LogError("Plex Settings are not valid");
|
||||
await Notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, recentlyAddedSearch ? "Plex Recently Added Sync, Settings Not Valid" : "Plex Content, Settings Not Valid");
|
||||
return;
|
||||
}
|
||||
var processedContent = new ProcessedContent();
|
||||
|
@ -94,25 +107,35 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await Notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, recentlyAddedSearch ? "Plex Recently Added Sync Errored" : "Plex Content Sync Errored");
|
||||
Logger.LogWarning(LoggingEvents.PlexContentCacher, e, "Exception thrown when attempting to cache the Plex Content");
|
||||
}
|
||||
|
||||
if (!recentlyAddedSearch)
|
||||
{
|
||||
Logger.LogInformation("Starting EP Cacher");
|
||||
BackgroundJob.Enqueue(() => EpisodeSync.Start());
|
||||
|
||||
await OmbiQuartz.TriggerJob(nameof(IPlexEpisodeSync), "Plex");
|
||||
}
|
||||
|
||||
if ((processedContent?.HasProcessedContent ?? false) && recentlyAddedSearch)
|
||||
{
|
||||
// Just check what we send it
|
||||
BackgroundJob.Enqueue(() => Metadata.ProcessPlexServerContent(processedContent.Content));
|
||||
await OmbiQuartz.TriggerJob(nameof(IMediaDatabaseRefresh), "System");
|
||||
}
|
||||
|
||||
if ((processedContent?.HasProcessedEpisodes ?? false) && recentlyAddedSearch)
|
||||
{
|
||||
BackgroundJob.Enqueue(() => Checker.Start());
|
||||
|
||||
await OmbiQuartz.TriggerJob(nameof(IPlexAvailabilityChecker), "Plex");
|
||||
}
|
||||
|
||||
Logger.LogInformation("Finished Plex Content Cacher, with processed content: {0}, episodes: {0}", processedContent.Content.Count(), processedContent.Episodes.Count());
|
||||
|
||||
await Notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, recentlyAddedSearch ? "Plex Recently Added Sync Finished" : "Plex Content Sync Finished");
|
||||
|
||||
}
|
||||
|
||||
private async Task<ProcessedContent> StartTheCache(PlexSettings plexSettings, bool recentlyAddedSearch)
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Plex;
|
||||
|
@ -10,31 +11,34 @@ using Ombi.Api.Plex.Models;
|
|||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Plex
|
||||
{
|
||||
public class PlexEpisodeSync : IPlexEpisodeSync
|
||||
{
|
||||
public PlexEpisodeSync(ISettingsService<PlexSettings> s, ILogger<PlexEpisodeSync> log, IPlexApi plexApi,
|
||||
IPlexContentRepository repo, IPlexAvailabilityChecker a)
|
||||
IPlexContentRepository repo, IHubContext<NotificationHub> hub)
|
||||
{
|
||||
_settings = s;
|
||||
_log = log;
|
||||
_api = plexApi;
|
||||
_repo = repo;
|
||||
_availabilityChecker = a;
|
||||
_notification = hub;
|
||||
_settings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly ISettingsService<PlexSettings> _settings;
|
||||
private readonly ILogger<PlexEpisodeSync> _log;
|
||||
private readonly IPlexApi _api;
|
||||
private readonly IPlexContentRepository _repo;
|
||||
private readonly IPlexAvailabilityChecker _availabilityChecker;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -43,6 +47,8 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
{
|
||||
return;
|
||||
}
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Plex Episode Sync Started");
|
||||
|
||||
foreach (var server in s.Servers)
|
||||
{
|
||||
|
@ -52,10 +58,15 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Plex Episode Sync Failed");
|
||||
_log.LogError(LoggingEvents.Cacher, e, "Caching Episodes Failed");
|
||||
}
|
||||
|
||||
BackgroundJob.Enqueue(() => _availabilityChecker.Start());
|
||||
|
||||
await OmbiQuartz.TriggerJob(nameof(IPlexAvailabilityChecker), "Plex");
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Plex Episode Sync Finished");
|
||||
}
|
||||
|
||||
private async Task Cache(PlexServers settings)
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
//using System;
|
||||
//using System.Threading.Tasks;
|
||||
//using Hangfire;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Plex
|
||||
{
|
||||
public class PlexRecentlyAddedSync : IPlexRecentlyAddedSync
|
||||
{
|
||||
public PlexRecentlyAddedSync(IPlexContentSync sync)
|
||||
{
|
||||
_sync = sync;
|
||||
}
|
||||
//namespace Ombi.Schedule.Jobs.Plex
|
||||
//{
|
||||
// public class PlexRecentlyAddedSync : IPlexRecentlyAddedSync
|
||||
// {
|
||||
// public PlexRecentlyAddedSync(IPlexContentSync sync)
|
||||
// {
|
||||
// _sync = sync;
|
||||
// }
|
||||
|
||||
private readonly IPlexContentSync _sync;
|
||||
// private readonly IPlexContentSync _sync;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
BackgroundJob.Enqueue(() => _sync.CacheContent(true));
|
||||
}
|
||||
// public void Start()
|
||||
// {
|
||||
// BackgroundJob.Enqueue(() => _sync.CacheContent(true));
|
||||
// }
|
||||
|
||||
private bool _disposed;
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
// private bool _disposed;
|
||||
// protected virtual void Dispose(bool disposing)
|
||||
// {
|
||||
// if (_disposed)
|
||||
// return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_sync?.Dispose();
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
// if (disposing)
|
||||
// {
|
||||
// _sync?.Dispose();
|
||||
// }
|
||||
// _disposed = true;
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
// public void Dispose()
|
||||
// {
|
||||
// Dispose(true);
|
||||
// GC.SuppressFinalize(this);
|
||||
// }
|
||||
// }
|
||||
//}
|
|
@ -3,27 +3,33 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Plex;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Hubs;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Plex
|
||||
{
|
||||
public class PlexUserImporter : IPlexUserImporter
|
||||
{
|
||||
public PlexUserImporter(IPlexApi api, UserManager<OmbiUser> um, ILogger<PlexUserImporter> log,
|
||||
ISettingsService<PlexSettings> plexSettings, ISettingsService<UserManagementSettings> ums)
|
||||
ISettingsService<PlexSettings> plexSettings, ISettingsService<UserManagementSettings> ums, IHubContext<NotificationHub> hub)
|
||||
{
|
||||
_api = api;
|
||||
_userManager = um;
|
||||
_log = log;
|
||||
_plexSettings = plexSettings;
|
||||
_userManagementSettings = ums;
|
||||
_notification = hub;
|
||||
_plexSettings.ClearCache();
|
||||
_userManagementSettings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly IPlexApi _api;
|
||||
|
@ -31,9 +37,10 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
private readonly ILogger<PlexUserImporter> _log;
|
||||
private readonly ISettingsService<PlexSettings> _plexSettings;
|
||||
private readonly ISettingsService<UserManagementSettings> _userManagementSettings;
|
||||
private readonly IHubContext<NotificationHub> _notification;
|
||||
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
var userManagementSettings = await _userManagementSettings.GetSettingsAsync();
|
||||
if (!userManagementSettings.ImportPlexUsers)
|
||||
|
@ -47,6 +54,8 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
}
|
||||
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Plex User Importer Started");
|
||||
var allUsers = await _userManager.Users.Where(x => x.UserType == UserType.PlexUser).ToListAsync();
|
||||
foreach (var server in settings.Servers)
|
||||
{
|
||||
|
@ -118,6 +127,9 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Plex User Importer Finished");
|
||||
}
|
||||
|
||||
private async Task ImportAdmin(UserManagementSettings settings, PlexServers server, List<OmbiUser> allUsers)
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace Ombi.Schedule.Jobs.Radarr
|
|||
{
|
||||
public interface IRadarrSync : IBaseJob
|
||||
{
|
||||
Task CacheContent();
|
||||
Task<IEnumerable<RadarrCache>> GetCachedContent();
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ using Ombi.Helpers;
|
|||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz;
|
||||
using Serilog;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Radarr
|
||||
|
@ -22,6 +23,7 @@ namespace Ombi.Schedule.Jobs.Radarr
|
|||
RadarrApi = radarrApi;
|
||||
Logger = log;
|
||||
_ctx = ctx;
|
||||
RadarrSettings.ClearCache();
|
||||
}
|
||||
|
||||
private ISettingsService<RadarrSettings> RadarrSettings { get; }
|
||||
|
@ -31,7 +33,7 @@ namespace Ombi.Schedule.Jobs.Radarr
|
|||
|
||||
private static readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
|
||||
public async Task CacheContent()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
await SemaphoreSlim.WaitAsync();
|
||||
try
|
||||
|
|
|
@ -4,6 +4,5 @@ namespace Ombi.Schedule.Jobs.SickRage
|
|||
{
|
||||
public interface ISickRageSync : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ using Ombi.Helpers;
|
|||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.SickRage
|
||||
{
|
||||
|
@ -22,6 +23,7 @@ namespace Ombi.Schedule.Jobs.SickRage
|
|||
_api = api;
|
||||
_log = l;
|
||||
_ctx = ctx;
|
||||
_settings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly ISettingsService<SickRageSettings> _settings;
|
||||
|
@ -29,7 +31,7 @@ namespace Ombi.Schedule.Jobs.SickRage
|
|||
private readonly ILogger<SickRageSync> _log;
|
||||
private readonly IExternalContext _ctx;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -4,6 +4,5 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
{
|
||||
public interface ISonarrSync : IBaseJob
|
||||
{
|
||||
Task Start();
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ using Ombi.Helpers;
|
|||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Sonarr
|
||||
{
|
||||
|
@ -25,6 +26,7 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
_api = api;
|
||||
_log = l;
|
||||
_ctx = ctx;
|
||||
_settings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly ISettingsService<SonarrSettings> _settings;
|
||||
|
@ -32,7 +34,7 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
private readonly ILogger<SonarrSync> _log;
|
||||
private readonly IExternalContext _ctx;
|
||||
|
||||
public async Task Start()
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -10,12 +10,13 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="1.50.2" />
|
||||
<PackageReference Include="Hangfire" Version="1.7.0" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.0" />
|
||||
<PackageReference Include="Hangfire.Console" Version="1.4.2" />
|
||||
<PackageReference Include="Hangfire" Version="1.7.1" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.1" />
|
||||
<PackageReference Include="Hangfire.Console" Version="1.3.10" />
|
||||
<PackageReference Include="Hangfire.MemoryStorage.Core" Version="1.4.0" />
|
||||
<PackageReference Include="Hangfire.RecurringJobExtensions" Version="1.1.6" />
|
||||
<PackageReference Include="Hangfire.SQLite" Version="1.4.2" />
|
||||
<PackageReference Include="Quartz" Version="3.0.7" />
|
||||
<PackageReference Include="Serilog" Version="2.8.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.18.2" />
|
||||
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
||||
|
@ -35,9 +36,16 @@
|
|||
<ProjectReference Include="..\Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Hubs\Ombi.Hubs.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Notifications\Ombi.Notifications.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Settings\Ombi.Settings.csproj" />
|
||||
<ProjectReference Include="..\Ombi.TheMovieDbApi\Ombi.Api.TheMovieDb.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AspNetCore.SignalR.Core">
|
||||
<HintPath>..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.signalr.core\1.1.0\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Core.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
87
src/Ombi.Schedule/OmbiQuartz.cs
Normal file
87
src/Ombi.Schedule/OmbiQuartz.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Helpers;
|
||||
using Quartz;
|
||||
using Quartz.Impl;
|
||||
using Quartz.Spi;
|
||||
|
||||
namespace Ombi.Schedule
|
||||
{
|
||||
public class OmbiQuartz
|
||||
{
|
||||
protected IScheduler _scheduler { get; set; }
|
||||
|
||||
public static IScheduler Scheduler => Instance._scheduler;
|
||||
|
||||
// Singleton
|
||||
protected static OmbiQuartz _instance;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton
|
||||
/// </summary>
|
||||
public static OmbiQuartz Instance => _instance ?? (_instance = new OmbiQuartz());
|
||||
|
||||
protected OmbiQuartz()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
private async void Init()
|
||||
{
|
||||
_scheduler = await new StdSchedulerFactory().GetScheduler();
|
||||
}
|
||||
|
||||
public IScheduler UseJobFactory(IJobFactory jobFactory)
|
||||
{
|
||||
Scheduler.JobFactory = jobFactory;
|
||||
return Scheduler;
|
||||
}
|
||||
|
||||
public async Task AddJob<T>(string name, string group, string cronExpression, Dictionary<string, string> jobData = null)
|
||||
where T : IJob
|
||||
{
|
||||
var jobBuilder = JobBuilder.Create<T>()
|
||||
.WithIdentity(new JobKey(name, group));
|
||||
if (jobData != null)
|
||||
{
|
||||
foreach (var o in jobData)
|
||||
{
|
||||
jobBuilder.UsingJobData(o.Key, o.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if(!cronExpression.HasValue())
|
||||
{
|
||||
jobBuilder.StoreDurably(true);
|
||||
}
|
||||
|
||||
var job = jobBuilder.Build();
|
||||
if (cronExpression.HasValue())
|
||||
{
|
||||
ITrigger jobTrigger = TriggerBuilder.Create()
|
||||
.WithIdentity(name + "Trigger", group)
|
||||
.WithCronSchedule(cronExpression,
|
||||
x => x.WithMisfireHandlingInstructionFireAndProceed())
|
||||
.ForJob(name, group)
|
||||
.StartNow()
|
||||
.Build();
|
||||
await Scheduler.ScheduleJob(job, jobTrigger);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Scheduler.AddJob(job, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static async Task TriggerJob(string jobName, string group)
|
||||
{
|
||||
await Scheduler.TriggerJob(new JobKey(jobName, group));
|
||||
}
|
||||
|
||||
public static async Task Start()
|
||||
{
|
||||
await Scheduler.Start();
|
||||
}
|
||||
}
|
||||
}
|
99
src/Ombi.Schedule/OmbiScheduler.cs
Normal file
99
src/Ombi.Schedule/OmbiScheduler.cs
Normal file
|
@ -0,0 +1,99 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Schedule.Jobs;
|
||||
using Ombi.Schedule.Jobs.Couchpotato;
|
||||
using Ombi.Schedule.Jobs.Emby;
|
||||
using Ombi.Schedule.Jobs.Lidarr;
|
||||
using Ombi.Schedule.Jobs.Ombi;
|
||||
using Ombi.Schedule.Jobs.Plex;
|
||||
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
||||
using Ombi.Schedule.Jobs.Radarr;
|
||||
using Ombi.Schedule.Jobs.SickRage;
|
||||
using Ombi.Schedule.Jobs.Sonarr;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Quartz;
|
||||
using Quartz.Spi;
|
||||
|
||||
namespace Ombi.Schedule
|
||||
{
|
||||
public static class OmbiScheduler
|
||||
{
|
||||
//public void Setup()
|
||||
//{
|
||||
// CreateJobDefinitions();
|
||||
//}
|
||||
|
||||
//public void CreateJobDefinitions()
|
||||
//{
|
||||
// var contentSync = JobBuilder.Create<PlexContentSync>()
|
||||
// .UsingJobData("recentlyAddedSearch", false)
|
||||
// .WithIdentity(nameof(PlexContentSync), "Plex")
|
||||
// .Build();
|
||||
|
||||
// var recentlyAdded = JobBuilder.Create<PlexContentSync>()
|
||||
// .UsingJobData("recentlyAddedSearch", true)
|
||||
// .WithIdentity("PlexRecentlyAdded", "Plex")
|
||||
// .Build();
|
||||
//}
|
||||
|
||||
public static async Task UseQuartz(this IApplicationBuilder app)
|
||||
{
|
||||
// Job Factory through IOC container
|
||||
var jobFactory = (IJobFactory)app.ApplicationServices.GetService(typeof(IJobFactory));
|
||||
var service = (ISettingsService<JobSettings>)app.ApplicationServices.GetService(typeof(ISettingsService<JobSettings>));
|
||||
var s = service.GetSettings();
|
||||
// Set job factory
|
||||
OmbiQuartz.Instance.UseJobFactory(jobFactory);
|
||||
|
||||
// Run configuration
|
||||
await AddPlex(s);
|
||||
await AddEmby(s);
|
||||
await AddDvrApps(s);
|
||||
await AddSystem(s);
|
||||
|
||||
// Run Quartz
|
||||
await OmbiQuartz.Start();
|
||||
}
|
||||
|
||||
private static async Task AddSystem(JobSettings s)
|
||||
{
|
||||
await OmbiQuartz.Instance.AddJob<IRefreshMetadata>(nameof(IRefreshMetadata), "System", JobSettingsHelper.RefreshMetadata(s));
|
||||
await OmbiQuartz.Instance.AddJob<IIssuesPurge>(nameof(IIssuesPurge), "System", JobSettingsHelper.IssuePurge(s));
|
||||
//OmbiQuartz.Instance.AddJob<IOmbiAutomaticUpdater>(nameof(IOmbiAutomaticUpdater), "System", JobSettingsHelper.Updater(s));
|
||||
await OmbiQuartz.Instance.AddJob<INewsletterJob>(nameof(INewsletterJob), "System", JobSettingsHelper.Newsletter(s));
|
||||
await OmbiQuartz.Instance.AddJob<IResendFailedRequests>(nameof(IResendFailedRequests), "System", JobSettingsHelper.ResendFailedRequests(s));
|
||||
await OmbiQuartz.Instance.AddJob<IMediaDatabaseRefresh>(nameof(IMediaDatabaseRefresh), "System", JobSettingsHelper.MediaDatabaseRefresh(s));
|
||||
}
|
||||
|
||||
private static async Task AddDvrApps(JobSettings s)
|
||||
{
|
||||
await OmbiQuartz.Instance.AddJob<ISonarrSync>(nameof(ISonarrSync), "DVR", JobSettingsHelper.Sonarr(s));
|
||||
await OmbiQuartz.Instance.AddJob<IRadarrSync>(nameof(IRadarrSync), "DVR", JobSettingsHelper.Radarr(s));
|
||||
await OmbiQuartz.Instance.AddJob<ICouchPotatoSync>(nameof(ICouchPotatoSync), "DVR", JobSettingsHelper.CouchPotato(s));
|
||||
await OmbiQuartz.Instance.AddJob<ISickRageSync>(nameof(ISickRageSync), "DVR", JobSettingsHelper.SickRageSync(s));
|
||||
await OmbiQuartz.Instance.AddJob<ILidarrArtistSync>(nameof(ILidarrArtistSync), "DVR", JobSettingsHelper.LidarrArtistSync(s));
|
||||
await OmbiQuartz.Instance.AddJob<ILidarrAlbumSync>(nameof(ILidarrAlbumSync), "DVR", null);
|
||||
await OmbiQuartz.Instance.AddJob<ILidarrAvailabilityChecker>(nameof(ILidarrAvailabilityChecker), "DVR", null);
|
||||
}
|
||||
|
||||
private static async Task AddPlex(JobSettings s)
|
||||
{
|
||||
await OmbiQuartz.Instance.AddJob<IPlexContentSync>(nameof(IPlexContentSync), "Plex", JobSettingsHelper.PlexContent(s), new Dictionary<string, string> { { "recentlyAddedSearch", "false" } });
|
||||
await OmbiQuartz.Instance.AddJob<IPlexContentSync>(nameof(IPlexContentSync) + "RecentlyAdded", "Plex", JobSettingsHelper.PlexRecentlyAdded(s), new Dictionary<string, string> { { "recentlyAddedSearch", "true" } });
|
||||
await OmbiQuartz.Instance.AddJob<IPlexUserImporter>(nameof(IPlexUserImporter), "Plex", JobSettingsHelper.UserImporter(s));
|
||||
await OmbiQuartz.Instance.AddJob<IPlexEpisodeSync>(nameof(IPlexEpisodeSync), "Plex", null);
|
||||
await OmbiQuartz.Instance.AddJob<IPlexAvailabilityChecker>(nameof(IPlexAvailabilityChecker), "Plex", null);
|
||||
}
|
||||
|
||||
private static async Task AddEmby(JobSettings s)
|
||||
{
|
||||
await OmbiQuartz.Instance.AddJob<IEmbyContentSync>(nameof(IEmbyContentSync), "Emby", JobSettingsHelper.EmbyContent(s));
|
||||
await OmbiQuartz.Instance.AddJob<IEmbyEpisodeSync>(nameof(IEmbyEpisodeSync), "Emby", null);
|
||||
await OmbiQuartz.Instance.AddJob<IEmbyAvaliabilityChecker>(nameof(IEmbyAvaliabilityChecker), "Emby", null);
|
||||
await OmbiQuartz.Instance.AddJob<IEmbyUserImporter>(nameof(IEmbyUserImporter), "Emby", JobSettingsHelper.UserImporter(s));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
|
||||
<PackageReference Include="Quartz" Version="3.0.7" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using Ombi.Helpers;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Settings.Settings.Models
|
||||
{
|
||||
|
@ -7,71 +8,93 @@ namespace Ombi.Settings.Settings.Models
|
|||
{
|
||||
public static string Radarr(JobSettings s)
|
||||
{
|
||||
return Get(s.RadarrSync, Cron.Hourly(15));
|
||||
return ValidateCron(Get(s.RadarrSync, Cron.Hourly(15)));
|
||||
}
|
||||
|
||||
public static string Sonarr(JobSettings s)
|
||||
{
|
||||
return Get(s.SonarrSync, Cron.Hourly(10));
|
||||
return ValidateCron(Get(s.SonarrSync, Cron.Hourly(10)));
|
||||
}
|
||||
|
||||
public static string EmbyContent(JobSettings s)
|
||||
{
|
||||
return Get(s.EmbyContentSync, Cron.Hourly(5));
|
||||
return ValidateCron(Get(s.EmbyContentSync, Cron.Hourly(5)));
|
||||
}
|
||||
|
||||
public static string PlexContent(JobSettings s)
|
||||
{
|
||||
return Get(s.PlexContentSync, Cron.Daily(2));
|
||||
return ValidateCron(Get(s.PlexContentSync, Cron.Daily(2)));
|
||||
}
|
||||
|
||||
public static string PlexRecentlyAdded(JobSettings s)
|
||||
{
|
||||
return Get(s.PlexRecentlyAddedSync, Cron.MinuteInterval(30));
|
||||
return ValidateCron(Get(s.PlexRecentlyAddedSync, Cron.MinuteInterval(30)));
|
||||
}
|
||||
|
||||
public static string CouchPotato(JobSettings s)
|
||||
{
|
||||
return Get(s.CouchPotatoSync, Cron.Hourly(30));
|
||||
return ValidateCron(Get(s.CouchPotatoSync, Cron.Hourly(30)));
|
||||
}
|
||||
|
||||
public static string Updater(JobSettings s)
|
||||
{
|
||||
return Get(s.AutomaticUpdater, Cron.HourInterval(6));
|
||||
return ValidateCron(Get(s.AutomaticUpdater, Cron.HourInterval(6)));
|
||||
}
|
||||
|
||||
public static string UserImporter(JobSettings s)
|
||||
{
|
||||
return Get(s.UserImporter, Cron.Daily());
|
||||
return ValidateCron(Get(s.UserImporter, Cron.Daily()));
|
||||
}
|
||||
|
||||
public static string Newsletter(JobSettings s)
|
||||
{
|
||||
return Get(s.Newsletter, Cron.Weekly(DayOfWeek.Friday, 12));
|
||||
return ValidateCron(Get(s.Newsletter, Cron.Weekly(Helpers.DayOfWeek.Friday, 12)));
|
||||
}
|
||||
|
||||
public static string SickRageSync(JobSettings s)
|
||||
{
|
||||
return Get(s.SickRageSync, Cron.Hourly(35));
|
||||
return ValidateCron(Get(s.SickRageSync, Cron.Hourly(35)));
|
||||
}
|
||||
|
||||
public static string RefreshMetadata(JobSettings s)
|
||||
{
|
||||
return Get(s.RefreshMetadata, Cron.DayInterval(3));
|
||||
return ValidateCron(Get(s.RefreshMetadata, Cron.DayInterval(3)));
|
||||
}
|
||||
|
||||
public static string LidarrArtistSync(JobSettings s)
|
||||
{
|
||||
return Get(s.LidarrArtistSync, Cron.Hourly(40));
|
||||
return ValidateCron(Get(s.LidarrArtistSync, Cron.Hourly(40)));
|
||||
}
|
||||
|
||||
public static string IssuePurge(JobSettings s)
|
||||
{
|
||||
return Get(s.IssuesPurge, Cron.Daily());
|
||||
return ValidateCron(Get(s.IssuesPurge, Cron.Daily()));
|
||||
}
|
||||
|
||||
public static string ResendFailedRequests(JobSettings s)
|
||||
{
|
||||
return Get(s.RetryRequests, Cron.Daily(6));
|
||||
return ValidateCron(Get(s.RetryRequests, Cron.Daily(6)));
|
||||
}
|
||||
|
||||
public static string MediaDatabaseRefresh(JobSettings s)
|
||||
{
|
||||
return Get(s.MediaDatabaseRefresh, Cron.DayInterval(5));
|
||||
return ValidateCron(Get(s.MediaDatabaseRefresh, Cron.DayInterval(5)));
|
||||
}
|
||||
|
||||
private static string Get(string settings, string defaultCron)
|
||||
{
|
||||
return settings.HasValue() ? settings : defaultCron;
|
||||
}
|
||||
|
||||
private const string _defaultCron = "0 0 12 1/1 * ? *";
|
||||
|
||||
private static string ValidateCron(string cron)
|
||||
{
|
||||
if (CronExpression.IsValidExpression(cron))
|
||||
{
|
||||
return cron;
|
||||
}
|
||||
return _defaultCron;
|
||||
}
|
||||
}
|
||||
}
|
50
src/Ombi.Store/Migrations/Settings/20190416204533_ResetSchedules.Designer.cs
generated
Normal file
50
src/Ombi.Store/Migrations/Settings/20190416204533_ResetSchedules.Designer.cs
generated
Normal file
|
@ -0,0 +1,50 @@
|
|||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Ombi.Store.Context;
|
||||
|
||||
namespace Ombi.Store.Migrations.Settings
|
||||
{
|
||||
[DbContext(typeof(SettingsContext))]
|
||||
[Migration("20190416204533_ResetSchedules")]
|
||||
partial class ResetSchedules
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.2.2-servicing-10034");
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ApplicationConfiguration");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Content");
|
||||
|
||||
b.Property<string>("SettingsName");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("GlobalSettings");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ombi.Store.Migrations.Settings
|
||||
{
|
||||
public partial class ResetSchedules : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql(@"
|
||||
DELETE FROM GlobalSettings
|
||||
WHERE SettingsName = 'JobSettings'
|
||||
");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ namespace Ombi.Store.Migrations.Settings
|
|||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");
|
||||
.HasAnnotation("ProductVersion", "2.2.2-servicing-10034");
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
|
@ -10,6 +10,7 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.2.0" />
|
||||
<PackageReference Include="Moq" Version="4.10.0" />
|
||||
<PackageReference Include="Nunit" Version="3.11.0" />
|
||||
<PackageReference Include="Hangfire" Version="1.7.1" />
|
||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="16.0.1"></packagereference>
|
||||
|
|
|
@ -104,6 +104,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Settings.Tests", "Ombi
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Test.Common", "Ombi.Test.Common\Ombi.Test.Common.csproj", "{27111E7C-748E-4996-BD71-2117027C6460}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Hubs", "Ombi.Hubs\Ombi.Hubs.csproj", "{67416CC5-13B2-44BB-98CE-39DA93D6F70E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -274,6 +276,10 @@ Global
|
|||
{27111E7C-748E-4996-BD71-2117027C6460}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{27111E7C-748E-4996-BD71-2117027C6460}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{27111E7C-748E-4996-BD71-2117027C6460}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{67416CC5-13B2-44BB-98CE-39DA93D6F70E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{67416CC5-13B2-44BB-98CE-39DA93D6F70E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{67416CC5-13B2-44BB-98CE-39DA93D6F70E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{67416CC5-13B2-44BB-98CE-39DA93D6F70E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -7,10 +7,14 @@ import { AuthService } from "./auth/auth.service";
|
|||
import { ILocalUser } from "./auth/IUserLogin";
|
||||
import { IdentityService, NotificationService, CustomPageService } from "./services";
|
||||
import { JobService, SettingsService } from "./services";
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
|
||||
import { ICustomizationSettings, ICustomPage } from "./interfaces";
|
||||
import { StorageService } from './shared/storage/storage-service';
|
||||
|
||||
import { SignalRNotificationService } from './services/signlarnotification.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: "app-ombi",
|
||||
templateUrl: "./app.component.html",
|
||||
|
@ -32,6 +36,7 @@ export class AppComponent implements OnInit {
|
|||
public username: string;
|
||||
|
||||
private checkedForUpdate: boolean;
|
||||
private hubConnected: boolean;
|
||||
|
||||
|
||||
@HostBinding('class') public componentCssClass;
|
||||
|
@ -45,7 +50,9 @@ export class AppComponent implements OnInit {
|
|||
private readonly identityService: IdentityService,
|
||||
private readonly customPageService: CustomPageService,
|
||||
public overlayContainer: OverlayContainer,
|
||||
private storage: StorageService) {
|
||||
private storage: StorageService,
|
||||
private signalrNotification: SignalRNotificationService,
|
||||
private readonly snackBar: MatSnackBar) {
|
||||
|
||||
// const base = this.platformLocation.getBaseHrefFromDOM();
|
||||
// if (base.length > 1) {
|
||||
|
@ -109,6 +116,17 @@ export class AppComponent implements OnInit {
|
|||
},
|
||||
err => this.checkedForUpdate = true);
|
||||
}
|
||||
|
||||
if (this.authService.loggedIn() && !this.hubConnected) {
|
||||
this.signalrNotification.initialize();
|
||||
this.hubConnected = true;
|
||||
|
||||
this.signalrNotification.Notification.subscribe(data => {
|
||||
this.snackBar.open(data, "OK", {
|
||||
duration: 3000
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
|||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { JwtModule } from "@auth0/angular-jwt";
|
||||
|
||||
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { TranslateLoader, TranslateModule } from "@ngx-translate/core";
|
||||
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
|
||||
|
@ -53,6 +52,7 @@ import { NavSearchComponent } from "./my-nav/nav-search.component";
|
|||
import { OverlayModule } from "@angular/cdk/overlay";
|
||||
import { getBaseLocation } from "./shared/functions/common-functions";
|
||||
import { StorageService } from "./shared/storage/storage-service";
|
||||
import { SignalRNotificationService } from "./services/signlarnotification.service";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "*", component: PageNotFoundComponent },
|
||||
|
@ -114,6 +114,7 @@ export function JwtTokenGetter() {
|
|||
MatSnackBarModule,
|
||||
SharedModule,
|
||||
NgxEditorModule,
|
||||
MatSnackBarModule,
|
||||
DialogModule,
|
||||
MatButtonModule,
|
||||
NavbarModule,
|
||||
|
@ -179,6 +180,7 @@ export function JwtTokenGetter() {
|
|||
SearchV2Service,
|
||||
MessageService,
|
||||
StorageService,
|
||||
SignalRNotificationService,
|
||||
{ provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' }
|
||||
// {
|
||||
// provide: APP_BASE_HREF,
|
||||
|
|
|
@ -28,6 +28,10 @@ export class AuthService extends ServiceHelpers {
|
|||
return this.http.post<boolean>(`${this.url}/requirePassword`, JSON.stringify(login), { headers: this.headers });
|
||||
}
|
||||
|
||||
public getToken() {
|
||||
return this.jwtHelperService.tokenGetter();
|
||||
}
|
||||
|
||||
public loggedIn() {
|
||||
const token: string = this.jwtHelperService.tokenGetter();
|
||||
|
||||
|
|
|
@ -222,7 +222,6 @@ export interface IIssueCategory extends ISettings {
|
|||
export interface ICronTestModel {
|
||||
success: boolean;
|
||||
message: string;
|
||||
schedule: Date[];
|
||||
}
|
||||
|
||||
export interface ICronViewModelBody {
|
||||
|
|
|
@ -92,11 +92,10 @@ export class MusicRequestsComponent implements OnInit {
|
|||
this.searchChanged.next(text.target.value);
|
||||
}
|
||||
|
||||
public removeRequest(request: IAlbumRequest) {
|
||||
this.requestService.removeAlbumRequest(request).subscribe(x => {
|
||||
this.removeRequestFromUi(request);
|
||||
this.loadRequests(this.amountToLoad, this.currentlyLoaded = 0);
|
||||
});
|
||||
public async removeRequest(request: IAlbumRequest) {
|
||||
await this.requestService.removeAlbumRequest(request).toPromise();
|
||||
this.removeRequestFromUi(request);
|
||||
this.loadRequests(this.amountToLoad, this.currentlyLoaded = 0);
|
||||
}
|
||||
|
||||
public changeAvailability(request: IAlbumRequest, available: boolean) {
|
||||
|
@ -337,7 +336,7 @@ export class MusicRequestsComponent implements OnInit {
|
|||
}
|
||||
private setAlbumBackground(req: IAlbumRequest) {
|
||||
if (req.disk === null) {
|
||||
if(req.cover === null) {
|
||||
if (req.cover === null) {
|
||||
req.disk = this.defaultPoster;
|
||||
} else {
|
||||
req.disk = req.cover;
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
|
||||
|
||||
|
||||
<!-- Movie tab -->
|
||||
<div role="tabpanel" class="tab-pane active" id="MoviesTab">
|
||||
|
||||
<div class="input-group search-bar-background">
|
||||
<input id="search" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons"
|
||||
<input id="search" type="text" placeholder="{{ 'Search.SearchBarPlaceholder' | translate}}" class="form-control form-control-custom form-control-search form-control-withbuttons"
|
||||
(keyup)="search($event)">
|
||||
<div class="input-group-addon right-radius">
|
||||
<div class="btn-group" role="group">
|
||||
|
@ -27,7 +25,7 @@
|
|||
<i class="fa fa-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Refine search options -->
|
||||
<div class="row top-spacing form-group vcenter" *ngIf="refineSearchEnabled">
|
||||
<div class="col-md-1">
|
||||
<div class="form-group">
|
||||
|
@ -37,6 +35,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <label for="name" class="col-xs-2 col-md-1">Language:</label> -->
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label for="select" class="control-label">Language</label>
|
||||
|
@ -64,6 +63,7 @@
|
|||
|
||||
<remaining-requests [movie]="true" [quotaRefreshEvents]="movieRequested.asObservable()" #remainingFilms></remaining-requests>
|
||||
|
||||
<!-- Movie content -->
|
||||
<div id="movieList">
|
||||
<div *ngIf="searchApplied && movieResults?.length <= 0" class='no-search-results'>
|
||||
<i class='fa fa-film no-search-results-icon'></i>
|
||||
|
@ -101,10 +101,10 @@
|
|||
class="label label-info" [translate]="'Search.Movies.Trailer'"></span></a>
|
||||
<span *ngIf="result.quality" id="qualityLabel" class="label label-success">{{result.quality}}p</span>
|
||||
|
||||
<ng-template [ngIf]="result.available">
|
||||
<span class="label label-success" id="availableLabel" [translate]="'Common.Available'"></span></ng-template>
|
||||
<ng-template [ngIf]="result.approved && !result.available">
|
||||
<span class="label label-info" id="processingRequestLabel" [translate]="'Common.ProcessingRequest'"></span></ng-template>
|
||||
<ng-template [ngIf]="result.available"><span class="label label-success" id="availableLabel"
|
||||
[translate]="'Common.Available'"></span></ng-template>
|
||||
<ng-template [ngIf]="result.approved && !result.available"><span class="label label-info"
|
||||
id="processingRequestLabel" [translate]="'Common.ProcessingRequest'"></span></ng-template>
|
||||
<ng-template [ngIf]="result.requested && !result.approved && !result.available"><span class="label label-warning"
|
||||
id="pendingApprovalLabel" [translate]="'Common.PendingApproval'"></span></ng-template>
|
||||
<ng-template [ngIf]="!result.requested && !result.available && !result.approved"><span
|
||||
|
@ -181,4 +181,4 @@
|
|||
|
||||
|
||||
<issue-report [movie]="true" [visible]="issuesBarVisible" (visibleChange)="issuesBarVisible = $event;" [title]="issueRequestTitle"
|
||||
[issueCategory]="issueCategorySelected" [id]="issueRequestId" [providerId]="issueProviderId"></issue-report>
|
||||
[issueCategory]="issueCategorySelected" [id]="issueRequestId" [providerId]="issueProviderId"></issue-report>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!-- Movie tab -->
|
||||
<div role="tabpanel" class="tab-pane active" id="MoviesTab">
|
||||
<div class="input-group">
|
||||
<input id="search" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons" (keyup)="search($event)">
|
||||
<input id="search" type="text" placeholder="{{ 'Search.SearchBarPlaceholder' | translate }}" class="form-control form-control-custom form-control-search form-control-withbuttons" (keyup)="search($event)">
|
||||
<div class="input-group-addon right-radius">
|
||||
<i class="fa fa-search"></i>
|
||||
</div>
|
||||
|
@ -49,4 +49,4 @@
|
|||
|
||||
|
||||
<issue-report [movie]="true" [visible]="issuesBarVisible" (visibleChange)="issuesBarVisible = $event;" [title]="issueRequestTitle"
|
||||
[issueCategory]="issueCategorySelected" [id]="issueRequestId" [providerId]="issueProviderId"></issue-report>
|
||||
[issueCategory]="issueCategorySelected" [id]="issueRequestId" [providerId]="issueProviderId"></issue-report>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<!-- Nav tabs -->
|
||||
|
||||
|
||||
<ul id="nav-tabs" class="nav nav-tabs" role="tablist">
|
||||
<ul id="nav-tabs" class="nav nav-tabs nav-justified" role="tablist">
|
||||
|
||||
<li role="presentation" class="active">
|
||||
<a id="movieTabButton" href="#MoviesTab" aria-controls="home" role="tab" data-toggle="tab" (click)="selectMovieTab()"><i class="fa fa-film"></i> {{ 'Search.MoviesTab' | translate }}</a>
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.search-bar-background {
|
||||
background-color: #333333;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!-- Movie tab -->
|
||||
<div role="tabpanel" class="tab-pane" id="TvShowTab">
|
||||
<div class="input-group">
|
||||
<input id="search" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons" (keyup)="search($event)">
|
||||
<input id="search" type="text" placeholder="{{ 'Search.SearchBarPlaceholder' | translate }}" class="form-control form-control-custom form-control-search form-control-withbuttons" (keyup)="search($event)">
|
||||
<div class="input-group-addon right-radius">
|
||||
<div class="btn-group">
|
||||
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
|
@ -164,4 +164,4 @@
|
|||
|
||||
|
||||
<issue-report [movie]="false" [visible]="issuesBarVisible" (visibleChange)="issuesBarVisible = $event;" [title]="issueRequestTitle"
|
||||
[issueCategory]="issueCategorySelected" [id]="issueRequestId" [providerId]="issueProviderId"></issue-report>
|
||||
[issueCategory]="issueCategorySelected" [id]="issueRequestId" [providerId]="issueProviderId"></issue-report>
|
||||
|
|
|
@ -186,7 +186,7 @@ export class RequestService extends ServiceHelpers {
|
|||
}
|
||||
|
||||
public removeAlbumRequest(request: IAlbumRequest): any {
|
||||
this.http.delete(`${this.url}music/${request.id}`, {headers: this.headers}).subscribe();
|
||||
return this.http.delete(`${this.url}music/${request.id}`, {headers: this.headers});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import { Injectable, EventEmitter } from '@angular/core';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
|
||||
import { HubConnection } from '@aspnet/signalr';
|
||||
import * as signalR from '@aspnet/signalr';
|
||||
|
||||
@Injectable()
|
||||
export class SignalRNotificationService {
|
||||
|
||||
private hubConnection: HubConnection | undefined;
|
||||
public Notification: EventEmitter<any>;
|
||||
|
||||
constructor(private authService: AuthService) {
|
||||
this.Notification = new EventEmitter<any>();
|
||||
}
|
||||
|
||||
public initialize(): void {
|
||||
|
||||
this.stopConnection();
|
||||
|
||||
this.hubConnection = new signalR.HubConnectionBuilder().withUrl("/hubs/notification", {
|
||||
accessTokenFactory: () => {
|
||||
return this.authService.getToken();
|
||||
}
|
||||
}).configureLogging(signalR.LogLevel.Information).build();
|
||||
|
||||
|
||||
this.hubConnection.on("Notification", (data: any) => {
|
||||
debugger;
|
||||
this.Notification.emit(data);
|
||||
});
|
||||
|
||||
|
||||
this.hubConnection.start().then((data: any) => {
|
||||
console.log('Now connected');
|
||||
}).catch((error: any) => {
|
||||
console.log('Could not connect ' + error);
|
||||
setTimeout(() => this.initialize(), 3000);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
stopConnection() {
|
||||
if (this.hubConnection) {
|
||||
this.hubConnection.stop();
|
||||
this.hubConnection = null;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -7,7 +7,8 @@
|
|||
<legend>Job Settings</legend>
|
||||
<form novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)" style="padding-top:5%;">
|
||||
<div class="col-md-6">
|
||||
<small>Changes to any of the below requires you to restart Ombi.</small>
|
||||
<small>Changes to any of the below requires you to restart Ombi. </small>
|
||||
<small>You can generate valid CRON Expressions here: <a href="http://www.cronmaker.com/" target="_blank">http://www.cronmaker.com/</a></small>
|
||||
<div class="form-group">
|
||||
<label for="sonarrSync" class="control-label">Sonarr Sync</label>
|
||||
<input type="text" class="form-control form-control-custom" [ngClass]="{'form-error': form.get('sonarrSync').hasError('required')}" id="sonarrSync" name="sonarrSync" formControlName="sonarrSync">
|
||||
|
@ -121,9 +122,3 @@
|
|||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<p-dialog header="CRON Schedule" [(visible)]="displayTest">
|
||||
<ul *ngIf="testModel">
|
||||
<li *ngFor="let item of testModel.schedule">{{item | date:'short'}}</li>
|
||||
</ul>
|
||||
</p-dialog>
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
import { NotificationService, SettingsService } from "../../services";
|
||||
|
||||
import { ICronTestModel } from "../../interfaces";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./jobs.component.html",
|
||||
})
|
||||
|
@ -13,8 +11,6 @@ export class JobsComponent implements OnInit {
|
|||
public form: FormGroup;
|
||||
|
||||
public profilesRunning: boolean;
|
||||
public testModel: ICronTestModel;
|
||||
public displayTest: boolean;
|
||||
|
||||
constructor(private readonly settingsService: SettingsService,
|
||||
private readonly fb: FormBuilder,
|
||||
|
@ -44,9 +40,8 @@ export class JobsComponent implements OnInit {
|
|||
|
||||
public testCron(expression: string) {
|
||||
this.settingsService.testCron({ expression }).subscribe(x => {
|
||||
if(x.success) {
|
||||
this.testModel = x;
|
||||
this.displayTest = true;
|
||||
if(x.success) {
|
||||
this.notificationService.success("Cron is Valid");
|
||||
} else {
|
||||
this.notificationService.error(x.message);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import { InputSwitchModule, SidebarModule } from "primeng/primeng";
|
|||
|
||||
import {
|
||||
MatButtonModule, MatNativeDateModule, MatIconModule, MatSidenavModule, MatListModule, MatToolbarModule, MatTooltipModule, MatSelectModule, MatTableModule, MatPaginatorModule, MatSortModule,
|
||||
MatTreeModule, MatStepperModule} from '@angular/material';
|
||||
MatTreeModule, MatStepperModule, MatSnackBarModule} from '@angular/material';
|
||||
import { MatCardModule, MatInputModule, MatTabsModule, MatAutocompleteModule, MatCheckboxModule, MatExpansionModule, MatDialogModule, MatProgressSpinnerModule,
|
||||
MatChipsModule } from "@angular/material";
|
||||
import { EpisodeRequestComponent } from "./episode-request/episode-request.component";
|
||||
|
@ -50,6 +50,7 @@ import { EpisodeRequestComponent } from "./episode-request/episode-request.compo
|
|||
MatSortModule,
|
||||
MatTreeModule,
|
||||
MatStepperModule,
|
||||
MatSnackBarModule,
|
||||
],
|
||||
entryComponents: [
|
||||
EpisodeRequestComponent
|
||||
|
@ -73,6 +74,7 @@ import { EpisodeRequestComponent } from "./episode-request/episode-request.compo
|
|||
MatButtonModule,
|
||||
MatNativeDateModule,
|
||||
MatIconModule,
|
||||
MatSnackBarModule,
|
||||
MatSidenavModule,
|
||||
MatSelectModule,
|
||||
MatListModule,
|
||||
|
|
4
src/Ombi/ClientApp/src/typings/globals.d.ts
vendored
4
src/Ombi/ClientApp/src/typings/globals.d.ts
vendored
|
@ -1,8 +1,6 @@
|
|||
// Globals
|
||||
|
||||
declare module "pace";
|
||||
declare var __webpack_public_path__: any;
|
||||
declare var module: any;
|
||||
declare var module: NodeModule;
|
||||
|
||||
// declare module "*.json" {
|
||||
// const value: any;
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Ombi.Attributes;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Schedule;
|
||||
using Ombi.Schedule.Jobs;
|
||||
using Ombi.Schedule.Jobs.Emby;
|
||||
using Ombi.Schedule.Jobs.Ombi;
|
||||
using Ombi.Schedule.Jobs.Plex;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Controllers.V1
|
||||
{
|
||||
|
@ -17,35 +20,23 @@ namespace Ombi.Controllers.V1
|
|||
[ApiController]
|
||||
public class JobController : ControllerBase
|
||||
{
|
||||
public JobController(IOmbiAutomaticUpdater updater, IPlexUserImporter userImporter,
|
||||
ICacheService mem, IEmbyUserImporter embyImporter, IPlexContentSync plexContentSync,
|
||||
IEmbyContentSync embyContentSync, INewsletterJob newsletter)
|
||||
public JobController(IOmbiAutomaticUpdater updater, ICacheService mem)
|
||||
{
|
||||
_updater = updater;
|
||||
_plexUserImporter = userImporter;
|
||||
_embyUserImporter = embyImporter;
|
||||
_memCache = mem;
|
||||
_plexContentSync = plexContentSync;
|
||||
_embyContentSync = embyContentSync;
|
||||
_newsletterJob = newsletter;
|
||||
}
|
||||
|
||||
private readonly IOmbiAutomaticUpdater _updater;
|
||||
private readonly IPlexUserImporter _plexUserImporter;
|
||||
private readonly IEmbyUserImporter _embyUserImporter;
|
||||
private readonly ICacheService _memCache;
|
||||
private readonly IPlexContentSync _plexContentSync;
|
||||
private readonly IEmbyContentSync _embyContentSync;
|
||||
private readonly INewsletterJob _newsletterJob;
|
||||
|
||||
/// <summary>
|
||||
/// Runs the update job
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("update")]
|
||||
public bool ForceUpdate()
|
||||
public async Task<bool> ForceUpdate()
|
||||
{
|
||||
BackgroundJob.Enqueue(() => _updater.Update(null));
|
||||
|
||||
await OmbiQuartz.TriggerJob(nameof(IOmbiAutomaticUpdater), "System");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -92,9 +83,9 @@ namespace Ombi.Controllers.V1
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("plexuserimporter")]
|
||||
public bool PlexUserImporter()
|
||||
public async Task<bool> PlexUserImporter()
|
||||
{
|
||||
BackgroundJob.Enqueue(() => _plexUserImporter.Start());
|
||||
await OmbiQuartz.TriggerJob(nameof(IPlexUserImporter), "Plex");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -103,9 +94,9 @@ namespace Ombi.Controllers.V1
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("embyuserimporter")]
|
||||
public bool EmbyUserImporter()
|
||||
public async Task<bool> EmbyUserImporter()
|
||||
{
|
||||
BackgroundJob.Enqueue(() => _embyUserImporter.Start());
|
||||
await OmbiQuartz.TriggerJob(nameof(IEmbyUserImporter), "Emby");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -116,7 +107,7 @@ namespace Ombi.Controllers.V1
|
|||
[HttpPost("plexcontentcacher")]
|
||||
public bool StartPlexContentCacher()
|
||||
{
|
||||
BackgroundJob.Enqueue(() => _plexContentSync.CacheContent(false));
|
||||
OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IPlexContentSync), "Plex"), new JobDataMap(new Dictionary<string, string> { { "recentlyAddedSearch", "false" } }));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -127,7 +118,7 @@ namespace Ombi.Controllers.V1
|
|||
[HttpPost("plexrecentlyadded")]
|
||||
public bool StartRecentlyAdded()
|
||||
{
|
||||
BackgroundJob.Enqueue(() => _plexContentSync.CacheContent(true));
|
||||
OmbiQuartz.Scheduler.TriggerJob(new JobKey(nameof(IPlexContentSync), "Plex"), new JobDataMap(new Dictionary<string, string> { { "recentlyAddedSearch", "true" } }));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -136,9 +127,9 @@ namespace Ombi.Controllers.V1
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("embycontentcacher")]
|
||||
public bool StartEmbyContentCacher()
|
||||
public async Task<bool> StartEmbyContentCacher()
|
||||
{
|
||||
BackgroundJob.Enqueue(() => _embyContentSync.Start());
|
||||
await OmbiQuartz.TriggerJob(nameof(IEmbyContentSync), "Emby");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -147,9 +138,9 @@ namespace Ombi.Controllers.V1
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("newsletter")]
|
||||
public bool StartNewsletter()
|
||||
public async Task<bool> StartNewsletter()
|
||||
{
|
||||
BackgroundJob.Enqueue(() => _newsletterJob.Start());
|
||||
await OmbiQuartz.TriggerJob(nameof(INewsletterJob), "System");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -361,6 +361,19 @@ namespace Ombi.Controllers.V1
|
|||
return await MusicEngine.SearchAlbum(searchTerm);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the album information specified by the foreignAlbumId passed in
|
||||
/// </summary>
|
||||
/// <remarks>We use Lidarr as the Provider</remarks>
|
||||
/// <returns></returns>
|
||||
[HttpGet("music/album/info/{foreignAlbumId}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesDefaultResponseType]
|
||||
public async Task<SearchAlbumViewModel> GetAlbumInformation(string foreignAlbumId)
|
||||
{
|
||||
return await MusicEngine.GetAlbumInformation(foreignAlbumId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all albums for the artist using the ForeignArtistId
|
||||
/// </summary>
|
||||
|
|
|
@ -27,6 +27,10 @@ using Ombi.Settings.Settings.Models.External;
|
|||
using Ombi.Settings.Settings.Models.Notifications;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Api.Github;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Schedule;
|
||||
using Quartz;
|
||||
|
||||
namespace Ombi.Controllers.V1
|
||||
{
|
||||
|
@ -44,7 +48,6 @@ namespace Ombi.Controllers.V1
|
|||
IMapper mapper,
|
||||
INotificationTemplatesRepository templateRepo,
|
||||
IEmbyApi embyApi,
|
||||
IRadarrSync radarrSync,
|
||||
ICacheService memCache,
|
||||
IGithubApi githubApi,
|
||||
IRecentlyAddedEngine engine)
|
||||
|
@ -53,7 +56,6 @@ namespace Ombi.Controllers.V1
|
|||
Mapper = mapper;
|
||||
TemplateRepository = templateRepo;
|
||||
_embyApi = embyApi;
|
||||
_radarrSync = radarrSync;
|
||||
_cache = memCache;
|
||||
_githubApi = githubApi;
|
||||
_recentlyAdded = engine;
|
||||
|
@ -63,7 +65,6 @@ namespace Ombi.Controllers.V1
|
|||
private IMapper Mapper { get; }
|
||||
private INotificationTemplatesRepository TemplateRepository { get; }
|
||||
private readonly IEmbyApi _embyApi;
|
||||
private readonly IRadarrSync _radarrSync;
|
||||
private readonly ICacheService _cache;
|
||||
private readonly IGithubApi _githubApi;
|
||||
private readonly IRecentlyAddedEngine _recentlyAdded;
|
||||
|
@ -408,7 +409,8 @@ namespace Ombi.Controllers.V1
|
|||
{
|
||||
_cache.Remove(CacheKeys.RadarrRootProfiles);
|
||||
_cache.Remove(CacheKeys.RadarrQualityProfiles);
|
||||
BackgroundJob.Enqueue(() => _radarrSync.CacheContent());
|
||||
|
||||
await OmbiQuartz.TriggerJob(nameof(IRadarrSync), "DVR");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -568,8 +570,8 @@ namespace Ombi.Controllers.V1
|
|||
|
||||
try
|
||||
{
|
||||
var r = CrontabSchedule.TryParse(expression);
|
||||
if (r == null)
|
||||
var isValid = CronExpression.IsValidExpression(expression);
|
||||
if (!isValid)
|
||||
{
|
||||
return new JobSettingsViewModel
|
||||
{
|
||||
|
@ -599,14 +601,15 @@ namespace Ombi.Controllers.V1
|
|||
var model = new CronTestModel();
|
||||
try
|
||||
{
|
||||
var time = DateTime.UtcNow;
|
||||
var result = CrontabSchedule.TryParse(body.Expression);
|
||||
for (int i = 0; i < 10; i++)
|
||||
var isValid = CronExpression.IsValidExpression(body.Expression);
|
||||
if (!isValid)
|
||||
{
|
||||
var next = result.GetNextOccurrence(time);
|
||||
model.Schedule.Add(next);
|
||||
time = next;
|
||||
return new CronTestModel
|
||||
{
|
||||
Message = $"CRON Expression {body.Expression} is not valid"
|
||||
};
|
||||
}
|
||||
|
||||
model.Success = true;
|
||||
return model;
|
||||
}
|
||||
|
@ -617,8 +620,6 @@ namespace Ombi.Controllers.V1
|
|||
Message = $"CRON Expression {body.Expression} is not valid"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -126,7 +126,8 @@ namespace Ombi.Controllers.V1
|
|||
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
|
||||
new Claim(ClaimTypes.NameIdentifier, user.Id),
|
||||
new Claim(ClaimTypes.Name, user.UserName),
|
||||
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
|
||||
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
||||
new Claim("Id", user.Id)
|
||||
};
|
||||
claims.AddRange(roles.Select(role => new Claim("role", role)));
|
||||
|
||||
|
|
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