Skip to content

Commit

Permalink
clean up notification broker, fix ntfy
Browse files Browse the repository at this point in the history
related to #493
  • Loading branch information
MrBrax committed Jan 26, 2024
1 parent eac9fef commit abffc39
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 234 deletions.
5 changes: 4 additions & 1 deletion common/Defs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ export const NotificationProvidersList = [
{ id: NotificationProvider.NTFY, name: "Ntfy" },
];

export const NotificationCategories = [
export const NotificationCategories: {
id: NotificationCategory;
name: string;
}[] = [
{ id: "offlineStatusChange", name: "Offline status change" },
{ id: "streamOnline", name: "Stream online" },
{ id: "streamOffline", name: "Stream offline" },
Expand Down
4 changes: 2 additions & 2 deletions common/ServerConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -605,14 +605,14 @@ export const settingsFields: Record<string, SettingField> = {
type: "string",
},

"notify.ntfy.enabled": {
"notifications.ntfy.enabled": {
group: "Notifications (Ntfy)",
text: "Enable Ntfy notifications",
type: "boolean",
default: false,
},

"notify.ntfy.url": {
"notifications.ntfy.url": {
group: "Notifications (Ntfy)",
text: "Ntfy url with topic",
type: "string",
Expand Down
5 changes: 1 addition & 4 deletions server/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ module.exports = {
// "browser": true,
es2021: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended-type-checked",
],
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
Expand Down
252 changes: 26 additions & 226 deletions server/src/Core/ClientBroker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { debugLog } from "@/Helpers/Console";
import type { NotificationCategory } from "@common/Defs";
import { NotificationCategories, NotificationProvider } from "@common/Defs";
import type { NotifyData } from "@common/Webhook";
import type { AxiosError } from "axios";
import axios from "axios";
import chalk from "chalk";
import type express from "express";
import fs from "node:fs";
Expand All @@ -14,6 +12,9 @@ import { BaseConfigPath } from "./BaseConfig";
import { Config } from "./Config";
import { LiveStreamDVR } from "./LiveStreamDVR";
import { LOGLEVEL, log } from "./Log";
import DiscordNotify from "./Notifiers/Discord";
import NtfyNotify from "./Notifiers/Ntfy";
import PushoverNotify from "./Notifiers/Pushover";
import TelegramNotify from "./Notifiers/Telegram";

interface Client {
Expand All @@ -25,107 +26,23 @@ interface Client {
authenticated: boolean;
}

interface DiscordSendMessagePayload {
content: string;
username?: string;
avatar_url?: string;
tts?: boolean;
embeds?: DiscordEmbed[];
allowed_mentions?: unknown;
components?: unknown;
files?: unknown;
payload_json?: string;
attachments?: unknown;
flags?: number;
}

interface DiscordEmbed {
title?: string;
type?: string;
description?: string;
url?: string;
timestamp?: string;
color?: number;
footer?: DiscordEmbedFooter;
image?: DiscordEmbedImage;
thumbnail?: DiscordEmbedThumbnail;
video?: DiscordEmbedVideo;
provider?: DiscordEmbedProvider;
author?: DiscordEmbedAuthor;
fields?: DiscordEmbedField[];
}

interface DiscordEmbedFooter {
text: string;
icon_url?: string;
proxy_icon_url?: string;
}

interface DiscordEmbedImage {
url?: string;
proxy_url?: string;
height?: number;
width?: number;
}

interface DiscordEmbedThumbnail {
url?: string;
proxy_url?: string;
height?: number;
width?: number;
}

interface DiscordEmbedVideo {
url?: string;
proxy_url?: string;
height?: number;
width?: number;
}

interface DiscordEmbedProvider {
name?: string;
url?: string;
}

interface DiscordEmbedAuthor {
name?: string;
url?: string;
icon_url?: string;
proxy_icon_url?: string;
}

interface DiscordEmbedField {
name: string;
value: string;
inline?: boolean;
}

interface PushoverSendMessagePayload {
token: string;
user: string;
message: string;
attachment?: string;
attachment_base64?: string;
attachment_type?: string;
device?: string;
html?: 1;
priority?: -2 | -1 | 0 | 1 | 2;
sound?: string;
timestamp?: number;
title?: string;
ttl?: number;
url?: string;
url_title?: string;
}

export class ClientBroker {
public static clients: Client[] = [];
public static wss: WebSocket.Server<WebSocket.WebSocket> | undefined =
undefined;

// bitmask of notification categories and providers
public static notificationSettings: Record<NotificationCategory, number> =
{} as Record<NotificationCategory, number>;
public static notificationSettings: Record<NotificationCategory, number> = {
offlineStatusChange: 0,
streamOnline: 0,
streamOffline: 0,
streamStatusChange: 0,
streamStatusChangeFavourite: 0,
vodMuted: 0,
vodDeleted: 0,
debug: 0,
system: 0,
};

public static attach(server: WebSocket.Server<WebSocket.WebSocket>): void {
log(
Expand Down Expand Up @@ -343,13 +260,13 @@ export class ClientBroker {
}

if (
Config.getInstance().cfg("notify.ntfy.enabled") &&
Config.getInstance().cfg("notifications.ntfy.enabled") &&
ClientBroker.getNotificationSettingForProvider(
category,
NotificationProvider.NTFY
)
) {
TelegramNotify(title, body, icon, category, url, tts);
NtfyNotify(title, body, icon, category, url, tts);
}

if (
Expand All @@ -359,40 +276,7 @@ export class ClientBroker {
NotificationProvider.DISCORD
)
) {
axios
.post(Config.getInstance().cfg("discord_webhook"), {
content: `**${title}**\n${body}${url ? `\n\n${url}` : ""}`,
avatar_url:
icon && icon.startsWith("https") ? icon : undefined, // only allow https
tts: tts,
} as DiscordSendMessagePayload)
.then((res) => {
log(
LOGLEVEL.DEBUG,
"clientBroker.notify",
"Discord response",
res.data
);
})
.catch((err: AxiosError) => {
if (axios.isAxiosError(err)) {
log(
LOGLEVEL.ERROR,
"clientBroker.notify",
`Discord axios error: ${
err.message
} (${JSON.stringify(err.response?.data)})`,
{ err: err, response: err.response?.data }
);
} else {
log(
LOGLEVEL.ERROR,
"clientBroker.notify",
`Discord error: ${(err as Error).message}`,
err
);
}
});
DiscordNotify(title, body, icon, category, url, tts);
}

if (
Expand All @@ -402,91 +286,7 @@ export class ClientBroker {
NotificationProvider.PUSHOVER
)
) {
// escape with backslash
// const escaped_title = title.replace(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/g, "\\$&");
// const escaped_body = body.replace(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/g, "\\$&");

axios
.post("https://api.pushover.net/1/messages.json", {
token: Config.getInstance().cfg(
"notifications.pushover.token"
),
user: Config.getInstance().cfg(
"notifications.pushover.user"
),
title: title,
message: body,
url: url,
// html: 1,
} as PushoverSendMessagePayload)
.then((res) => {
log(
LOGLEVEL.DEBUG,
"clientBroker.notify",
"Pushover response",
res.data
);
})
.catch((err: Error) => {
if (axios.isAxiosError(err)) {
// const data = err.response?.data;
// TwitchlogAdvanced(LOGLEVEL.ERROR, "notify", `Telegram axios error: ${err.message} (${data})`, { err: err, response: data });
// console.error(chalk.bgRed.whiteBright(`Telegram axios error: ${err.message} (${data})`), JSON.stringify(err, null, 2));

if (err.response) {
log(
LOGLEVEL.ERROR,
"clientBroker.notify",
`Pushover axios error response: ${err.message} (${err.response.data})`,
{ err: err, response: err.response.data }
);
console.error(
chalk.bgRed.whiteBright(
`Pushover axios error response : ${err.message} (${err.response.data})`
),
JSON.stringify(err, null, 2)
);
} else if (err.request) {
log(
LOGLEVEL.ERROR,
"clientBroker.notify",
`Pushover axios error request: ${err.message} (${err.request})`,
{ err: err, request: err.request }
);
console.error(
chalk.bgRed.whiteBright(
`Pushover axios error request: ${err.message} (${err.request})`
),
JSON.stringify(err, null, 2)
);
} else {
log(
LOGLEVEL.ERROR,
"clientBroker.notify",
`Pushover axios error: ${err.message}`,
err
);
console.error(
chalk.bgRed.whiteBright(
`Pushover axios error: ${err.message}`
),
JSON.stringify(err, null, 2)
);
}
} else {
log(
LOGLEVEL.ERROR,
"clientBroker.notify",
`Pushover error: ${err.message}`,
err
);
console.error(
chalk.bgRed.whiteBright(
`Pushover error: ${err.message}`
)
);
}
});
PushoverNotify(title, body, icon, category, url, tts);
}
}

Expand Down Expand Up @@ -529,20 +329,20 @@ export class ClientBroker {
const settings = JSON.parse(data);

for (const category of NotificationCategories) {
if (settings[category.id as NotificationCategory]) {
this.notificationSettings[category.id as NotificationCategory] =
settings[category.id as NotificationCategory];
if (!category.id || !category.name) continue;
if (settings[category.id]) {
this.notificationSettings[category.id] = settings[category.id];
} else {
this.notificationSettings[
category.id as NotificationCategory
] = 0;
this.notificationSettings[category.id] = 0;
}
}
}

public static saveNotificationSettings() {
const data = JSON.stringify(this.notificationSettings);
fs.writeFileSync(BaseConfigPath.notifications, data);
fs.writeFileSync(
BaseConfigPath.notifications,
JSON.stringify(this.notificationSettings)
);
}

private static onConnect(
Expand Down
Loading

0 comments on commit abffc39

Please sign in to comment.