Merge branch 'develop' of https://github.com/sct/overseerr into jellyfin-support
This commit is contained in:
@@ -1,16 +1,32 @@
|
||||
import axios from 'axios';
|
||||
import { getRepository } from 'typeorm';
|
||||
import { hasNotificationType, Notification } from '..';
|
||||
import { MediaType } from '../../../constants/media';
|
||||
import { User } from '../../../entity/User';
|
||||
import logger from '../../../logger';
|
||||
import { getSettings, NotificationAgentTelegram } from '../../settings';
|
||||
import { Permission } from '../../permissions';
|
||||
import {
|
||||
getSettings,
|
||||
NotificationAgentKey,
|
||||
NotificationAgentTelegram,
|
||||
} from '../../settings';
|
||||
import { BaseAgent, NotificationAgent, NotificationPayload } from './agent';
|
||||
|
||||
interface TelegramPayload {
|
||||
interface TelegramMessagePayload {
|
||||
text: string;
|
||||
parse_mode: string;
|
||||
chat_id: string;
|
||||
disable_notification: boolean;
|
||||
}
|
||||
|
||||
interface TelegramPhotoPayload {
|
||||
photo: string;
|
||||
caption: string;
|
||||
parse_mode: string;
|
||||
chat_id: string;
|
||||
disable_notification: boolean;
|
||||
}
|
||||
|
||||
class TelegramAgent
|
||||
extends BaseAgent<NotificationAgentTelegram>
|
||||
implements NotificationAgent {
|
||||
@@ -26,12 +42,13 @@ class TelegramAgent
|
||||
return settings.notifications.agents.telegram;
|
||||
}
|
||||
|
||||
public shouldSend(type: Notification): boolean {
|
||||
public shouldSend(): boolean {
|
||||
const settings = this.getSettings();
|
||||
|
||||
if (
|
||||
this.getSettings().enabled &&
|
||||
this.getSettings().options.botAPI &&
|
||||
this.getSettings().options.chatId &&
|
||||
hasNotificationType(type, this.getSettings().types)
|
||||
settings.enabled &&
|
||||
settings.options.botAPI &&
|
||||
settings.options.chatId
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -45,20 +62,24 @@ class TelegramAgent
|
||||
|
||||
private buildMessage(
|
||||
type: Notification,
|
||||
payload: NotificationPayload
|
||||
): string {
|
||||
payload: NotificationPayload,
|
||||
chatId: string,
|
||||
sendSilently: boolean
|
||||
): TelegramMessagePayload | TelegramPhotoPayload {
|
||||
const settings = getSettings();
|
||||
let message = '';
|
||||
|
||||
const title = this.escapeText(payload.subject);
|
||||
const plot = this.escapeText(payload.message);
|
||||
const user = this.escapeText(payload.notifyUser.displayName);
|
||||
const user = this.escapeText(payload.request?.requestedBy.displayName);
|
||||
const applicationTitle = this.escapeText(settings.main.applicationTitle);
|
||||
|
||||
/* eslint-disable no-useless-escape */
|
||||
switch (type) {
|
||||
case Notification.MEDIA_PENDING:
|
||||
message += `\*New Request\*`;
|
||||
message += `\*New ${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Request\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
@@ -67,7 +88,20 @@ class TelegramAgent
|
||||
message += `\n\n\*Status\*\nPending Approval`;
|
||||
break;
|
||||
case Notification.MEDIA_APPROVED:
|
||||
message += `\*Request Approved\*`;
|
||||
message += `\*${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Request Approved\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
}
|
||||
message += `\n\n\*Requested By\*\n${user}`;
|
||||
message += `\n\n\*Status\*\nProcessing`;
|
||||
break;
|
||||
case Notification.MEDIA_AUTO_APPROVED:
|
||||
message += `\*${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Request Automatically Approved\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
@@ -76,7 +110,9 @@ class TelegramAgent
|
||||
message += `\n\n\*Status\*\nProcessing`;
|
||||
break;
|
||||
case Notification.MEDIA_AVAILABLE:
|
||||
message += `\*Now Available\*`;
|
||||
message += `\*${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Now Available\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
@@ -85,7 +121,9 @@ class TelegramAgent
|
||||
message += `\n\n\*Status\*\nAvailable`;
|
||||
break;
|
||||
case Notification.MEDIA_DECLINED:
|
||||
message += `\*Request Declined\*`;
|
||||
message += `\*${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Request Declined\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
@@ -94,7 +132,9 @@ class TelegramAgent
|
||||
message += `\n\n\*Status\*\nDeclined`;
|
||||
break;
|
||||
case Notification.MEDIA_FAILED:
|
||||
message += `\*Failed Request\*`;
|
||||
message += `\*Failed ${
|
||||
payload.media?.mediaType === MediaType.TV ? 'Series' : 'Movie'
|
||||
} Request\*`;
|
||||
message += `\n\n\*${title}\*`;
|
||||
if (plot) {
|
||||
message += `\n${plot}`;
|
||||
@@ -108,40 +148,171 @@ class TelegramAgent
|
||||
break;
|
||||
}
|
||||
|
||||
for (const extra of payload.extra ?? []) {
|
||||
message += `\n\n\*${extra.name}\*\n${extra.value}`;
|
||||
}
|
||||
|
||||
if (settings.main.applicationUrl && payload.media) {
|
||||
const actionUrl = `${settings.main.applicationUrl}/${payload.media.mediaType}/${payload.media.tmdbId}`;
|
||||
message += `\n\n\[Open in ${applicationTitle}\]\(${actionUrl}\)`;
|
||||
}
|
||||
/* eslint-enable */
|
||||
|
||||
return message;
|
||||
return payload.image
|
||||
? ({
|
||||
photo: payload.image,
|
||||
caption: message,
|
||||
parse_mode: 'MarkdownV2',
|
||||
chat_id: chatId,
|
||||
disable_notification: !!sendSilently,
|
||||
} as TelegramPhotoPayload)
|
||||
: ({
|
||||
text: message,
|
||||
parse_mode: 'MarkdownV2',
|
||||
chat_id: chatId,
|
||||
disable_notification: !!sendSilently,
|
||||
} as TelegramMessagePayload);
|
||||
}
|
||||
|
||||
public async send(
|
||||
type: Notification,
|
||||
payload: NotificationPayload
|
||||
): Promise<boolean> {
|
||||
logger.debug('Sending telegram notification', { label: 'Notifications' });
|
||||
try {
|
||||
const endpoint = `${this.baseUrl}bot${
|
||||
this.getSettings().options.botAPI
|
||||
}/sendMessage`;
|
||||
const settings = this.getSettings();
|
||||
|
||||
await axios.post(endpoint, {
|
||||
text: this.buildMessage(type, payload),
|
||||
parse_mode: 'MarkdownV2',
|
||||
chat_id: `${this.getSettings().options.chatId}`,
|
||||
disable_notification: this.getSettings().options.sendSilently,
|
||||
} as TelegramPayload);
|
||||
const endpoint = `${this.baseUrl}bot${settings.options.botAPI}/${
|
||||
payload.image ? 'sendPhoto' : 'sendMessage'
|
||||
}`;
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
logger.error('Error sending Telegram notification', {
|
||||
// Send system notification
|
||||
if (hasNotificationType(type, settings.types ?? 0)) {
|
||||
logger.debug('Sending Telegram notification', {
|
||||
label: 'Notifications',
|
||||
message: e.message,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
});
|
||||
return false;
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
endpoint,
|
||||
this.buildMessage(
|
||||
type,
|
||||
payload,
|
||||
settings.options.chatId,
|
||||
settings.options.sendSilently
|
||||
)
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error('Error sending Telegram notification', {
|
||||
label: 'Notifications',
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
errorMessage: e.message,
|
||||
response: e.response?.data,
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (payload.notifyUser) {
|
||||
// Send notification to the user who submitted the request
|
||||
if (
|
||||
payload.notifyUser.settings?.hasNotificationType(
|
||||
NotificationAgentKey.TELEGRAM,
|
||||
type
|
||||
) &&
|
||||
payload.notifyUser.settings?.telegramChatId &&
|
||||
payload.notifyUser.settings?.telegramChatId !== settings.options.chatId
|
||||
) {
|
||||
logger.debug('Sending Telegram notification', {
|
||||
label: 'Notifications',
|
||||
recipient: payload.notifyUser.displayName,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
});
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
endpoint,
|
||||
this.buildMessage(
|
||||
type,
|
||||
payload,
|
||||
payload.notifyUser.settings.telegramChatId,
|
||||
!!payload.notifyUser.settings.telegramSendSilently
|
||||
)
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error('Error sending Telegram notification', {
|
||||
label: 'Notifications',
|
||||
recipient: payload.notifyUser.displayName,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
errorMessage: e.message,
|
||||
response: e.response?.data,
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Send notifications to all users with the Manage Requests permission
|
||||
const userRepository = getRepository(User);
|
||||
const users = await userRepository.find();
|
||||
|
||||
await Promise.all(
|
||||
users
|
||||
.filter(
|
||||
(user) =>
|
||||
user.hasPermission(Permission.MANAGE_REQUESTS) &&
|
||||
user.settings?.hasNotificationType(
|
||||
NotificationAgentKey.TELEGRAM,
|
||||
type
|
||||
) &&
|
||||
// Check if it's the user's own auto-approved request
|
||||
(type !== Notification.MEDIA_AUTO_APPROVED ||
|
||||
user.id !== payload.request?.requestedBy.id)
|
||||
)
|
||||
.map(async (user) => {
|
||||
if (
|
||||
user.settings?.telegramChatId &&
|
||||
user.settings.telegramChatId !== settings.options.chatId
|
||||
) {
|
||||
logger.debug('Sending Telegram notification', {
|
||||
label: 'Notifications',
|
||||
recipient: user.displayName,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
});
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
endpoint,
|
||||
this.buildMessage(
|
||||
type,
|
||||
payload,
|
||||
user.settings.telegramChatId,
|
||||
!!user.settings?.telegramSendSilently
|
||||
)
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error('Error sending Telegram notification', {
|
||||
label: 'Notifications',
|
||||
recipient: user.displayName,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
errorMessage: e.message,
|
||||
response: e.response?.data,
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user