mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-25 07:25:22 -07:00
commit
6162e438e1
51 changed files with 654 additions and 136 deletions
|
@ -75,6 +75,7 @@ Supported notifications:
|
||||||
* Pushover
|
* Pushover
|
||||||
* Mattermost
|
* Mattermost
|
||||||
* Telegram
|
* Telegram
|
||||||
|
* Webhook
|
||||||
|
|
||||||
### The difference between Version 3 and 2
|
### The difference between Version 3 and 2
|
||||||
|
|
||||||
|
|
10
src/Ombi.Api.Webhook/IWebhookApi.cs
Normal file
10
src/Ombi.Api.Webhook/IWebhookApi.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Webhook
|
||||||
|
{
|
||||||
|
public interface IWebhookApi
|
||||||
|
{
|
||||||
|
Task PushAsync(string endpoint, string accessToken, IDictionary<string, string> parameters);
|
||||||
|
}
|
||||||
|
}
|
15
src/Ombi.Api.Webhook/Ombi.Api.Webhook.csproj
Normal file
15
src/Ombi.Api.Webhook/Ombi.Api.Webhook.csproj
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<AssemblyVersion>3.0.0.0</AssemblyVersion>
|
||||||
|
<FileVersion>3.0.0.0</FileVersion>
|
||||||
|
<Version></Version>
|
||||||
|
<PackageVersion></PackageVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
40
src/Ombi.Api.Webhook/WebhookApi.cs
Normal file
40
src/Ombi.Api.Webhook/WebhookApi.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Webhook
|
||||||
|
{
|
||||||
|
public class WebhookApi : IWebhookApi
|
||||||
|
{
|
||||||
|
private static readonly CamelCasePropertyNamesContractResolver _nameResolver = new CamelCasePropertyNamesContractResolver();
|
||||||
|
|
||||||
|
public WebhookApi(IApi api)
|
||||||
|
{
|
||||||
|
_api = api;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IApi _api;
|
||||||
|
|
||||||
|
public async Task PushAsync(string baseUrl, string accessToken, IDictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
var request = new Request("/", baseUrl, HttpMethod.Post);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(accessToken))
|
||||||
|
{
|
||||||
|
request.AddHeader("Access-Token", accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
var body = parameters.ToDictionary(
|
||||||
|
x => _nameResolver.GetResolvedPropertyName(x.Key),
|
||||||
|
x => x.Value
|
||||||
|
);
|
||||||
|
|
||||||
|
request.ApplicationJsonContentType();
|
||||||
|
request.AddJsonBody(body);
|
||||||
|
|
||||||
|
await _api.Request(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,7 +56,7 @@ namespace Ombi.Core.Engine.Demo
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
retVal.Add(ProcessResult(tvMazeSearch));
|
retVal.Add(await ProcessResult(tvMazeSearch));
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ namespace Ombi.Core.Engine.Demo
|
||||||
}
|
}
|
||||||
|
|
||||||
var movieResult = await TvMazeApi.ShowLookup(tv);
|
var movieResult = await TvMazeApi.ShowLookup(tv);
|
||||||
responses.Add(ProcessResult(movieResult));
|
responses.Add(await ProcessResult(movieResult));
|
||||||
}
|
}
|
||||||
|
|
||||||
return responses;
|
return responses;
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
retVal.Add(ProcessResult(tvMazeSearch));
|
retVal.Add(await ProcessResult(tvMazeSearch));
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ namespace Ombi.Core.Engine
|
||||||
public async Task<IEnumerable<SearchTvShowViewModel>> Popular()
|
public async Task<IEnumerable<SearchTvShowViewModel>> Popular()
|
||||||
{
|
{
|
||||||
var result = await Cache.GetOrAdd(CacheKeys.PopularTv, async () => await TraktApi.GetPopularShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.PopularTv, async () => await TraktApi.GetPopularShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,37 +131,38 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
|
|
||||||
var result = await Cache.GetOrAdd(CacheKeys.AnticipatedTv, async () => await TraktApi.GetAnticipatedShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.AnticipatedTv, async () => await TraktApi.GetAnticipatedShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches()
|
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches()
|
||||||
{
|
{
|
||||||
var result = await Cache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SearchTvShowViewModel>> Trending()
|
public async Task<IEnumerable<SearchTvShowViewModel>> Trending()
|
||||||
{
|
{
|
||||||
var result = await Cache.GetOrAdd(CacheKeys.TrendingTv, async () => await TraktApi.GetTrendingShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.TrendingTv, async () => await TraktApi.GetTrendingShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IEnumerable<SearchTvShowViewModel> ProcessResults<T>(IEnumerable<T> items)
|
protected async Task<IEnumerable<SearchTvShowViewModel>> ProcessResults<T>(IEnumerable<T> items)
|
||||||
{
|
{
|
||||||
var retVal = new List<SearchTvShowViewModel>();
|
var retVal = new List<SearchTvShowViewModel>();
|
||||||
foreach (var tvMazeSearch in items)
|
foreach (var tvMazeSearch in items)
|
||||||
{
|
{
|
||||||
retVal.Add(ProcessResult(tvMazeSearch));
|
retVal.Add(await ProcessResult(tvMazeSearch));
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SearchTvShowViewModel ProcessResult<T>(T tvMazeSearch)
|
protected async Task<SearchTvShowViewModel> ProcessResult<T>(T tvMazeSearch)
|
||||||
{
|
{
|
||||||
return Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
var viewTv = Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
||||||
|
return await ProcessResult(viewTv);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<SearchTvShowViewModel> ProcessResult(SearchTvShowViewModel item)
|
private async Task<SearchTvShowViewModel> ProcessResult(SearchTvShowViewModel item)
|
||||||
|
|
|
@ -7,6 +7,8 @@ namespace Ombi.Core.Models.Search
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public bool Approved { get; set; }
|
public bool Approved { get; set; }
|
||||||
|
public bool? Denied { get; set; }
|
||||||
|
public string DeniedReason { get; set; }
|
||||||
public bool Requested { get; set; }
|
public bool Requested { get; set; }
|
||||||
public int RequestId { get; set; }
|
public int RequestId { get; set; }
|
||||||
public bool Available { get; set; }
|
public bool Available { get; set; }
|
||||||
|
|
15
src/Ombi.Core/Models/UI/WebhookNotificationViewModel.cs
Normal file
15
src/Ombi.Core/Models/UI/WebhookNotificationViewModel.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The view model for the notification settings page
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="WebhookSettings" />
|
||||||
|
public class WebhookNotificationViewModel : WebhookSettings
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,8 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
obj.Requested = true;
|
obj.Requested = true;
|
||||||
obj.RequestId = movieRequests.Id;
|
obj.RequestId = movieRequests.Id;
|
||||||
obj.Approved = movieRequests.Approved;
|
obj.Approved = movieRequests.Approved;
|
||||||
|
obj.Denied = movieRequests.Denied ?? false;
|
||||||
|
obj.DeniedReason = movieRequests.DeniedReason;
|
||||||
obj.Available = movieRequests.Available;
|
obj.Available = movieRequests.Available;
|
||||||
|
|
||||||
return Success();
|
return Success();
|
||||||
|
@ -60,6 +62,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
|
|
||||||
request.Requested = true;
|
request.Requested = true;
|
||||||
request.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
|
request.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
|
||||||
|
request.Denied = tvRequests.ChildRequests.Any(x => x.Denied ?? false);
|
||||||
|
|
||||||
// Let's modify the seasonsrequested to reflect what we have requested...
|
// Let's modify the seasonsrequested to reflect what we have requested...
|
||||||
foreach (var season in request.SeasonRequests)
|
foreach (var season in request.SeasonRequests)
|
||||||
|
@ -108,6 +111,8 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
obj.Requested = true;
|
obj.Requested = true;
|
||||||
obj.RequestId = albumRequest.Id;
|
obj.RequestId = albumRequest.Id;
|
||||||
obj.Approved = albumRequest.Approved;
|
obj.Approved = albumRequest.Approved;
|
||||||
|
obj.Denied = albumRequest.Denied;
|
||||||
|
obj.DeniedReason = albumRequest.DeniedReason;
|
||||||
obj.Available = albumRequest.Available;
|
obj.Available = albumRequest.Available;
|
||||||
|
|
||||||
return Success();
|
return Success();
|
||||||
|
|
|
@ -32,6 +32,7 @@ using Ombi.Api.DogNzb;
|
||||||
using Ombi.Api.FanartTv;
|
using Ombi.Api.FanartTv;
|
||||||
using Ombi.Api.Github;
|
using Ombi.Api.Github;
|
||||||
using Ombi.Api.Gotify;
|
using Ombi.Api.Gotify;
|
||||||
|
using Ombi.Api.Webhook;
|
||||||
using Ombi.Api.Lidarr;
|
using Ombi.Api.Lidarr;
|
||||||
using Ombi.Api.Mattermost;
|
using Ombi.Api.Mattermost;
|
||||||
using Ombi.Api.Notifications;
|
using Ombi.Api.Notifications;
|
||||||
|
@ -122,6 +123,7 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<IFanartTvApi, FanartTvApi>();
|
services.AddTransient<IFanartTvApi, FanartTvApi>();
|
||||||
services.AddTransient<IPushoverApi, PushoverApi>();
|
services.AddTransient<IPushoverApi, PushoverApi>();
|
||||||
services.AddTransient<IGotifyApi, GotifyApi>();
|
services.AddTransient<IGotifyApi, GotifyApi>();
|
||||||
|
services.AddTransient<IWebhookApi, WebhookApi>();
|
||||||
services.AddTransient<IMattermostApi, MattermostApi>();
|
services.AddTransient<IMattermostApi, MattermostApi>();
|
||||||
services.AddTransient<ICouchPotatoApi, CouchPotatoApi>();
|
services.AddTransient<ICouchPotatoApi, CouchPotatoApi>();
|
||||||
services.AddTransient<IDogNzbApi, DogNzbApi>();
|
services.AddTransient<IDogNzbApi, DogNzbApi>();
|
||||||
|
@ -173,6 +175,7 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<IMattermostNotification, MattermostNotification>();
|
services.AddTransient<IMattermostNotification, MattermostNotification>();
|
||||||
services.AddTransient<IPushoverNotification, PushoverNotification>();
|
services.AddTransient<IPushoverNotification, PushoverNotification>();
|
||||||
services.AddTransient<IGotifyNotification, GotifyNotification>();
|
services.AddTransient<IGotifyNotification, GotifyNotification>();
|
||||||
|
services.AddTransient<IWebhookNotification, WebhookNotification>();
|
||||||
services.AddTransient<ITelegramNotification, TelegramNotification>();
|
services.AddTransient<ITelegramNotification, TelegramNotification>();
|
||||||
services.AddTransient<IMobileNotification, MobileNotification>();
|
services.AddTransient<IMobileNotification, MobileNotification>();
|
||||||
services.AddTransient<IChangeLogProcessor, ChangeLogProcessor>();
|
services.AddTransient<IChangeLogProcessor, ChangeLogProcessor>();
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
<ProjectReference Include="..\Ombi.Api.Telegram\Ombi.Api.Telegram.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Telegram\Ombi.Api.Telegram.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Trakt\Ombi.Api.Trakt.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Trakt\Ombi.Api.Trakt.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj" />
|
<ProjectReference Include="..\Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj" />
|
||||||
|
<ProjectReference Include="..\Ombi.Api.Webhook\Ombi.Api.Webhook.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
|
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Notifications\Ombi.Notifications.csproj" />
|
<ProjectReference Include="..\Ombi.Notifications\Ombi.Notifications.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Schedule\Ombi.Schedule.csproj" />
|
<ProjectReference Include="..\Ombi.Schedule\Ombi.Schedule.csproj" />
|
||||||
|
|
46
src/Ombi.Helpers.Tests/EmbyHelperTests.cs
Normal file
46
src/Ombi.Helpers.Tests/EmbyHelperTests.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ombi.Helpers.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class EmbyHelperTests
|
||||||
|
{
|
||||||
|
[TestCaseSource(nameof(UrlData))]
|
||||||
|
public string TestUrl(string mediaId, string url)
|
||||||
|
{
|
||||||
|
return EmbyHelper.GetEmbyMediaUrl(mediaId, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(JellyfinUrlData))]
|
||||||
|
public string TestJellyfinUrl(string mediaId, string url)
|
||||||
|
{
|
||||||
|
return EmbyHelper.GetEmbyMediaUrl(mediaId, url, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TestCaseData> UrlData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var mediaId = 1;
|
||||||
|
yield return new TestCaseData(mediaId.ToString(), "http://google.com").Returns($"http://google.com/#!/item?id={mediaId}").SetName("EmbyHelper_GetMediaUrl_WithCustomDomain_WithoutTrailingSlash");
|
||||||
|
yield return new TestCaseData(mediaId.ToString(), "http://google.com/").Returns($"http://google.com/#!/item?id={mediaId}").SetName("EmbyHelper_GetMediaUrl_WithCustomDomain");
|
||||||
|
yield return new TestCaseData(mediaId.ToString(), "https://google.com/").Returns($"https://google.com/#!/item?id={mediaId}").SetName("EmbyHelper_GetMediaUrl_WithCustomDomain_Https");
|
||||||
|
yield return new TestCaseData(mediaId.ToString(), string.Empty).Returns($"https://app.emby.media/#!/item?id={mediaId}").SetName("EmbyHelper_GetMediaUrl_WithOutCustomDomain");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TestCaseData> JellyfinUrlData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var mediaId = 1;
|
||||||
|
yield return new TestCaseData(mediaId.ToString(), "http://google.com").Returns($"http://google.com/#!/itemdetails.html?id={mediaId}").SetName("EmbyHelperJellyfin_GetMediaUrl_WithCustomDomain_WithoutTrailingSlash");
|
||||||
|
yield return new TestCaseData(mediaId.ToString(), "http://google.com/").Returns($"http://google.com/#!/itemdetails.html?id={mediaId}").SetName("EmbyHelperJellyfin_GetMediaUrl_WithCustomDomain");
|
||||||
|
yield return new TestCaseData(mediaId.ToString(), "https://google.com/").Returns($"https://google.com/#!/itemdetails.html?id={mediaId}").SetName("EmbyHelperJellyfin_GetMediaUrl_WithCustomDomain_Https");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,6 +39,8 @@ namespace Ombi.Helpers.Tests
|
||||||
yield return new TestCaseData("com.plexapp.agents.agent47://tt2543456?lang=en", ProviderIdType.Imdb).Returns("tt2543456").SetName("Unknown IMDB agent");
|
yield return new TestCaseData("com.plexapp.agents.agent47://tt2543456?lang=en", ProviderIdType.Imdb).Returns("tt2543456").SetName("Unknown IMDB agent");
|
||||||
yield return new TestCaseData("com.plexapp.agents.agent47://456822/1/1?lang=en", ProviderIdType.TvDb).Returns("456822").SetName("Unknown TvDb agent");
|
yield return new TestCaseData("com.plexapp.agents.agent47://456822/1/1?lang=en", ProviderIdType.TvDb).Returns("456822").SetName("Unknown TvDb agent");
|
||||||
yield return new TestCaseData("com.plexapp.agents.agent47://456822/999/999?lang=en", ProviderIdType.TvDb).Returns("456822").SetName("Unknown TvDb agent, large episode and season");
|
yield return new TestCaseData("com.plexapp.agents.agent47://456822/999/999?lang=en", ProviderIdType.TvDb).Returns("456822").SetName("Unknown TvDb agent, large episode and season");
|
||||||
|
yield return new TestCaseData("com.plexapp.agents.xbmcnfotv://153021/2/1?lang=xn", ProviderIdType.TvDb).Returns("153021").SetName("xmbc agent, tv episode");
|
||||||
|
yield return new TestCaseData("com.plexapp.agents.xbmcnfotv://153021?lang=xn", ProviderIdType.TvDb).Returns("153021").SetName("xmbc agent, tv show");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,22 @@
|
||||||
{
|
{
|
||||||
public static string GetEmbyMediaUrl(string mediaId, string customerServerUrl = null, bool isJellyfin = false)
|
public static string GetEmbyMediaUrl(string mediaId, string customerServerUrl = null, bool isJellyfin = false)
|
||||||
{
|
{
|
||||||
string path = "item/item";
|
string path = "item";
|
||||||
if (isJellyfin)
|
if (isJellyfin)
|
||||||
{
|
{
|
||||||
path = "itemdetails";
|
path = "itemdetails.html";
|
||||||
}
|
}
|
||||||
if (customerServerUrl.HasValue())
|
if (customerServerUrl.HasValue())
|
||||||
{
|
{
|
||||||
return $"{customerServerUrl}#!/{path}.html?id={mediaId}";
|
if (!customerServerUrl.EndsWith("/"))
|
||||||
|
{
|
||||||
|
return $"{customerServerUrl}/#!/{path}?id={mediaId}";
|
||||||
|
}
|
||||||
|
return $"{customerServerUrl}#!/{path}?id={mediaId}";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return $"https://app.emby.media/#!/{path}.html?id={mediaId}";
|
return $"https://app.emby.media/#!/{path}?id={mediaId}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace Ombi.Helpers
|
||||||
public static EventId PushoverNotification => new EventId(4005);
|
public static EventId PushoverNotification => new EventId(4005);
|
||||||
public static EventId TelegramNotifcation => new EventId(4006);
|
public static EventId TelegramNotifcation => new EventId(4006);
|
||||||
public static EventId GotifyNotification => new EventId(4007);
|
public static EventId GotifyNotification => new EventId(4007);
|
||||||
|
public static EventId WebhookNotification => new EventId(4008);
|
||||||
|
|
||||||
public static EventId TvSender => new EventId(5000);
|
public static EventId TvSender => new EventId(5000);
|
||||||
public static EventId SonarrSender => new EventId(5001);
|
public static EventId SonarrSender => new EventId(5001);
|
||||||
|
|
|
@ -11,5 +11,6 @@
|
||||||
Mattermost = 6,
|
Mattermost = 6,
|
||||||
Mobile = 7,
|
Mobile = 7,
|
||||||
Gotify = 8,
|
Gotify = 8,
|
||||||
|
Webhook = 9,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -33,14 +33,15 @@ namespace Ombi.Helpers
|
||||||
{
|
{
|
||||||
public class PlexHelper
|
public class PlexHelper
|
||||||
{
|
{
|
||||||
private const string ImdbMatchExpression = "tt([0-9]{1,10})";
|
private const string ImdbMatchExpression = "tt([0-9]{1,10})";
|
||||||
private const string TvDbIdMatchExpression = "//[0-9]+/([0-9]{1,3})/([0-9]{1,3})";
|
private const string TvDbIdMatchExpression = "//[0-9]+/?([0-9]{1,3})/?([0-9]{1,3})";
|
||||||
|
|
||||||
public static ProviderId GetProviderIdFromPlexGuid(string guid)
|
public static ProviderId GetProviderIdFromPlexGuid(string guid)
|
||||||
{
|
{
|
||||||
//com.plexapp.agents.thetvdb://269586/2/8?lang=en
|
//com.plexapp.agents.thetvdb://269586/2/8?lang=en
|
||||||
//com.plexapp.agents.themoviedb://390043?lang=en
|
//com.plexapp.agents.themoviedb://390043?lang=en
|
||||||
//com.plexapp.agents.imdb://tt2543164?lang=en
|
//com.plexapp.agents.imdb://tt2543164?lang=en
|
||||||
|
// https://github.com/tidusjar/Ombi/issues/3277
|
||||||
if (string.IsNullOrEmpty(guid))
|
if (string.IsNullOrEmpty(guid))
|
||||||
{
|
{
|
||||||
return new ProviderId();
|
return new ProviderId();
|
||||||
|
@ -55,7 +56,7 @@ namespace Ombi.Helpers
|
||||||
{
|
{
|
||||||
TheTvDb = guidSplit[1]
|
TheTvDb = guidSplit[1]
|
||||||
};
|
};
|
||||||
} else
|
}
|
||||||
if (guid.Contains("themoviedb", CompareOptions.IgnoreCase))
|
if (guid.Contains("themoviedb", CompareOptions.IgnoreCase))
|
||||||
{
|
{
|
||||||
return new ProviderId
|
return new ProviderId
|
||||||
|
@ -63,7 +64,6 @@ namespace Ombi.Helpers
|
||||||
TheMovieDb = guidSplit[1]
|
TheMovieDb = guidSplit[1]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
|
||||||
if (guid.Contains("imdb", CompareOptions.IgnoreCase))
|
if (guid.Contains("imdb", CompareOptions.IgnoreCase))
|
||||||
{
|
{
|
||||||
return new ProviderId
|
return new ProviderId
|
||||||
|
@ -71,74 +71,31 @@ namespace Ombi.Helpers
|
||||||
ImdbId = guidSplit[1]
|
ImdbId = guidSplit[1]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
var imdbRegex = new Regex(ImdbMatchExpression, RegexOptions.Compiled);
|
||||||
|
var tvdbRegex = new Regex(TvDbIdMatchExpression, RegexOptions.Compiled);
|
||||||
|
var imdbMatch = imdbRegex.IsMatch(guid);
|
||||||
|
if (imdbMatch)
|
||||||
{
|
{
|
||||||
var imdbRegex = new Regex(ImdbMatchExpression, RegexOptions.Compiled);
|
return new ProviderId
|
||||||
var tvdbRegex = new Regex(TvDbIdMatchExpression, RegexOptions.Compiled);
|
|
||||||
var imdbMatch = imdbRegex.IsMatch(guid);
|
|
||||||
if (imdbMatch)
|
|
||||||
{
|
{
|
||||||
return new ProviderId
|
ImdbId = guidSplit[1]
|
||||||
{
|
};
|
||||||
ImdbId = guidSplit[1]
|
}
|
||||||
};
|
|
||||||
}
|
// Check if it matches the TvDb pattern
|
||||||
else
|
var tvdbMatch = tvdbRegex.IsMatch(guid);
|
||||||
|
if (tvdbMatch)
|
||||||
|
{
|
||||||
|
return new ProviderId
|
||||||
{
|
{
|
||||||
// Check if it matches the TvDb pattern
|
TheTvDb = guidSplit[1]
|
||||||
var tvdbMatch = tvdbRegex.IsMatch(guid);
|
};
|
||||||
if (tvdbMatch)
|
|
||||||
{
|
|
||||||
return new ProviderId
|
|
||||||
{
|
|
||||||
TheTvDb = guidSplit[1]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ProviderId();
|
return new ProviderId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EpisodeModelHelper GetSeasonsAndEpisodesFromPlexGuid(string guid)
|
|
||||||
{
|
|
||||||
var ep = new EpisodeModelHelper();
|
|
||||||
//com.plexapp.agents.thetvdb://269586/2/8?lang=en
|
|
||||||
//com.plexapp.agents.themoviedb://390043?lang=en
|
|
||||||
//com.plexapp.agents.imdb://tt2543164?lang=en
|
|
||||||
if (string.IsNullOrEmpty(guid))
|
|
||||||
return null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var guidSplit = guid.Split(new[] { '/', '?' }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
if (guidSplit.Length > 2)
|
|
||||||
{
|
|
||||||
if (guid.Contains("thetvdb", CompareOptions.IgnoreCase))
|
|
||||||
{
|
|
||||||
ep.ProviderId = new ProviderId {TheTvDb = guidSplit[1]};
|
|
||||||
}
|
|
||||||
if (guid.Contains("themoviedb", CompareOptions.IgnoreCase))
|
|
||||||
{
|
|
||||||
ep.ProviderId = new ProviderId { TheMovieDb = guidSplit[1] };
|
|
||||||
|
|
||||||
}
|
|
||||||
if (guid.Contains("imdb", CompareOptions.IgnoreCase))
|
|
||||||
{
|
|
||||||
ep.ProviderId = new ProviderId { ImdbId = guidSplit[1] };
|
|
||||||
|
|
||||||
}
|
|
||||||
ep.SeasonNumber = int.Parse(guidSplit[2]);
|
|
||||||
ep.EpisodeNumber = int.Parse(guidSplit[3]);
|
|
||||||
}
|
|
||||||
return ep;
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return ep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetPlexMediaUrl(string machineId, int mediaId)
|
public static string GetPlexMediaUrl(string machineId, int mediaId)
|
||||||
{
|
{
|
||||||
var url =
|
var url =
|
||||||
|
@ -147,13 +104,6 @@ namespace Ombi.Helpers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EpisodeModelHelper
|
|
||||||
{
|
|
||||||
public ProviderId ProviderId { get; set; }
|
|
||||||
public int SeasonNumber { get; set; }
|
|
||||||
public int EpisodeNumber { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ProviderId
|
public class ProviderId
|
||||||
{
|
{
|
||||||
public string TheTvDb { get; set; }
|
public string TheTvDb { get; set; }
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace Ombi.Mapping.Profiles
|
||||||
CreateMap<MobileNotificationsViewModel, MobileNotificationSettings>().ReverseMap();
|
CreateMap<MobileNotificationsViewModel, MobileNotificationSettings>().ReverseMap();
|
||||||
CreateMap<NewsletterNotificationViewModel, NewsletterSettings>().ReverseMap();
|
CreateMap<NewsletterNotificationViewModel, NewsletterSettings>().ReverseMap();
|
||||||
CreateMap<GotifyNotificationViewModel, GotifySettings>().ReverseMap();
|
CreateMap<GotifyNotificationViewModel, GotifySettings>().ReverseMap();
|
||||||
|
CreateMap<WebhookNotificationViewModel, WebhookSettings>().ReverseMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace Ombi.Notifications.Agents
|
||||||
|
{
|
||||||
|
public interface IWebhookNotification : INotification
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
123
src/Ombi.Notifications/Agents/WebhookNotification.cs
Normal file
123
src/Ombi.Notifications/Agents/WebhookNotification.cs
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.Webhook;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Notifications.Models;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Notifications.Agents
|
||||||
|
{
|
||||||
|
public class WebhookNotification : BaseNotification<WebhookSettings>, IWebhookNotification
|
||||||
|
{
|
||||||
|
public WebhookNotification(IWebhookApi api, ISettingsService<WebhookSettings> sn, ILogger<WebhookNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
||||||
|
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub, IMusicRequestRepository music,
|
||||||
|
IRepository<UserNotificationPreferences> userPref) : base(sn, r, m, t, s, log, sub, music, userPref)
|
||||||
|
{
|
||||||
|
Api = api;
|
||||||
|
Logger = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string NotificationName => "WebhookNotification";
|
||||||
|
|
||||||
|
private IWebhookApi Api { get; }
|
||||||
|
private ILogger<WebhookNotification> Logger { get; }
|
||||||
|
|
||||||
|
protected override bool ValidateConfiguration(WebhookSettings settings)
|
||||||
|
{
|
||||||
|
return settings.Enabled && !string.IsNullOrEmpty(settings.WebhookUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task NewRequest(NotificationOptions model, WebhookSettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.NewRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override async Task NewIssue(NotificationOptions model, WebhookSettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.Issue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task IssueComment(NotificationOptions model, WebhookSettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.IssueComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task IssueResolved(NotificationOptions model, WebhookSettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.IssueResolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task AddedToRequestQueue(NotificationOptions model, WebhookSettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.ItemAddedToFaultQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RequestDeclined(NotificationOptions model, WebhookSettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.RequestDeclined);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RequestApproved(NotificationOptions model, WebhookSettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.RequestApproved);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task AvailableRequest(NotificationOptions model, WebhookSettings settings)
|
||||||
|
{
|
||||||
|
await Run(model, settings, NotificationType.RequestAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task Send(NotificationMessage model, WebhookSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Api.PushAsync(settings.WebhookUrl, settings.ApplicationToken, model.Data);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(LoggingEvents.WebhookNotification, e, "Failed to send webhook notification");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task Test(NotificationOptions model, WebhookSettings settings)
|
||||||
|
{
|
||||||
|
var c = new NotificationMessageCurlys();
|
||||||
|
|
||||||
|
var testData = c.Curlys.ToDictionary(x => x.Key, x => x.Value);
|
||||||
|
testData[nameof(NotificationType)] = NotificationType.Test.ToString();
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Data = testData,
|
||||||
|
};
|
||||||
|
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Run(NotificationOptions model, WebhookSettings settings, NotificationType type)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Webhook, type, model);
|
||||||
|
if (parsed.Disabled)
|
||||||
|
{
|
||||||
|
Logger.LogInformation($"Template {type} is disabled for {NotificationAgent.Webhook}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var notificationData = parsed.Data.ToDictionary(x => x.Key, x => x.Value);
|
||||||
|
notificationData[nameof(NotificationType)] = type.ToString();
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Data = notificationData,
|
||||||
|
};
|
||||||
|
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,5 +9,6 @@ namespace Ombi.Notifications.Models
|
||||||
public string To { get; set; }
|
public string To { get; set; }
|
||||||
|
|
||||||
public Dictionary<string, string> Other { get; set; } = new Dictionary<string, string>();
|
public Dictionary<string, string> Other { get; set; } = new Dictionary<string, string>();
|
||||||
|
public IDictionary<string, string> Data { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
namespace Ombi.Notifications
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ombi.Notifications
|
||||||
{
|
{
|
||||||
public class NotificationMessageContent
|
public class NotificationMessageContent
|
||||||
{
|
{
|
||||||
|
@ -6,5 +8,6 @@
|
||||||
public string Subject { get; set; }
|
public string Subject { get; set; }
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
public string Image { get; set; }
|
public string Image { get; set; }
|
||||||
|
public IReadOnlyDictionary<string, string> Data { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,8 @@ namespace Ombi.Notifications
|
||||||
{
|
{
|
||||||
LoadIssues(opts);
|
LoadIssues(opts);
|
||||||
|
|
||||||
|
RequestId = req?.Id.ToString();
|
||||||
|
|
||||||
string title;
|
string title;
|
||||||
if (req == null)
|
if (req == null)
|
||||||
{
|
{
|
||||||
|
@ -68,6 +70,8 @@ namespace Ombi.Notifications
|
||||||
{
|
{
|
||||||
LoadIssues(opts);
|
LoadIssues(opts);
|
||||||
|
|
||||||
|
RequestId = req?.Id.ToString();
|
||||||
|
|
||||||
string title;
|
string title;
|
||||||
if (req == null)
|
if (req == null)
|
||||||
{
|
{
|
||||||
|
@ -114,6 +118,9 @@ namespace Ombi.Notifications
|
||||||
public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s, UserNotificationPreferences pref)
|
public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||||
{
|
{
|
||||||
LoadIssues(opts);
|
LoadIssues(opts);
|
||||||
|
|
||||||
|
RequestId = req?.ParentRequestId.ToString();
|
||||||
|
|
||||||
string title;
|
string title;
|
||||||
if (req == null)
|
if (req == null)
|
||||||
{
|
{
|
||||||
|
@ -216,6 +223,7 @@ namespace Ombi.Notifications
|
||||||
}
|
}
|
||||||
|
|
||||||
// User Defined
|
// User Defined
|
||||||
|
public string RequestId { get; set; }
|
||||||
public string RequestedUser { get; set; }
|
public string RequestedUser { get; set; }
|
||||||
public string UserName { get; set; }
|
public string UserName { get; set; }
|
||||||
public string IssueUser => UserName;
|
public string IssueUser => UserName;
|
||||||
|
@ -248,6 +256,7 @@ namespace Ombi.Notifications
|
||||||
|
|
||||||
public Dictionary<string, string> Curlys => new Dictionary<string, string>
|
public Dictionary<string, string> Curlys => new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
|
{nameof(RequestId), RequestId },
|
||||||
{nameof(RequestedUser), RequestedUser },
|
{nameof(RequestedUser), RequestedUser },
|
||||||
{nameof(Title), Title },
|
{nameof(Title), Title },
|
||||||
{nameof(RequestedDate), RequestedDate },
|
{nameof(RequestedDate), RequestedDate },
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace Ombi.Notifications
|
||||||
|
|
||||||
body = ReplaceFields(bodyFields, parameters, body);
|
body = ReplaceFields(bodyFields, parameters, body);
|
||||||
subject = ReplaceFields(subjectFields, parameters, subject);
|
subject = ReplaceFields(subjectFields, parameters, subject);
|
||||||
return new NotificationMessageContent { Message = body ?? string.Empty, Subject = subject ?? string.Empty};
|
return new NotificationMessageContent { Message = body ?? string.Empty, Subject = subject ?? string.Empty, Data = parameters };
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<string> ProcessConditions(IEnumerable<string> conditionalFields, IReadOnlyDictionary<string, string> parameters)
|
public IEnumerable<string> ProcessConditions(IEnumerable<string> conditionalFields, IReadOnlyDictionary<string, string> parameters)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ombi.Api.Discord\Ombi.Api.Discord.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Discord\Ombi.Api.Discord.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Gotify\Ombi.Api.Gotify.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Gotify\Ombi.Api.Gotify.csproj" />
|
||||||
|
<ProjectReference Include="..\Ombi.Api.Webhook\Ombi.Api.Webhook.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Notifications\Ombi.Api.Notifications.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Notifications\Ombi.Api.Notifications.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
|
||||||
|
|
|
@ -730,7 +730,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
finalsb.Append("<br />");
|
finalsb.Append("<br />");
|
||||||
}
|
}
|
||||||
|
|
||||||
var summary = info.summary;
|
var summary = info?.summary ?? string.Empty;
|
||||||
if (summary.Length > 280)
|
if (summary.Length > 280)
|
||||||
{
|
{
|
||||||
summary = summary.Remove(280);
|
summary = summary.Remove(280);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ombi.Api.Emby;
|
using Ombi.Api.Emby;
|
||||||
using Ombi.Api.TheMovieDb;
|
using Ombi.Api.TheMovieDb;
|
||||||
|
@ -67,13 +69,13 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
private async Task StartPlex()
|
private async Task StartPlex()
|
||||||
{
|
{
|
||||||
// Ensure we check that we have not linked this item to a request
|
// Ensure we check that we have not linked this item to a request
|
||||||
var allMovies = _plexRepo.GetAll().Where(x =>
|
var allMovies = await _plexRepo.GetAll().Where(x =>
|
||||||
x.Type == PlexMediaTypeEntity.Movie && !x.RequestId.HasValue && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue()));
|
x.Type == PlexMediaTypeEntity.Movie && !x.RequestId.HasValue && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue())).ToListAsync();
|
||||||
await StartPlexMovies(allMovies);
|
await StartPlexMovies(allMovies);
|
||||||
|
|
||||||
// Now Tv
|
// Now Tv
|
||||||
var allTv = _plexRepo.GetAll().Where(x =>
|
var allTv = await _plexRepo.GetAll().Where(x =>
|
||||||
x.Type == PlexMediaTypeEntity.Show && !x.RequestId.HasValue && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue() || !x.TvDbId.HasValue()));
|
x.Type == PlexMediaTypeEntity.Show && !x.RequestId.HasValue && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue() || !x.TvDbId.HasValue())).ToListAsync();
|
||||||
await StartPlexTv(allTv);
|
await StartPlexTv(allTv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +85,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
await StartEmbyTv();
|
await StartEmbyTv();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartPlexTv(IQueryable<PlexServerContent> allTv)
|
private async Task StartPlexTv(List<PlexServerContent> allTv)
|
||||||
{
|
{
|
||||||
foreach (var show in allTv)
|
foreach (var show in allTv)
|
||||||
{
|
{
|
||||||
|
@ -121,8 +123,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
|
|
||||||
private async Task StartEmbyTv()
|
private async Task StartEmbyTv()
|
||||||
{
|
{
|
||||||
var allTv = _embyRepo.GetAll().Where(x =>
|
var allTv = await _embyRepo.GetAll().Where(x =>
|
||||||
x.Type == EmbyMediaType.Series && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue() || !x.TvDbId.HasValue()));
|
x.Type == EmbyMediaType.Series && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue() || !x.TvDbId.HasValue())).ToListAsync();;
|
||||||
|
|
||||||
foreach (var show in allTv)
|
foreach (var show in allTv)
|
||||||
{
|
{
|
||||||
|
@ -154,7 +156,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartPlexMovies(IQueryable<PlexServerContent> allMovies)
|
private async Task StartPlexMovies(List<PlexServerContent> allMovies)
|
||||||
{
|
{
|
||||||
foreach (var movie in allMovies)
|
foreach (var movie in allMovies)
|
||||||
{
|
{
|
||||||
|
@ -186,8 +188,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
|
|
||||||
private async Task StartEmbyMovies(EmbySettings settings)
|
private async Task StartEmbyMovies(EmbySettings settings)
|
||||||
{
|
{
|
||||||
var allMovies = _embyRepo.GetAll().Where(x =>
|
var allMovies = await _embyRepo.GetAll().Where(x =>
|
||||||
x.Type == EmbyMediaType.Movie && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue()));
|
x.Type == EmbyMediaType.Movie && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue())).ToListAsync();
|
||||||
foreach (var movie in allMovies)
|
foreach (var movie in allMovies)
|
||||||
{
|
{
|
||||||
movie.ImdbId.HasValue();
|
movie.ImdbId.HasValue();
|
||||||
|
|
10
src/Ombi.Schedule/Jobs/Plex/Models/AvailabilityModel.cs
Normal file
10
src/Ombi.Schedule/Jobs/Plex/Models/AvailabilityModel.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Schedule.Jobs.Plex.Models
|
||||||
|
{
|
||||||
|
public class AvailabilityModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string RequestedUser { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -6,6 +7,7 @@ using Microsoft.Extensions.Logging;
|
||||||
using Ombi.Core;
|
using Ombi.Core;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Notifications.Models;
|
using Ombi.Notifications.Models;
|
||||||
|
using Ombi.Schedule.Jobs.Plex.Models;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
@ -47,13 +49,13 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
|
|
||||||
private Task ProcessTv()
|
private Task ProcessTv()
|
||||||
{
|
{
|
||||||
var tv = _tvRepo.GetChild().Where(x => !x.Available);
|
var tv = _tvRepo.GetChild().Where(x => !x.Available).AsNoTracking();
|
||||||
return ProcessTv(tv);
|
return ProcessTv(tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessTv(IQueryable<ChildRequests> tv)
|
private async Task ProcessTv(IQueryable<ChildRequests> tv)
|
||||||
{
|
{
|
||||||
var plexEpisodes = _repo.GetAllEpisodes().Include(x => x.Series);
|
var plexEpisodes = _repo.GetAllEpisodes().Include(x => x.Series).AsNoTracking();
|
||||||
|
|
||||||
foreach (var child in tv)
|
foreach (var child in tv)
|
||||||
{
|
{
|
||||||
|
@ -95,6 +97,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var availableEpisode = new List<AvailabilityModel>();
|
||||||
foreach (var season in child.SeasonRequests)
|
foreach (var season in child.SeasonRequests)
|
||||||
{
|
{
|
||||||
foreach (var episode in season.Episodes)
|
foreach (var episode in season.Episodes)
|
||||||
|
@ -109,20 +112,28 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
|
|
||||||
if (foundEp != null)
|
if (foundEp != null)
|
||||||
{
|
{
|
||||||
|
availableEpisode.Add(new AvailabilityModel
|
||||||
|
{
|
||||||
|
Id = episode.Id
|
||||||
|
});
|
||||||
episode.Available = true;
|
episode.Available = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO Partial avilability notifications here
|
||||||
|
foreach(var c in availableEpisode)
|
||||||
|
{
|
||||||
|
await _tvRepo.MarkEpisodeAsAvailable(c.Id);
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see if all of the episodes in all seasons are available for this request
|
// Check to see if all of the episodes in all seasons are available for this request
|
||||||
var allAvailable = child.SeasonRequests.All(x => x.Episodes.All(c => c.Available));
|
var allAvailable = child.SeasonRequests.All(x => x.Episodes.All(c => c.Available));
|
||||||
if (allAvailable)
|
if (allAvailable)
|
||||||
{
|
{
|
||||||
_log.LogInformation("[PAC] - Child request {0} is now available, sending notification", $"{child.Title} - {child.Id}");
|
_log.LogInformation("[PAC] - Child request {0} is now available, sending notification", $"{child.Title} - {child.Id}");
|
||||||
// We have ful-fulled this request!
|
// We have ful-fulled this request!
|
||||||
child.Available = true;
|
await _tvRepo.MarkChildAsAvailable(child.Id);
|
||||||
child.MarkedAsAvailable = DateTime.Now;
|
|
||||||
|
|
||||||
await _notificationService.Notify(new NotificationOptions
|
await _notificationService.Notify(new NotificationOptions
|
||||||
{
|
{
|
||||||
DateTime = DateTime.Now,
|
DateTime = DateTime.Now,
|
||||||
|
@ -140,10 +151,16 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
private async Task ProcessMovies()
|
private async Task ProcessMovies()
|
||||||
{
|
{
|
||||||
// Get all non available
|
// Get all non available
|
||||||
var movies = _movieRepo.GetAll().Include(x => x.RequestedUser).Where(x => !x.Available);
|
var movies = _movieRepo.GetAll().Include(x => x.RequestedUser).Where(x => !x.Available).AsNoTracking();
|
||||||
|
var itemsForAvailbility = new List<AvailabilityModel>();
|
||||||
|
|
||||||
foreach (var movie in movies)
|
foreach (var movie in movies)
|
||||||
{
|
{
|
||||||
|
if (movie.Available)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
PlexServerContent item = null;
|
PlexServerContent item = null;
|
||||||
if (movie.ImdbId.HasValue())
|
if (movie.ImdbId.HasValue())
|
||||||
{
|
{
|
||||||
|
@ -162,23 +179,28 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
movie.Available = true;
|
|
||||||
movie.MarkedAsAvailable = DateTime.Now;
|
|
||||||
item.RequestId = movie.Id;
|
|
||||||
|
|
||||||
_log.LogInformation("[PAC] - Movie request {0} is now available, sending notification", $"{movie.Title} - {movie.Id}");
|
_log.LogInformation("[PAC] - Movie request {0} is now available, sending notification", $"{movie.Title} - {movie.Id}");
|
||||||
|
itemsForAvailbility.Add(new AvailabilityModel
|
||||||
|
{
|
||||||
|
Id = movie.Id,
|
||||||
|
RequestedUser = movie.RequestedUser != null ? movie.RequestedUser.Email : string.Empty
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var i in itemsForAvailbility)
|
||||||
|
{
|
||||||
|
await _movieRepo.MarkAsAvailable(i.Id);
|
||||||
|
|
||||||
await _notificationService.Notify(new NotificationOptions
|
await _notificationService.Notify(new NotificationOptions
|
||||||
{
|
{
|
||||||
DateTime = DateTime.Now,
|
DateTime = DateTime.Now,
|
||||||
NotificationType = NotificationType.RequestAvailable,
|
NotificationType = NotificationType.RequestAvailable,
|
||||||
RequestId = movie.Id,
|
RequestId = i.Id,
|
||||||
RequestType = RequestType.Movie,
|
RequestType = RequestType.Movie,
|
||||||
Recipient = movie.RequestedUser != null ? movie.RequestedUser.Email : string.Empty
|
Recipient = i.RequestedUser
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await _movieRepo.Save();
|
|
||||||
await _repo.SaveChangesAsync();
|
await _repo.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
_log.LogError(LoggingEvents.Cacher, e, "Caching Episodes Failed");
|
_log.LogError(LoggingEvents.Cacher, e, "Caching Episodes Failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
//await OmbiQuartz.TriggerJob(nameof(IRefreshMetadata), "System");
|
await OmbiQuartz.TriggerJob(nameof(IRefreshMetadata), "System");
|
||||||
await OmbiQuartz.TriggerJob(nameof(IPlexAvailabilityChecker), "Plex");
|
await OmbiQuartz.TriggerJob(nameof(IPlexAvailabilityChecker), "Plex");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Ombi.Settings.Settings.Models.Notifications
|
||||||
|
{
|
||||||
|
public class WebhookSettings : Settings
|
||||||
|
{
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public string WebhookUrl { get; set; }
|
||||||
|
public string ApplicationToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
namespace Ombi.Store.Context
|
namespace Ombi.Store.Context
|
||||||
{
|
{
|
||||||
|
@ -35,6 +36,7 @@ namespace Ombi.Store.Context
|
||||||
public DbSet<AlbumRequest> AlbumRequests { get; set; }
|
public DbSet<AlbumRequest> AlbumRequests { get; set; }
|
||||||
public DbSet<TvRequests> TvRequests { get; set; }
|
public DbSet<TvRequests> TvRequests { get; set; }
|
||||||
public DbSet<ChildRequests> ChildRequests { get; set; }
|
public DbSet<ChildRequests> ChildRequests { get; set; }
|
||||||
|
public DbSet<EpisodeRequests> EpisodeRequests { get; set; }
|
||||||
|
|
||||||
public DbSet<Issues> Issues { get; set; }
|
public DbSet<Issues> Issues { get; set; }
|
||||||
public DbSet<IssueCategory> IssueCategories { get; set; }
|
public DbSet<IssueCategory> IssueCategories { get; set; }
|
||||||
|
@ -116,7 +118,7 @@ namespace Ombi.Store.Context
|
||||||
notificationToAdd = new NotificationTemplates
|
notificationToAdd = new NotificationTemplates
|
||||||
{
|
{
|
||||||
NotificationType = notificationType,
|
NotificationType = notificationType,
|
||||||
Message = "Hello! Your request for {Title} on {ApplicationName}! This is now available! :)",
|
Message = "Hello! Your request for {Title} on {ApplicationName} is now available.",
|
||||||
Subject = "{ApplicationName}: {Title} is now available!",
|
Subject = "{ApplicationName}: {Title} is now available!",
|
||||||
Agent = agent,
|
Agent = agent,
|
||||||
Enabled = true,
|
Enabled = true,
|
||||||
|
@ -138,7 +140,7 @@ namespace Ombi.Store.Context
|
||||||
notificationToAdd = new NotificationTemplates
|
notificationToAdd = new NotificationTemplates
|
||||||
{
|
{
|
||||||
NotificationType = notificationType,
|
NotificationType = notificationType,
|
||||||
Message = "Hello! Your request for {Title} has been declined, Sorry!",
|
Message = "Hello! Your request for {Title} has been declined.",
|
||||||
Subject = "{ApplicationName}: your request has been declined",
|
Subject = "{ApplicationName}: your request has been declined",
|
||||||
Agent = agent,
|
Agent = agent,
|
||||||
Enabled = true,
|
Enabled = true,
|
||||||
|
@ -148,7 +150,7 @@ namespace Ombi.Store.Context
|
||||||
notificationToAdd = new NotificationTemplates
|
notificationToAdd = new NotificationTemplates
|
||||||
{
|
{
|
||||||
NotificationType = notificationType,
|
NotificationType = notificationType,
|
||||||
Message = "Hello! The user '{UserName}' has requested {Title} but it could not be added. This has been added into the requests queue and will keep retrying",
|
Message = "Hello! The user '{UserName}' has requested {Title} but it could not be added. This has been added into the requests queue and it will keep retrying",
|
||||||
Subject = "Item Added To Retry Queue",
|
Subject = "Item Added To Retry Queue",
|
||||||
Agent = agent,
|
Agent = agent,
|
||||||
Enabled = true,
|
Enabled = true,
|
||||||
|
@ -158,7 +160,7 @@ namespace Ombi.Store.Context
|
||||||
notificationToAdd = new NotificationTemplates
|
notificationToAdd = new NotificationTemplates
|
||||||
{
|
{
|
||||||
NotificationType = notificationType,
|
NotificationType = notificationType,
|
||||||
Message = "Hello! You have been invited to use {ApplicationName}! You can login here: {ApplicationUrl}",
|
Message = "Hello! You have been invited to use {ApplicationName}. You can login here: {ApplicationUrl}",
|
||||||
Subject = "Invite to {ApplicationName}",
|
Subject = "Invite to {ApplicationName}",
|
||||||
Agent = agent,
|
Agent = agent,
|
||||||
Enabled = true,
|
Enabled = true,
|
||||||
|
@ -168,7 +170,7 @@ namespace Ombi.Store.Context
|
||||||
notificationToAdd = new NotificationTemplates
|
notificationToAdd = new NotificationTemplates
|
||||||
{
|
{
|
||||||
NotificationType = notificationType,
|
NotificationType = notificationType,
|
||||||
Message = "Hello {UserName} Your issue for {Title} has now been resolved.",
|
Message = "Hello {UserName}, your issue for {Title} has now been resolved.",
|
||||||
Subject = "{ApplicationName}: Issue has been resolved for {Title}!",
|
Subject = "{ApplicationName}: Issue has been resolved for {Title}!",
|
||||||
Agent = agent,
|
Agent = agent,
|
||||||
Enabled = true,
|
Enabled = true,
|
||||||
|
@ -179,7 +181,7 @@ namespace Ombi.Store.Context
|
||||||
notificationToAdd = new NotificationTemplates
|
notificationToAdd = new NotificationTemplates
|
||||||
{
|
{
|
||||||
NotificationType = notificationType,
|
NotificationType = notificationType,
|
||||||
Message = "Hello, There is a new comment on your issue {IssueSubject}, The comment is: {NewIssueComment}",
|
Message = "Hello, There is a new comment on your issue {IssueSubject}. The comment is: {NewIssueComment}",
|
||||||
Subject = "{ApplicationName}: New comment on issue {IssueSubject}!",
|
Subject = "{ApplicationName}: New comment on issue {IssueSubject}!",
|
||||||
Agent = agent,
|
Agent = agent,
|
||||||
Enabled = true,
|
Enabled = true,
|
||||||
|
@ -191,7 +193,7 @@ namespace Ombi.Store.Context
|
||||||
notificationToAdd = new NotificationTemplates
|
notificationToAdd = new NotificationTemplates
|
||||||
{
|
{
|
||||||
NotificationType = notificationType,
|
NotificationType = notificationType,
|
||||||
Message = "Here is a list of Movies and TV Shows that have recently been added!",
|
Message = "Here is a list of Movies and TV Shows that have recently been added:",
|
||||||
Subject = "{ApplicationName}: Recently Added Content!",
|
Subject = "{ApplicationName}: Recently Added Content!",
|
||||||
Agent = agent,
|
Agent = agent,
|
||||||
Enabled = true,
|
Enabled = true,
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace Ombi.Store.Repository.Requests
|
||||||
MovieRequests GetRequest(int theMovieDbId);
|
MovieRequests GetRequest(int theMovieDbId);
|
||||||
Task Update(MovieRequests request);
|
Task Update(MovieRequests request);
|
||||||
Task Save();
|
Task Save();
|
||||||
|
Task MarkAsAvailable(int id);
|
||||||
IQueryable<MovieRequests> GetWithUser();
|
IQueryable<MovieRequests> GetWithUser();
|
||||||
IQueryable<MovieRequests> GetWithUser(string userId);
|
IQueryable<MovieRequests> GetWithUser(string userId);
|
||||||
IQueryable<MovieRequests> GetAll(string userId);
|
IQueryable<MovieRequests> GetAll(string userId);
|
||||||
|
|
|
@ -23,6 +23,8 @@ namespace Ombi.Store.Repository.Requests
|
||||||
Task UpdateChild(ChildRequests request);
|
Task UpdateChild(ChildRequests request);
|
||||||
IQueryable<ChildRequests> GetChild();
|
IQueryable<ChildRequests> GetChild();
|
||||||
IQueryable<ChildRequests> GetChild(string userId);
|
IQueryable<ChildRequests> GetChild(string userId);
|
||||||
|
Task MarkEpisodeAsAvailable(int id);
|
||||||
|
Task MarkChildAsAvailable(int id);
|
||||||
Task Save();
|
Task Save();
|
||||||
Task DeleteChildRange(IEnumerable<ChildRequests> request);
|
Task DeleteChildRange(IEnumerable<ChildRequests> request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,14 @@ namespace Ombi.Store.Repository.Requests
|
||||||
.AsQueryable();
|
.AsQueryable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task MarkAsAvailable(int id)
|
||||||
|
{
|
||||||
|
var movieRequest = new MovieRequests{ Id = id, Available = true, MarkedAsAvailable = DateTime.UtcNow};
|
||||||
|
var attached = Db.MovieRequests.Attach(movieRequest);
|
||||||
|
attached.Property(x => x.Available).IsModified = true;
|
||||||
|
attached.Property(x => x.MarkedAsAvailable).IsModified = true;
|
||||||
|
await Db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public IQueryable<MovieRequests> GetWithUser(string userId)
|
public IQueryable<MovieRequests> GetWithUser(string userId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -100,6 +101,23 @@ namespace Ombi.Store.Repository.Requests
|
||||||
.AsQueryable();
|
.AsQueryable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task MarkChildAsAvailable(int id)
|
||||||
|
{
|
||||||
|
var request = new ChildRequests { Id = id, Available = true, MarkedAsAvailable = DateTime.UtcNow };
|
||||||
|
var attached = Db.ChildRequests.Attach(request);
|
||||||
|
attached.Property(x => x.Available).IsModified = true;
|
||||||
|
attached.Property(x => x.MarkedAsAvailable).IsModified = true;
|
||||||
|
await Db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task MarkEpisodeAsAvailable(int id)
|
||||||
|
{
|
||||||
|
var request = new EpisodeRequests { Id = id, Available = true };
|
||||||
|
var attached = Db.EpisodeRequests.Attach(request);
|
||||||
|
attached.Property(x => x.Available).IsModified = true;
|
||||||
|
await Db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Save()
|
public async Task Save()
|
||||||
{
|
{
|
||||||
await InternalSaveChanges();
|
await InternalSaveChanges();
|
||||||
|
|
11
src/Ombi.sln
11
src/Ombi.sln
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 15.0.27130.2027
|
VisualStudioVersion = 16.0.29519.87
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi", "Ombi\Ombi.csproj", "{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi", "Ombi\Ombi.csproj", "{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}"
|
||||||
EndProject
|
EndProject
|
||||||
|
@ -100,6 +100,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Helpers.Tests", "Ombi.
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Gotify", "Ombi.Api.Gotify\Ombi.Api.Gotify.csproj", "{105EA346-766E-45B8-928B-DE6991DCB7EB}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Gotify", "Ombi.Api.Gotify\Ombi.Api.Gotify.csproj", "{105EA346-766E-45B8-928B-DE6991DCB7EB}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Webhook", "Ombi.Api.Webhook\Ombi.Api.Webhook.csproj", "{E2186FDA-D827-4781-8663-130AC382F12C}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -262,6 +264,10 @@ Global
|
||||||
{105EA346-766E-45B8-928B-DE6991DCB7EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{105EA346-766E-45B8-928B-DE6991DCB7EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{105EA346-766E-45B8-928B-DE6991DCB7EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{105EA346-766E-45B8-928B-DE6991DCB7EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{105EA346-766E-45B8-928B-DE6991DCB7EB}.Release|Any CPU.Build.0 = Release|Any CPU
|
{105EA346-766E-45B8-928B-DE6991DCB7EB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E2186FDA-D827-4781-8663-130AC382F12C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E2186FDA-D827-4781-8663-130AC382F12C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E2186FDA-D827-4781-8663-130AC382F12C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E2186FDA-D827-4781-8663-130AC382F12C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -300,6 +306,7 @@ Global
|
||||||
{4FA21A20-92F4-462C-B929-2C517A88CC56} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
{4FA21A20-92F4-462C-B929-2C517A88CC56} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
{CC8CEFCD-0CB6-45BB-845F-508BCAB5BDC3} = {6F42AB98-9196-44C4-B888-D5E409F415A1}
|
{CC8CEFCD-0CB6-45BB-845F-508BCAB5BDC3} = {6F42AB98-9196-44C4-B888-D5E409F415A1}
|
||||||
{105EA346-766E-45B8-928B-DE6991DCB7EB} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
{105EA346-766E-45B8-928B-DE6991DCB7EB} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
|
{E2186FDA-D827-4781-8663-130AC382F12C} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869}
|
SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869}
|
||||||
|
|
|
@ -101,6 +101,11 @@ export interface IGotifyNotificationSettings extends INotificationSettings {
|
||||||
priority: number;
|
priority: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IWebhookNotificationSettings extends INotificationSettings {
|
||||||
|
webhookUrl: string;
|
||||||
|
applicationToken: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IMattermostNotifcationSettings extends INotificationSettings {
|
export interface IMattermostNotifcationSettings extends INotificationSettings {
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
username: string;
|
username: string;
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
<div class="col-sm-8 small-padding">
|
<div class="col-sm-8 small-padding">
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<a *ngIf="node.imdbId" href="{{node.imdbId}}" target="_blank">
|
<a *ngIf="node.imdbId" href="https://www.imdb.com/title/{{node.imdbId}}/" target="_blank">
|
||||||
<h4>{{node.title}} ({{node.firstAired | amLocal | amDateFormat: 'YYYY'}})</h4>
|
<h4>{{node.title}} ({{node.firstAired | amLocal | amDateFormat: 'YYYY'}})</h4>
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -24,6 +24,7 @@ import {
|
||||||
ISlackNotificationSettings,
|
ISlackNotificationSettings,
|
||||||
ISonarrSettings,
|
ISonarrSettings,
|
||||||
ITelegramNotifcationSettings,
|
ITelegramNotifcationSettings,
|
||||||
|
IWebhookNotificationSettings,
|
||||||
} from "../../interfaces";
|
} from "../../interfaces";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -48,6 +49,10 @@ export class TesterService extends ServiceHelpers {
|
||||||
return this.http.post<boolean>(`${this.url}gotify`, JSON.stringify(settings), { headers: this.headers });
|
return this.http.post<boolean>(`${this.url}gotify`, JSON.stringify(settings), { headers: this.headers });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public webhookTest(settings: IWebhookNotificationSettings): Observable<boolean> {
|
||||||
|
return this.http.post<boolean>(`${this.url}webhook`, JSON.stringify(settings), { headers: this.headers });
|
||||||
|
}
|
||||||
|
|
||||||
public mattermostTest(settings: IMattermostNotifcationSettings): Observable<boolean> {
|
public mattermostTest(settings: IMattermostNotifcationSettings): Observable<boolean> {
|
||||||
return this.http.post<boolean>(`${this.url}mattermost`, JSON.stringify(settings), {headers: this.headers});
|
return this.http.post<boolean>(`${this.url}mattermost`, JSON.stringify(settings), {headers: this.headers});
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import {
|
||||||
IUpdateSettings,
|
IUpdateSettings,
|
||||||
IUserManagementSettings,
|
IUserManagementSettings,
|
||||||
IVoteSettings,
|
IVoteSettings,
|
||||||
|
IWebhookNotificationSettings,
|
||||||
} from "../interfaces";
|
} from "../interfaces";
|
||||||
|
|
||||||
import { ServiceHelpers } from "./service.helpers";
|
import { ServiceHelpers } from "./service.helpers";
|
||||||
|
@ -192,6 +193,14 @@ export class SettingsService extends ServiceHelpers {
|
||||||
.post<boolean>(`${this.url}/notifications/gotify`, JSON.stringify(settings), { headers: this.headers });
|
.post<boolean>(`${this.url}/notifications/gotify`, JSON.stringify(settings), { headers: this.headers });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getWebhookNotificationSettings(): Observable<IWebhookNotificationSettings> {
|
||||||
|
return this.http.get<IWebhookNotificationSettings>(`${this.url}/notifications/webhook`, { headers: this.headers });
|
||||||
|
}
|
||||||
|
public saveWebhookNotificationSettings(settings: IWebhookNotificationSettings): Observable<boolean> {
|
||||||
|
return this.http
|
||||||
|
.post<boolean>(`${this.url}/notifications/webhook`, JSON.stringify(settings), { headers: this.headers });
|
||||||
|
}
|
||||||
|
|
||||||
public getSlackNotificationSettings(): Observable<ISlackNotificationSettings> {
|
public getSlackNotificationSettings(): Observable<ISlackNotificationSettings> {
|
||||||
return this.http.get<ISlackNotificationSettings>(`${this.url}/notifications/slack`, {headers: this.headers});
|
return this.http.get<ISlackNotificationSettings>(`${this.url}/notifications/slack`, {headers: this.headers});
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="subDir" class="control-label">Base URL</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" class="form-control-custom form-control" id="subDir" [(ngModel)]="server.subDir" value="{{server.subDir}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="authToken" class="control-label">Emby Api Key</label>
|
<label for="authToken" class="control-label">Emby Api Key</label>
|
||||||
<div class="">
|
<div class="">
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
|
||||||
|
<settings-menu></settings-menu>
|
||||||
|
<div *ngIf="form">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Webhook Notifications</legend>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="checkbox">
|
||||||
|
<input type="checkbox" id="enable" formControlName="enabled">
|
||||||
|
<label for="enable">Enabled</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="baseUrl" class="control-label">Base URL</label>
|
||||||
|
|
||||||
|
<input type="text" class="form-control form-control-custom " id="webhookUrl" name="webhookUrl" [ngClass]="{'form-error': form.get('webhookUrl').hasError('required')}" formControlName="webhookUrl" pTooltip="Enter the URL of your webhook server.">
|
||||||
|
<small *ngIf="form.get('webhookUrl').hasError('required')" class="error-text">The Webhook URL is required</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="applicationToken" class="control-label">Application Token
|
||||||
|
<i class="fa fa-question-circle" pTooltip="Optional authentication token. Will be sent as 'Access-Token' header."></i>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<input type="text" class="form-control form-control-custom " id="applicationToken" name="applicationToken" [ngClass]="{'form-error': form.get('applicationToken').hasError('required')}" formControlName="applicationToken" pTooltip="Enter your Application token from Webhook.">
|
||||||
|
<small *ngIf="form.get('applicationToken').hasError('required')" class="error-text">The Application Token is required</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<button [disabled]="form.invalid" type="button" (click)="test(form)" class="btn btn-primary-outline">
|
||||||
|
Test
|
||||||
|
<div id="spinner"></div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<button [disabled]="form.invalid" type="submit" id="save" class="btn btn-primary-outline">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||||
|
|
||||||
|
import { INotificationTemplates, IWebhookNotificationSettings, NotificationType } from "../../interfaces";
|
||||||
|
import { TesterService } from "../../services";
|
||||||
|
import { NotificationService } from "../../services";
|
||||||
|
import { SettingsService } from "../../services";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "./webhook.component.html",
|
||||||
|
})
|
||||||
|
export class WebhookComponent implements OnInit {
|
||||||
|
public NotificationType = NotificationType;
|
||||||
|
public templates: INotificationTemplates[];
|
||||||
|
public form: FormGroup;
|
||||||
|
|
||||||
|
constructor(private settingsService: SettingsService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private testerService: TesterService) { }
|
||||||
|
|
||||||
|
public ngOnInit() {
|
||||||
|
this.settingsService.getWebhookNotificationSettings().subscribe(x => {
|
||||||
|
this.form = this.fb.group({
|
||||||
|
enabled: [x.enabled],
|
||||||
|
webhookUrl: [x.webhookUrl, [Validators.required]],
|
||||||
|
applicationToken: [x.applicationToken],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public onSubmit(form: FormGroup) {
|
||||||
|
if (form.invalid) {
|
||||||
|
this.notificationService.error("Please check your entered values");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = <IWebhookNotificationSettings> form.value;
|
||||||
|
|
||||||
|
this.settingsService.saveWebhookNotificationSettings(settings).subscribe(x => {
|
||||||
|
if (x) {
|
||||||
|
this.notificationService.success("Successfully saved the Webhook settings");
|
||||||
|
} else {
|
||||||
|
this.notificationService.success("There was an error when saving the Webhook settings");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public test(form: FormGroup) {
|
||||||
|
if (form.invalid) {
|
||||||
|
this.notificationService.error("Please check your entered values");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.testerService.webhookTest(form.value).subscribe(x => {
|
||||||
|
if (x) {
|
||||||
|
this.notificationService.success("Successfully sent a Webhook message");
|
||||||
|
} else {
|
||||||
|
this.notificationService.error("There was an error when sending the Webhook message. Please check your settings");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ import { PushbulletComponent } from "./notifications/pushbullet.component";
|
||||||
import { PushoverComponent } from "./notifications/pushover.component";
|
import { PushoverComponent } from "./notifications/pushover.component";
|
||||||
import { SlackComponent } from "./notifications/slack.component";
|
import { SlackComponent } from "./notifications/slack.component";
|
||||||
import { TelegramComponent } from "./notifications/telegram.component";
|
import { TelegramComponent } from "./notifications/telegram.component";
|
||||||
|
import { WebhookComponent } from "./notifications/webhook.component";
|
||||||
import { OmbiComponent } from "./ombi/ombi.component";
|
import { OmbiComponent } from "./ombi/ombi.component";
|
||||||
import { PlexComponent } from "./plex/plex.component";
|
import { PlexComponent } from "./plex/plex.component";
|
||||||
import { RadarrComponent } from "./radarr/radarr.component";
|
import { RadarrComponent } from "./radarr/radarr.component";
|
||||||
|
@ -67,6 +68,7 @@ const routes: Routes = [
|
||||||
{ path: "Pushover", component: PushoverComponent, canActivate: [AuthGuard] },
|
{ path: "Pushover", component: PushoverComponent, canActivate: [AuthGuard] },
|
||||||
{ path: "Pushbullet", component: PushbulletComponent, canActivate: [AuthGuard] },
|
{ path: "Pushbullet", component: PushbulletComponent, canActivate: [AuthGuard] },
|
||||||
{ path: "Gotify", component: GotifyComponent, canActivate: [AuthGuard] },
|
{ path: "Gotify", component: GotifyComponent, canActivate: [AuthGuard] },
|
||||||
|
{ path: "Webhook", component: WebhookComponent, canActivate: [AuthGuard] },
|
||||||
{ path: "Mattermost", component: MattermostComponent, canActivate: [AuthGuard] },
|
{ path: "Mattermost", component: MattermostComponent, canActivate: [AuthGuard] },
|
||||||
{ path: "UserManagement", component: UserManagementComponent, canActivate: [AuthGuard] },
|
{ path: "UserManagement", component: UserManagementComponent, canActivate: [AuthGuard] },
|
||||||
{ path: "Update", component: UpdateComponent, canActivate: [AuthGuard] },
|
{ path: "Update", component: UpdateComponent, canActivate: [AuthGuard] },
|
||||||
|
@ -124,6 +126,7 @@ const routes: Routes = [
|
||||||
MattermostComponent,
|
MattermostComponent,
|
||||||
PushbulletComponent,
|
PushbulletComponent,
|
||||||
GotifyComponent,
|
GotifyComponent,
|
||||||
|
WebhookComponent,
|
||||||
UserManagementComponent,
|
UserManagementComponent,
|
||||||
UpdateComponent,
|
UpdateComponent,
|
||||||
AboutComponent,
|
AboutComponent,
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Mattermost']">Mattermost</a></li>
|
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Mattermost']">Mattermost</a></li>
|
||||||
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Telegram']">Telegram</a></li>
|
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Telegram']">Telegram</a></li>
|
||||||
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Gotify']">Gotify</a></li>
|
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Gotify']">Gotify</a></li>
|
||||||
|
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Webhook']">Webhook</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace Ombi.Controllers.External
|
||||||
IPushbulletNotification pushbullet, ISlackNotification slack, IPushoverNotification po, IMattermostNotification mm,
|
IPushbulletNotification pushbullet, ISlackNotification slack, IPushoverNotification po, IMattermostNotification mm,
|
||||||
IPlexApi plex, IEmbyApi emby, IRadarrApi radarr, ISonarrApi sonarr, ILogger<TesterController> log, IEmailProvider provider,
|
IPlexApi plex, IEmbyApi emby, IRadarrApi radarr, ISonarrApi sonarr, ILogger<TesterController> log, IEmailProvider provider,
|
||||||
ICouchPotatoApi cpApi, ITelegramNotification telegram, ISickRageApi srApi, INewsletterJob newsletter, IMobileNotification mobileNotification,
|
ICouchPotatoApi cpApi, ITelegramNotification telegram, ISickRageApi srApi, INewsletterJob newsletter, IMobileNotification mobileNotification,
|
||||||
ILidarrApi lidarrApi, IGotifyNotification gotifyNotification)
|
ILidarrApi lidarrApi, IGotifyNotification gotifyNotification, IWebhookNotification webhookNotification)
|
||||||
{
|
{
|
||||||
Service = service;
|
Service = service;
|
||||||
DiscordNotification = notification;
|
DiscordNotification = notification;
|
||||||
|
@ -62,6 +62,7 @@ namespace Ombi.Controllers.External
|
||||||
MobileNotification = mobileNotification;
|
MobileNotification = mobileNotification;
|
||||||
LidarrApi = lidarrApi;
|
LidarrApi = lidarrApi;
|
||||||
GotifyNotification = gotifyNotification;
|
GotifyNotification = gotifyNotification;
|
||||||
|
WebhookNotification = webhookNotification;
|
||||||
}
|
}
|
||||||
|
|
||||||
private INotificationService Service { get; }
|
private INotificationService Service { get; }
|
||||||
|
@ -71,6 +72,7 @@ namespace Ombi.Controllers.External
|
||||||
private ISlackNotification SlackNotification { get; }
|
private ISlackNotification SlackNotification { get; }
|
||||||
private IPushoverNotification PushoverNotification { get; }
|
private IPushoverNotification PushoverNotification { get; }
|
||||||
private IGotifyNotification GotifyNotification { get; }
|
private IGotifyNotification GotifyNotification { get; }
|
||||||
|
private IWebhookNotification WebhookNotification { get; }
|
||||||
private IMattermostNotification MattermostNotification { get; }
|
private IMattermostNotification MattermostNotification { get; }
|
||||||
private IPlexApi PlexApi { get; }
|
private IPlexApi PlexApi { get; }
|
||||||
private IRadarrApi RadarrApi { get; }
|
private IRadarrApi RadarrApi { get; }
|
||||||
|
@ -181,6 +183,30 @@ namespace Ombi.Controllers.External
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a test message to configured webhook using the provided settings
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="settings">The settings.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("webhook")]
|
||||||
|
public bool Webhook([FromBody] WebhookSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
settings.Enabled = true;
|
||||||
|
WebhookNotification.NotifyAsync(
|
||||||
|
new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.LogError(LoggingEvents.Api, e, "Could not test your webhook");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a test message to mattermost using the provided settings
|
/// Sends a test message to mattermost using the provided settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1007,6 +1007,33 @@ namespace Ombi.Controllers
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the webhook notification settings.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The model.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("notifications/webhook")]
|
||||||
|
public async Task<bool> WebhookNotificationSettings([FromBody] WebhookNotificationViewModel model)
|
||||||
|
{
|
||||||
|
var settings = Mapper.Map<WebhookSettings>(model);
|
||||||
|
var result = await Save(settings);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the webhook notification settings.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("notifications/webhook")]
|
||||||
|
public async Task<WebhookNotificationViewModel> WebhookNotificationSettings()
|
||||||
|
{
|
||||||
|
var settings = await Get<WebhookSettings>();
|
||||||
|
var model = Mapper.Map<WebhookNotificationViewModel>(settings);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves the Newsletter notification settings.
|
/// Saves the Newsletter notification settings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -55,9 +55,9 @@
|
||||||
"UpdateAvailableTooltip": "Mise à jour disponible !",
|
"UpdateAvailableTooltip": "Mise à jour disponible !",
|
||||||
"Settings": "Paramètres",
|
"Settings": "Paramètres",
|
||||||
"Welcome": "Bienvenue {{username}}",
|
"Welcome": "Bienvenue {{username}}",
|
||||||
"UpdateDetails": "Détails de la mise à jour",
|
"UpdateDetails": "Identifiant et mot de passe",
|
||||||
"Logout": "Déconnexion",
|
"Logout": "Déconnexion",
|
||||||
"OpenMobileApp": "Ouvrir l'application mobile",
|
"OpenMobileApp": "Ouvrir l'application",
|
||||||
"RecentlyAdded": "Ajouts récents"
|
"RecentlyAdded": "Ajouts récents"
|
||||||
},
|
},
|
||||||
"Search": {
|
"Search": {
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
"RequestAdded": "Kérés sikeresen leadva erre: {{title}}",
|
"RequestAdded": "Kérés sikeresen leadva erre: {{title}}",
|
||||||
"Similar": "Hasonló",
|
"Similar": "Hasonló",
|
||||||
"Refine": "Finomítás",
|
"Refine": "Finomítás",
|
||||||
"SearchBarPlaceholder": "Type Here to Search",
|
"SearchBarPlaceholder": "A kereséshez írj be valamit",
|
||||||
"Movies": {
|
"Movies": {
|
||||||
"PopularMovies": "Népszerű filmek",
|
"PopularMovies": "Népszerű filmek",
|
||||||
"UpcomingMovies": "Közelgő filmek",
|
"UpcomingMovies": "Közelgő filmek",
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"SignInButton": "Войти",
|
"SignInButton": "Войти",
|
||||||
"UsernamePlaceholder": "Имя пользователя",
|
"UsernamePlaceholder": "Имя пользователя",
|
||||||
"PasswordPlaceholder": "Пароль",
|
"PasswordPlaceholder": "Пароль",
|
||||||
"RememberMe": "Запомнить Меня",
|
"RememberMe": "Запомнить меня",
|
||||||
"ForgottenPassword": "Забыли пароль?",
|
"ForgottenPassword": "Забыли пароль?",
|
||||||
"Errors": {
|
"Errors": {
|
||||||
"IncorrectCredentials": "Неверное имя пользователя или пароль"
|
"IncorrectCredentials": "Неверное имя пользователя или пароль"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue