Added Telegram Notification support, Not tested.

pull/1676/head
Jamie 7 years ago
parent 5e48c66325
commit e526c1071a

@ -12,7 +12,7 @@ ____
[![Report a bug](http://i.imgur.com/xSpw482.png)](https://github.com/tidusjar/Ombi/issues/new) [![Feature request](http://i.imgur.com/mFO0OuX.png)](http://feathub.com/tidusjar/Ombi) [![Report a bug](http://i.imgur.com/xSpw482.png)](https://github.com/tidusjar/Ombi/issues/new) [![Feature request](http://i.imgur.com/mFO0OuX.png)](http://feathub.com/tidusjar/Ombi)
| Service | Master (Version 2.0 - Recommended) | Open Beta (Version 3.0) | | Service | Master (V2) | Open Beta (V3 - Recommended) |
|----------|:---------------------------:|:----------------------------:| |----------|:---------------------------:|:----------------------------:|
| AppVeyor | [![Build status](https://ci.appveyor.com/api/projects/status/hgj8j6lcea7j0yhn/branch/master?svg=true)](https://ci.appveyor.com/project/tidusjar/requestplex/branch/master) | [![Build status](https://ci.appveyor.com/api/projects/status/hgj8j6lcea7j0yhn/branch/DotNetCore?svg=true)](https://ci.appveyor.com/project/tidusjar/requestplex/branch/DotNetCore) | | AppVeyor | [![Build status](https://ci.appveyor.com/api/projects/status/hgj8j6lcea7j0yhn/branch/master?svg=true)](https://ci.appveyor.com/project/tidusjar/requestplex/branch/master) | [![Build status](https://ci.appveyor.com/api/projects/status/hgj8j6lcea7j0yhn/branch/DotNetCore?svg=true)](https://ci.appveyor.com/project/tidusjar/requestplex/branch/DotNetCore) |
| Download |[![Download](http://i.imgur.com/odToka3.png)](https://github.com/tidusjar/Ombi/releases) | [![Download](http://i.imgur.com/odToka3.png)](https://ci.appveyor.com/project/tidusjar/requestplex/branch/DotNetCore/artifacts) | | Download |[![Download](http://i.imgur.com/odToka3.png)](https://github.com/tidusjar/Ombi/releases) | [![Download](http://i.imgur.com/odToka3.png)](https://ci.appveyor.com/project/tidusjar/requestplex/branch/DotNetCore/artifacts) |
@ -24,19 +24,19 @@ Here are some of the features Ombi V3 has:
* User management system (supports plex.tv, Emby and local accounts) * User management system (supports plex.tv, Emby and local accounts)
* A landing page that will give you the availability of your Plex/Emby server and also add custom notification text to inform your users of downtime. * A landing page that will give you the availability of your Plex/Emby server and also add custom notification text to inform your users of downtime.
* Allows your users to get custom notifications! * Allows your users to get custom notifications!
* Secure authentication so you don't have to worry about those script kiddies * Secure authentication using best practises
* Will show if the request is already on plex or even if it's already monitored. * Will show if the request is already on plex or even if it's already monitored.
* Automatically updates the status of requests when they are available on Plex/Emby * Automatically updates the status of requests when they are available on Plex/Emby
* Slick, responsive and mobile friendly UI * Slick, responsive and mobile friendly UI
* Ombi will automatically update itself :) * Ombi will automatically update itself :)
* Very fast system. * Very fast!
### Integration ### Integration
We integrate with the following applications: We integrate with the following applications:
* Plex Media Server * Plex Media Server
* Emby * Emby
* Sonarr * Sonarr
* Radarr (beta) * Radarr
* DogNzb * DogNzb
* Couch Potato * Couch Potato
@ -49,30 +49,31 @@ Supported notifications:
* Pushbullet * Pushbullet
* Pushover * Pushover
* Mattermost * Mattermost
* Telegram
### The difference between Version 3 and 2 ### The difference between Version 3 and 2
Over the last 7 months, we focused on the main functions on Ombi, a complete rewrite while making it better, faster and more stable. Over the last 8 months, we focused on the main functions on Ombi, a complete rewrite while making it better, faster and more stable.
We have already done most of the work, but some features are still be missing in this first version. We have already done most of the work, but some features are still be missing in this first version.
We are planning to bring back these features in Version 3 but for now you can find a list below with a comparison of features between v2 and v3. We are planning to bring back these features in V3 but for now you can find a list below with a quick comparison of features between v2 and v3.
| Service | Version 3 | Version 2 | | Service | Version 3 | Version 2 |
|----------|:----------:|:----------:| |----------|:----------:|:----------:|
| Supported online | Yes | No | | Multiple Plex/Emby Servers| Yes | No |
|Multiple Plex/Emby Servers| Yes | No |
| Emby & Plex support | Yes | Yes | | Emby & Plex support | Yes | Yes |
| Mono dependency | No | Yes | | Mono dependency | No | Yes |
| Notifications support | Yes| Yes | | Notifications support | Yes| Yes |
| Landing page | Yes (brand new) | Yes | | Landing page | Yes (brand new) | Yes |
| Login page | Yes (brand new) | Yes | | Login page | Yes (brand new) | Yes |
| Custom Logo in Ombi and notifications | Yes | No | | Custom Notification Messages | Yes | No |
| Sending newsletters | Planned | Yes | | Sending newsletters | Planned | Yes |
| Send a Mass Email | Planned | Yes | | Send a Mass Email | Planned | Yes |
| SickRage | Planned (not supported yet)| Yes | | SickRage | Planned | Yes |
| CouchPotato | Yes | Yes | | CouchPotato | Yes | Yes |
| Watcher | Planned | Yes | | Watcher | Planned | Yes |
| DogNzb | Yes | No | | DogNzb | Yes | No |
| Issues | Planned | Yes |
| Headphones | No (support dropped) | Yes | | Headphones | No (support dropped) | Yes |
# Feature Requests # Feature Requests
@ -89,17 +90,7 @@ Search the existing requests to see if your suggestion has already been submitte
# Installation # Installation
Windows: Download the windows zip file above and run ombi.exe [Click Here](https://github.com/tidusjar/Ombi/wiki/Installation)
Linux: Download the linux zip file, run chmod +x Ombi to make the Ombi file an executable.
Get the following error?
libunwind.so.8: cannot open shared object file
You may need to install libwind8.
```apt-get install libunwind8```
# FAQ
Do you have an issue or a question? if so check out our [FAQ](https://github.com/tidusjar/Ombi/wiki/FAQ)!
# Contributors # Contributors
@ -113,7 +104,7 @@ If you feel like donating you can donate with the below buttons!
[![Patreon](https://www.ombi.io/img/patreondonate.svg)](https://patreon.com/tidusjar/Ombi) [![Patreon](https://www.ombi.io/img/patreondonate.svg)](https://patreon.com/tidusjar/Ombi)
[![Paypal](https://www.ombi.io/img/paypaldonate.svg)](https://paypal.me/PlexRequestsNet) [![Paypal](https://www.ombi.io/img/paypaldonate.svg)](https://paypal.me/PlexRequestsNet)
### A massive thanks to everyone for all their helps! ### A massive thanks to everyone for all their help!
## Stats ## Stats
[![Throughput Graph](https://graphs.waffle.io/tidusjar/PlexRequests.Net/throughput.svg)](https://waffle.io/tidusjar/PlexRequests.Net/metrics/throughput) [![Throughput Graph](https://graphs.waffle.io/tidusjar/PlexRequests.Net/throughput.svg)](https://waffle.io/tidusjar/PlexRequests.Net/metrics/throughput)

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Ombi.Api.Telegram
{
public interface ITelegramApi
{
Task Send(string message, string botApi, string chatId, string parseMode);
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,33 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace Ombi.Api.Telegram
{
public class TelegramApi : ITelegramApi
{
public TelegramApi(IApi api)
{
_api = api;
}
private readonly IApi _api;
private const string BaseUrl = "https://api.telegram.org/bot";
public async Task Send(string message, string botApi, string chatId, string parseMode)
{
var request = new Request($"{botApi}/sendMessage", BaseUrl, HttpMethod.Post);
request.AddQueryString("chat_id", chatId);
var body = new
{
text = message,
parse_mode = parseMode
};
request.AddJsonBody(body);
await _api.Request(request);
}
}
}

@ -0,0 +1,21 @@
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="TelegramNotificationsViewModel" />
public class TelegramNotificationsViewModel : TelegramSettings
{
/// <summary>
/// Gets or sets the notification templates.
/// </summary>
/// <value>
/// The notification templates.
/// </value>
public List<NotificationTemplates> NotificationTemplates { get; set; }
}
}

@ -44,10 +44,10 @@ using Ombi.Schedule.Jobs.Emby;
using Ombi.Schedule.Jobs.Ombi; using Ombi.Schedule.Jobs.Ombi;
using Ombi.Schedule.Jobs.Plex; using Ombi.Schedule.Jobs.Plex;
using Ombi.Schedule.Jobs.Sonarr; using Ombi.Schedule.Jobs.Sonarr;
using Ombi.Store.Entities;
using Ombi.Store.Repository.Requests; using Ombi.Store.Repository.Requests;
using Ombi.Updater; using Ombi.Updater;
using PlexContentCacher = Ombi.Schedule.Jobs.Plex.PlexContentCacher; using PlexContentCacher = Ombi.Schedule.Jobs.Plex.PlexContentCacher;
using Ombi.Api.Telegram;
namespace Ombi.DependencyInjection namespace Ombi.DependencyInjection
{ {
@ -99,6 +99,7 @@ namespace Ombi.DependencyInjection
services.AddTransient<IMattermostApi, MattermostApi>(); services.AddTransient<IMattermostApi, MattermostApi>();
services.AddTransient<ICouchPotatoApi, CouchPotatoApi>(); services.AddTransient<ICouchPotatoApi, CouchPotatoApi>();
services.AddTransient<IDogNzbApi, DogNzbApi>(); services.AddTransient<IDogNzbApi, DogNzbApi>();
services.AddTransient<ITelegramApi, TelegramApi>();
} }
public static void RegisterStore(this IServiceCollection services) { public static void RegisterStore(this IServiceCollection services) {

@ -28,6 +28,7 @@
<ProjectReference Include="..\Ombi.Api.Service\Ombi.Api.Service.csproj" /> <ProjectReference Include="..\Ombi.Api.Service\Ombi.Api.Service.csproj" />
<ProjectReference Include="..\Ombi.Api.Slack\Ombi.Api.Slack.csproj" /> <ProjectReference Include="..\Ombi.Api.Slack\Ombi.Api.Slack.csproj" />
<ProjectReference Include="..\Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj" /> <ProjectReference Include="..\Ombi.Api.Sonarr\Ombi.Api.Sonarr.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.Core\Ombi.Core.csproj" /> <ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />

@ -27,6 +27,7 @@ namespace Ombi.Helpers
public static EventId SlackNotification => new EventId(4003); public static EventId SlackNotification => new EventId(4003);
public static EventId MattermostNotification => new EventId(4004); public static EventId MattermostNotification => new EventId(4004);
public static EventId PushoverNotification => new EventId(4005); public static EventId PushoverNotification => new EventId(4005);
public static EventId TelegramNotifcation => new EventId(4006);
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);

@ -14,6 +14,7 @@ namespace Ombi.Mapping.Profiles
CreateMap<SlackNotificationsViewModel, SlackNotificationSettings>().ReverseMap(); CreateMap<SlackNotificationsViewModel, SlackNotificationSettings>().ReverseMap();
CreateMap<PushoverNotificationViewModel, PushoverSettings>().ReverseMap(); CreateMap<PushoverNotificationViewModel, PushoverSettings>().ReverseMap();
CreateMap<MattermostNotificationsViewModel, MattermostNotificationSettings>().ReverseMap(); CreateMap<MattermostNotificationsViewModel, MattermostNotificationSettings>().ReverseMap();
CreateMap<TelegramNotificationsViewModel, TelegramSettings>().ReverseMap();
} }
} }
} }

@ -0,0 +1,144 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Notifications.Interfaces;
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;
using Ombi.Api.Telegram;
namespace Ombi.Notifications.Agents
{
public class TelegramNotification : BaseNotification<TelegramSettings>
{
public TelegramNotification(ITelegramApi api, ISettingsService<TelegramSettings> sn, ILogger<TelegramNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, ISettingsService<CustomizationSettings> s) : base(sn, r, m, t,s)
{
Api = api;
Logger = log;
}
public override string NotificationName => "TelegramNotification";
private ITelegramApi Api { get; }
private ILogger<TelegramNotification> Logger { get; }
protected override bool ValidateConfiguration(TelegramSettings settings)
{
if (!settings.Enabled)
{
return false;
}
return !settings.BotApi.IsNullOrEmpty() && !settings.ChatId.IsNullOrEmpty();
}
protected override async Task NewRequest(NotificationOptions model, TelegramSettings settings)
{
var parsed = await LoadTemplate(NotificationAgent.Telegram, NotificationType.NewRequest, model);
var notification = new NotificationMessage
{
Message = parsed.Message,
};
await Send(notification, settings);
}
protected override async Task Issue(NotificationOptions model, TelegramSettings settings)
{
var parsed = await LoadTemplate(NotificationAgent.Telegram, NotificationType.Issue, model);
var notification = new NotificationMessage
{
Message = parsed.Message,
};
await Send(notification, settings);
}
protected override async Task AddedToRequestQueue(NotificationOptions model, TelegramSettings settings)
{
var user = string.Empty;
var title = string.Empty;
var image = string.Empty;
if (model.RequestType == RequestType.Movie)
{
user = MovieRequest.RequestedUser.UserAlias;
title = MovieRequest.Title;
image = MovieRequest.PosterPath;
}
else
{
user = TvRequest.RequestedUser.UserAlias;
title = TvRequest.ParentRequest.Title;
image = TvRequest.ParentRequest.PosterPath;
}
var message = $"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying";
var notification = new NotificationMessage
{
Message = message
};
await Send(notification, settings);
}
protected override async Task RequestDeclined(NotificationOptions model, TelegramSettings settings)
{
var parsed = await LoadTemplate(NotificationAgent.Telegram, NotificationType.RequestDeclined, model);
var notification = new NotificationMessage
{
Message = parsed.Message,
};
await Send(notification, settings);
}
protected override async Task RequestApproved(NotificationOptions model, TelegramSettings settings)
{
var parsed = await LoadTemplate(NotificationAgent.Telegram, NotificationType.RequestApproved, model);
var notification = new NotificationMessage
{
Message = parsed.Message,
};
await Send(notification, settings);
}
protected override async Task AvailableRequest(NotificationOptions model, TelegramSettings settings)
{
var parsed = await LoadTemplate(NotificationAgent.Telegram, NotificationType.RequestAvailable, model);
var notification = new NotificationMessage
{
Message = parsed.Message,
};
await Send(notification, settings);
}
protected override async Task Send(NotificationMessage model, TelegramSettings settings)
{
try
{
await Api.Send(model.Message, settings.BotApi, settings.ChatId, settings.ParseMode);
}
catch (Exception e)
{
Logger.LogError(LoggingEvents.TelegramNotifcation, e, "Failed to send Telegram Notification");
}
}
protected override async Task Test(NotificationOptions model, TelegramSettings settings)
{
var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!";
var notification = new NotificationMessage
{
Message = message,
};
await Send(notification, settings);
}
}
}

@ -19,6 +19,7 @@
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" /> <ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
<ProjectReference Include="..\Ombi.Api.Pushover\Ombi.Api.Pushover.csproj" /> <ProjectReference Include="..\Ombi.Api.Pushover\Ombi.Api.Pushover.csproj" />
<ProjectReference Include="..\Ombi.Api.Slack\Ombi.Api.Slack.csproj" /> <ProjectReference Include="..\Ombi.Api.Slack\Ombi.Api.Slack.csproj" />
<ProjectReference Include="..\Ombi.Api.Telegram\Ombi.Api.Telegram.csproj" />
<ProjectReference Include="..\Ombi.Notifications.Templates\Ombi.Notifications.Templates.csproj" /> <ProjectReference Include="..\Ombi.Notifications.Templates\Ombi.Notifications.Templates.csproj" />
<ProjectReference Include="..\Ombi.Settings\Ombi.Settings.csproj" /> <ProjectReference Include="..\Ombi.Settings\Ombi.Settings.csproj" />
<ProjectReference Include="..\Ombi.Store\Ombi.Store.csproj" /> <ProjectReference Include="..\Ombi.Store\Ombi.Store.csproj" />

@ -0,0 +1,10 @@
namespace Ombi.Settings.Settings.Models.Notifications
{
public class TelegramSettings : Settings
{
public bool Enabled { get; set; }
public string BotApi { get; set; }
public string ChatId { get; set; }
public string ParseMode { get; set; }
}
}

@ -84,7 +84,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.CouchPotato", "Omb
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.DogNzb", "Ombi.Api.DogNzb\Ombi.Api.DogNzb.csproj", "{4F3BF03A-6AAC-4960-A2CD-1EAD7273115E}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.DogNzb", "Ombi.Api.DogNzb\Ombi.Api.DogNzb.csproj", "{4F3BF03A-6AAC-4960-A2CD-1EAD7273115E}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Tests", "Ombi.Tests\Ombi.Tests.csproj", "{C12F5276-352A-43CF-8E33-400E768E9757}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Tests", "Ombi.Tests\Ombi.Tests.csproj", "{C12F5276-352A-43CF-8E33-400E768E9757}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Telegram", "Ombi.Api.Telegram\Ombi.Api.Telegram.csproj", "{CB9DD209-8E09-4E01-983E-C77C89592D36}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -220,6 +222,10 @@ Global
{C12F5276-352A-43CF-8E33-400E768E9757}.Debug|Any CPU.Build.0 = Debug|Any CPU {C12F5276-352A-43CF-8E33-400E768E9757}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C12F5276-352A-43CF-8E33-400E768E9757}.Release|Any CPU.ActiveCfg = Release|Any CPU {C12F5276-352A-43CF-8E33-400E768E9757}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C12F5276-352A-43CF-8E33-400E768E9757}.Release|Any CPU.Build.0 = Release|Any CPU {C12F5276-352A-43CF-8E33-400E768E9757}.Release|Any CPU.Build.0 = Release|Any CPU
{CB9DD209-8E09-4E01-983E-C77C89592D36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB9DD209-8E09-4E01-983E-C77C89592D36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB9DD209-8E09-4E01-983E-C77C89592D36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB9DD209-8E09-4E01-983E-C77C89592D36}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -251,6 +257,7 @@ Global
{87D7897D-7C73-4856-A0AA-FF5948F4EA86} = {9293CA11-360A-4C20-A674-B9E794431BF5} {87D7897D-7C73-4856-A0AA-FF5948F4EA86} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{4F3BF03A-6AAC-4960-A2CD-1EAD7273115E} = {9293CA11-360A-4C20-A674-B9E794431BF5} {4F3BF03A-6AAC-4960-A2CD-1EAD7273115E} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{C12F5276-352A-43CF-8E33-400E768E9757} = {6F42AB98-9196-44C4-B888-D5E409F415A1} {C12F5276-352A-43CF-8E33-400E768E9757} = {6F42AB98-9196-44C4-B888-D5E409F415A1}
{CB9DD209-8E09-4E01-983E-C77C89592D36} = {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}

@ -52,6 +52,13 @@ export interface IDiscordNotifcationSettings extends INotificationSettings {
notificationTemplates: INotificationTemplates[]; notificationTemplates: INotificationTemplates[];
} }
export interface ITelegramNotifcationSettings extends INotificationSettings {
botApi: string;
chatId: string;
parseMode: string;
notificationTemplates: INotificationTemplates[];
}
export interface ISlackNotificationSettings extends INotificationSettings { export interface ISlackNotificationSettings extends INotificationSettings {
webhookUrl: string; webhookUrl: string;
username: string; username: string;

@ -95,9 +95,13 @@ export interface IFullBaseRequest extends IBaseRequest {
overview: string; overview: string;
title: string; title: string;
posterPath: string; posterPath: string;
backdropPath: string;
releaseDate: Date; releaseDate: Date;
status: string; status: string;
released: boolean; released: boolean;
// Used in the UI
background: any;
} }
export interface IBaseRequest { export interface IBaseRequest {
@ -121,6 +125,7 @@ export interface ITvRequests {
overview: string; overview: string;
title: string; title: string;
posterPath: string; posterPath: string;
backdropPath: string;
releaseDate: Date; releaseDate: Date;
status: string; status: string;
childRequests: IChildRequests[]; childRequests: IChildRequests[];

@ -122,6 +122,9 @@ export class MovieRequestsComponent implements OnInit {
private loadRequests(amountToLoad: number, currentlyLoaded: number) { private loadRequests(amountToLoad: number, currentlyLoaded: number) {
this.requestService.getMovieRequests(amountToLoad, currentlyLoaded + 1) this.requestService.getMovieRequests(amountToLoad, currentlyLoaded + 1)
.subscribe(x => { .subscribe(x => {
// x.background = this.sanitizer.
// bypassSecurityTrustStyle
// ("linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%),url(" + "https://image.tmdb.org/t/p/w1280" + x.backdropPath + ")");
this.setOverrides(x); this.setOverrides(x);
this.movieRequests.push.apply(this.movieRequests, x); this.movieRequests.push.apply(this.movieRequests, x);
this.currentlyLoaded = currentlyLoaded + amountToLoad; this.currentlyLoaded = currentlyLoaded + amountToLoad;

@ -17,6 +17,7 @@ import {
IRadarrSettings, IRadarrSettings,
ISlackNotificationSettings, ISlackNotificationSettings,
ISonarrSettings, ISonarrSettings,
ITelegramNotifcationSettings,
} from "../../interfaces"; } from "../../interfaces";
@Injectable() @Injectable()
@ -61,5 +62,8 @@ export class TesterService extends ServiceAuthHelpers {
} }
public couchPotatoTest(settings: ICouchPotatoSettings): Observable<boolean> { public couchPotatoTest(settings: ICouchPotatoSettings): Observable<boolean> {
return this.http.post(`${this.url}couchpotato`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData); return this.http.post(`${this.url}couchpotato`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
}
public telegramTest(settings: ITelegramNotifcationSettings): Observable<boolean> {
return this.http.post(`${this.url}telegram`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
} }
} }

@ -22,6 +22,7 @@ import {
IRadarrSettings, IRadarrSettings,
ISlackNotificationSettings, ISlackNotificationSettings,
ISonarrSettings, ISonarrSettings,
ITelegramNotifcationSettings,
IUpdateSettings, IUpdateSettings,
IUserManagementSettings, IUserManagementSettings,
} from "../interfaces"; } from "../interfaces";
@ -220,4 +221,14 @@ export class SettingsService extends ServiceAuthHelpers {
.post(`${this.url}/DogNzb`, JSON.stringify(settings), { headers: this.headers }) .post(`${this.url}/DogNzb`, JSON.stringify(settings), { headers: this.headers })
.map(this.extractData).catch(this.handleError); .map(this.extractData).catch(this.handleError);
} }
public getTelegramNotificationSettings(): Observable<ITelegramNotifcationSettings> {
return this.httpAuth.get(`${this.url}/notifications/telegram`).map(this.extractData).catch(this.handleError);
}
public saveTelegramNotificationSettings(settings: ITelegramNotifcationSettings): Observable<boolean> {
return this.httpAuth
.post(`${this.url}/notifications/telegram`, JSON.stringify(settings), { headers: this.headers })
.map(this.extractData).catch(this.handleError);
}
} }

@ -0,0 +1,66 @@
<settings-menu>
</settings-menu>
<div *ngIf="form">
<fieldset>
<legend>Telegram 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="botApi" class="control-label">Bot API</label>
<input type="text" class="form-control form-control-custom " id="botApi" name="botApi" formControlName="botApi" [ngClass]="{'form-error': form.get('botApi').hasError('required')}">
<small *ngIf="form.get('botApi').hasError('required')" class="error-text">The Bot API is required</small>
<small>You need a bot for Telegram notifications, You can find out how to create a bot
<a href="https://core.telegram.org/bots#6-botfather">here</a>.</small>
</div>
<div class="form-group">
<label for="chatId" class="control-label">Chat Id</label>
<input type="text" class="form-control form-control-custom " id="chatId" name="chatId" formControlName="chatId" [ngClass]="{'form-error': form.get('chatId').hasError('required')}">
<small *ngIf="form.get('chatId').hasError('required')" class="error-text">The Chat Id is required</small>
<small>This is the Chat ID from Telegram. You can get the Chat Id from
<a href="https://telegram.me/get_id_bot">here</a>. This also supports Group Chat Id's.</small>
</div>
<div class="form-group">
<p-radioButton name="parseMode" value="markdown" formControlName="parseMode" label="Markdown Formatting"></p-radioButton>
</div>
<div class="form-group">
<p-radioButton name="parseMode" value="html" formControlName="parseMode" label="Html Formatting"></p-radioButton>
</div>
<small>Select a formatting option for the messages, you can view the supported formatting <a href="https://core.telegram.org/bots/api#formatting-options">here</a>.</small>
<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>
<div class="col-md-6">
<notification-templates [templates]="templates"></notification-templates>
</div>
</fieldset>
</div>

@ -0,0 +1,71 @@
import { Component, OnInit } from "@angular/core";
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { INotificationTemplates, ITelegramNotifcationSettings, NotificationType } from "../../interfaces";
import { TesterService } from "../../services";
import { NotificationService } from "../../services";
import { SettingsService } from "../../services";
@Component({
templateUrl: "./telegram.component.html",
})
export class TelegramComponent 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.getTelegramNotificationSettings().subscribe(x => {
this.templates = x.notificationTemplates;
this.form = this.fb.group({
enabled: [x.enabled],
botApi: [x.botApi, [Validators.required]],
chatId: [x.chatId, [Validators.required]],
parseMode: [x.parseMode, [Validators.required]],
});
});
}
public onSubmit(form: FormGroup) {
if (form.invalid) {
this.notificationService.error("Please check your entered values");
return;
}
const settings = <ITelegramNotifcationSettings>form.value;
settings.notificationTemplates = this.templates;
this.settingsService.saveTelegramNotificationSettings(settings).subscribe(x => {
if (x) {
this.notificationService.success("Successfully saved the Telegram settings");
} else {
this.notificationService.success("There was an error when saving the Telegram settings");
}
});
}
public test(form: FormGroup) {
if (form.invalid) {
this.notificationService.error("Please check your entered values");
return;
}
this.testerService.telegramTest(form.value).subscribe(x => {
if (x) {
this.notificationService.success("Successfully sent a Telegram message, please check the Telegram channel");
} else {
this.notificationService.error("There was an error when sending the Telegram message. Please check your settings");
}
});
}
}

@ -24,6 +24,7 @@ import { NotificationTemplate } from "./notifications/notificationtemplate.compo
import { PushbulletComponent } from "./notifications/pushbullet.component"; 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 { 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";
@ -34,7 +35,7 @@ import { WikiComponent } from "./wiki.component";
import { SettingsMenuComponent } from "./settingsmenu.component"; import { SettingsMenuComponent } from "./settingsmenu.component";
import { AutoCompleteModule, CalendarModule, InputSwitchModule, InputTextModule, MenuModule, TooltipModule } from "primeng/primeng"; import { AutoCompleteModule, CalendarModule, InputSwitchModule, InputTextModule, MenuModule, RadioButtonModule, TooltipModule } from "primeng/primeng";
const routes: Routes = [ const routes: Routes = [
{ path: "Settings/Ombi", component: OmbiComponent, canActivate: [AuthGuard] }, { path: "Settings/Ombi", component: OmbiComponent, canActivate: [AuthGuard] },
@ -55,6 +56,7 @@ const routes: Routes = [
{ path: "Settings/Update", component: UpdateComponent, canActivate: [AuthGuard] }, { path: "Settings/Update", component: UpdateComponent, canActivate: [AuthGuard] },
{ path: "Settings/CouchPotato", component: CouchPotatoComponent, canActivate: [AuthGuard] }, { path: "Settings/CouchPotato", component: CouchPotatoComponent, canActivate: [AuthGuard] },
{ path: "Settings/DogNzb", component: DogNzbComponent, canActivate: [AuthGuard] }, { path: "Settings/DogNzb", component: DogNzbComponent, canActivate: [AuthGuard] },
{ path: "Settings/Telegram", component: TelegramComponent, canActivate: [AuthGuard] },
]; ];
@NgModule({ @NgModule({
@ -74,6 +76,7 @@ const routes: Routes = [
CalendarModule, CalendarModule,
ClipboardModule, ClipboardModule,
PipeModule, PipeModule,
RadioButtonModule,
], ],
declarations: [ declarations: [
SettingsMenuComponent, SettingsMenuComponent,
@ -97,6 +100,7 @@ const routes: Routes = [
WikiComponent, WikiComponent,
CouchPotatoComponent, CouchPotatoComponent,
DogNzbComponent, DogNzbComponent,
TelegramComponent,
], ],
exports: [ exports: [
RouterModule, RouterModule,

@ -61,6 +61,7 @@
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Pushbullet']">Pushbullet</a></li> <li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Pushbullet']">Pushbullet</a></li>
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Pushover']">Pushover</a></li> <li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Pushover']">Pushover</a></li>
<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>
</ul> </ul>
</li> </li>

@ -310,4 +310,19 @@ button.list-group-item:focus {
.ui-dialog-titlebar{ .ui-dialog-titlebar{
background:$bg-colour-disabled; background:$bg-colour-disabled;
color:white; color:white;
}
.ui-state-active{
color:$primary-colour $i;
}
.ui-state-default {
border-width: 2px;
border-style: solid;
border-color: $primary-colour-outline;
border-image: initial;
}
.ui-radiobutton, .ui-radiobutton-label{
vertical-align: baseline;
} }

@ -9,6 +9,7 @@ using Ombi.Api.Emby;
using Ombi.Api.Plex; using Ombi.Api.Plex;
using Ombi.Api.Radarr; using Ombi.Api.Radarr;
using Ombi.Api.Sonarr; using Ombi.Api.Sonarr;
using Ombi.Api.Telegram;
using Ombi.Attributes; using Ombi.Attributes;
using Ombi.Core.Notifications; using Ombi.Core.Notifications;
using Ombi.Core.Settings.Models.External; using Ombi.Core.Settings.Models.External;
@ -292,5 +293,20 @@ namespace Ombi.Controllers.External
return false; return false;
} }
} }
/// <summary>
/// Sends a test message to Slack using the provided settings
/// </summary>
/// <param name="settings">The settings.</param>
/// <returns></returns>
//[HttpPost("telegram")]
//public async Task<bool> Telegram([FromBody] TelegramSettings settings)
//{
// settings.Enabled = true;
// await TelegramApi.Send("This is a test ")
// return true;
//}
} }
} }

@ -454,6 +454,41 @@ namespace Ombi.Controllers
return model; return model;
} }
/// <summary>
/// Saves the telegram notification settings.
/// </summary>
/// <param name="model">The model.</param>
/// <returns></returns>
[HttpPost("notifications/telegram")]
public async Task<bool> TelegramNotificationSettings([FromBody] TelegramNotificationsViewModel model)
{
// Save the email settings
var settings = Mapper.Map<TelegramSettings>(model);
var result = await Save(settings);
// Save the templates
await TemplateRepository.UpdateRange(model.NotificationTemplates);
return result;
}
/// <summary>
/// Gets the telegram Notification Settings.
/// </summary>
/// <returns></returns>
[HttpGet("notifications/telegram")]
public async Task<TelegramNotificationsViewModel> TelegramNotificationSettings()
{
var emailSettings = await Get<TelegramSettings>();
var model = Mapper.Map<TelegramNotificationsViewModel>(emailSettings);
// Lookup to see if we have any templates saved
model.NotificationTemplates = await BuildTemplates(NotificationAgent.Telegram);
return model;
}
/// <summary> /// <summary>
/// Saves the pushbullet notification settings. /// Saves the pushbullet notification settings.
/// </summary> /// </summary>

Loading…
Cancel
Save