From 35b6d9d100f556268268d863e403135697a8adef Mon Sep 17 00:00:00 2001 From: Guillaume Guerin Date: Sat, 3 May 2025 16:34:28 +0200 Subject: [PATCH 1/3] feat: Add telegram notification --- src/lib/Video.ts | 3 +++ src/lib/defaults.ts | 7 +++++++ src/lib/notifications/notify.ts | 19 +++++++++++++++++++ src/lib/notifications/telegram.ts | 20 ++++++++++++++++++++ src/lib/types.ts | 9 +++++++++ 5 files changed, 58 insertions(+) create mode 100644 src/lib/notifications/notify.ts create mode 100644 src/lib/notifications/telegram.ts diff --git a/src/lib/Video.ts b/src/lib/Video.ts index af755fed..e2afa84a 100644 --- a/src/lib/Video.ts +++ b/src/lib/Video.ts @@ -23,6 +23,7 @@ import { updatePlex } from "./helpers/updatePlex.js"; import { ProgressHeadless } from "./logging/ProgressConsole.js"; import { ProgressBars } from "./logging/ProgressBars.js"; +import { notifyDownloaded, notifyError } from "./notifications/notify.js"; const exec = promisify(execCallback); const sleep = promisify(setTimeout); @@ -178,6 +179,7 @@ export class Video extends Attachment { } logger.done(chalk`{cyan Download & Muxing complete!}`); promDownloadedTotal.inc(); + notifyDownloaded(this); break; } catch (error) { const message = this.parseErrorMessage(error); @@ -188,6 +190,7 @@ export class Video extends Attachment { await sleep(1000 * retries); } else { logger.error(`${message} - Failed`); + notifyError(this); } } } diff --git a/src/lib/defaults.ts b/src/lib/defaults.ts index bf379562..1a01fb10 100644 --- a/src/lib/defaults.ts +++ b/src/lib/defaults.ts @@ -65,4 +65,11 @@ export const defaultSettings: Settings = { prometheusExporterPort: null, contributeMetrics: true, }, + notifications: { + telegram: { + enabled: false, + token: "", + chatId: "", + }, + }, }; diff --git a/src/lib/notifications/notify.ts b/src/lib/notifications/notify.ts new file mode 100644 index 00000000..4a52e0b8 --- /dev/null +++ b/src/lib/notifications/notify.ts @@ -0,0 +1,19 @@ +import { settings } from "../helpers/index.js"; +import { Video } from "../Video.js"; +import telegramNotify from "./telegram.js"; + +export const notifyDownloaded = (video: Video) => { + const { videoTitle, channelTitle } = video; + const message = `Downloaded ${videoTitle} from ${channelTitle}`; + if (settings.notifications.telegram && settings.notifications.telegram.enabled) { + telegramNotify(message); + } +}; + +export const notifyError = (video: Video) => { + const { videoTitle, channelTitle } = video; + const message = `Error downloading ${videoTitle} from ${channelTitle}`; + if (settings.notifications.telegram && settings.notifications.telegram.enabled) { + telegramNotify(message); + } +}; diff --git a/src/lib/notifications/telegram.ts b/src/lib/notifications/telegram.ts new file mode 100644 index 00000000..5c07a2c1 --- /dev/null +++ b/src/lib/notifications/telegram.ts @@ -0,0 +1,20 @@ +import { settings } from "../helpers/index.js"; + +export default async function telegramNotify(message: string) { + const telegram = settings.notifications.telegram; + if (!telegram || !telegram.enabled) return; + try { + fetch(`https://api.telegram.org/bot${telegram.token}/sendMessage`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + chat_id: telegram.chatId, + text: message, + }), + }); + } catch { + console.error("Failed to send telegram notification"); + } +} diff --git a/src/lib/types.ts b/src/lib/types.ts index 488c4b8a..16e966a5 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -46,6 +46,14 @@ export interface Extras extends Record { export type Resolution = ValueOfA; +export type Notification = { + telegram?: { + token: string; + chatId: string; + enabled: boolean; + }; +}; + export type Settings = { __SettingsWiki: string; runQuickstartPrompts: boolean; @@ -68,4 +76,5 @@ export type Settings = { prometheusExporterPort: number | null; contributeMetrics: boolean; }; + notifications: Notification; }; From d77de95cab2656503641156200addd2e291dc535 Mon Sep 17 00:00:00 2001 From: Guillaume Guerin Date: Sat, 3 May 2025 22:47:16 +0200 Subject: [PATCH 2/3] feat: refactor and add discord --- src/lib/defaults.ts | 4 ++++ src/lib/notifications/discord.ts | 20 ++++++++++++++++++++ src/lib/notifications/notify.ts | 24 ++++++++++++++---------- src/lib/notifications/telegram.ts | 5 +++-- src/lib/types.ts | 4 ++++ 5 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 src/lib/notifications/discord.ts diff --git a/src/lib/defaults.ts b/src/lib/defaults.ts index 1a01fb10..39d95f2a 100644 --- a/src/lib/defaults.ts +++ b/src/lib/defaults.ts @@ -71,5 +71,9 @@ export const defaultSettings: Settings = { token: "", chatId: "", }, + discord: { + enabled: false, + webhookUrl: "", + }, }, }; diff --git a/src/lib/notifications/discord.ts b/src/lib/notifications/discord.ts new file mode 100644 index 00000000..a78f3a73 --- /dev/null +++ b/src/lib/notifications/discord.ts @@ -0,0 +1,20 @@ +import { settings } from "../helpers/index.js"; + +export default async function discordSendMessage(message: string) { + const discord = settings.notifications.discord; + if (!discord || !discord.enabled || !discord.webhookUrl || !message) return; + + try { + fetch(discord.webhookUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + content: message, + }), + }); + } catch { + console.error("Failed to send discord notification"); + } +} diff --git a/src/lib/notifications/notify.ts b/src/lib/notifications/notify.ts index 4a52e0b8..054dc9d9 100644 --- a/src/lib/notifications/notify.ts +++ b/src/lib/notifications/notify.ts @@ -1,19 +1,23 @@ import { settings } from "../helpers/index.js"; import { Video } from "../Video.js"; -import telegramNotify from "./telegram.js"; +import discordSendMessage from "./discord.js"; +import telegramSendMessage from "./telegram.js"; -export const notifyDownloaded = (video: Video) => { - const { videoTitle, channelTitle } = video; - const message = `Downloaded ${videoTitle} from ${channelTitle}`; +const notifyAll = (message: string) => { if (settings.notifications.telegram && settings.notifications.telegram.enabled) { - telegramNotify(message); + telegramSendMessage(message); + } + if (settings.notifications.discord && settings.notifications.discord.enabled) { + discordSendMessage(message); } }; +export const notifyDownloaded = (video: Video) => { + const message = `Downloaded ${video.videoTitle} from ${video.channelTitle}`; + notifyAll(message); +}; + export const notifyError = (video: Video) => { - const { videoTitle, channelTitle } = video; - const message = `Error downloading ${videoTitle} from ${channelTitle}`; - if (settings.notifications.telegram && settings.notifications.telegram.enabled) { - telegramNotify(message); - } + const message = `Error downloading ${video.videoTitle} from ${video.channelTitle}`; + notifyAll(message); }; diff --git a/src/lib/notifications/telegram.ts b/src/lib/notifications/telegram.ts index 5c07a2c1..89438853 100644 --- a/src/lib/notifications/telegram.ts +++ b/src/lib/notifications/telegram.ts @@ -1,8 +1,9 @@ import { settings } from "../helpers/index.js"; -export default async function telegramNotify(message: string) { +export default async function telegramSendMessage(message: string) { const telegram = settings.notifications.telegram; - if (!telegram || !telegram.enabled) return; + if (!telegram || !telegram.enabled || !telegram.token || !telegram.chatId || !message) return; + try { fetch(`https://api.telegram.org/bot${telegram.token}/sendMessage`, { method: "POST", diff --git a/src/lib/types.ts b/src/lib/types.ts index 16e966a5..489bf6a4 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -52,6 +52,10 @@ export type Notification = { chatId: string; enabled: boolean; }; + discord?: { + enabled: boolean; + webhookUrl: string; + }; }; export type Settings = { From eab742892ac3f321561549feec75174df40bc5b3 Mon Sep 17 00:00:00 2001 From: Guillaume Guerin Date: Sun, 4 May 2025 11:25:49 +0200 Subject: [PATCH 3/3] chore: refactor discord notification to use embed for video downloaded --- src/lib/Video.ts | 4 +-- src/lib/notifications/discord.ts | 46 ++++++++++++++++++++++++++++++-- src/lib/notifications/notify.ts | 22 +++++---------- 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/lib/Video.ts b/src/lib/Video.ts index e2afa84a..fd8781a7 100644 --- a/src/lib/Video.ts +++ b/src/lib/Video.ts @@ -64,7 +64,7 @@ const byteToMbits = 131072; export class Video extends Attachment { private readonly description: string; - private readonly artworkUrl?: string; + public readonly artworkUrl?: string; public static State = VideoState; @@ -190,7 +190,7 @@ export class Video extends Attachment { await sleep(1000 * retries); } else { logger.error(`${message} - Failed`); - notifyError(this); + notifyError(message, this); } } } diff --git a/src/lib/notifications/discord.ts b/src/lib/notifications/discord.ts index a78f3a73..12a8f366 100644 --- a/src/lib/notifications/discord.ts +++ b/src/lib/notifications/discord.ts @@ -1,6 +1,48 @@ import { settings } from "../helpers/index.js"; +import { Video } from "../Video.js"; -export default async function discordSendMessage(message: string) { +export const discordSendEmbed = async (title: string, video: Video) => { + const discord = settings.notifications.discord; + if (!discord || !discord.enabled || !discord.webhookUrl || !video) return; + + try { + fetch(discord.webhookUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + embeds: [ + { + title: title, + author: { + name: video.channelTitle, + }, + image: { + url: video.artworkUrl, + }, + fields: [ + { + name: "Title", + value: video.videoTitle, + inline: true, + }, + { + name: "Channel", + value: video.channelTitle, + inline: true, + }, + ], + }, + ], + }), + }); + } catch { + console.error("Failed to send discord notification"); + } +}; + +export const discordSendMessage = async (message: string) => { const discord = settings.notifications.discord; if (!discord || !discord.enabled || !discord.webhookUrl || !message) return; @@ -17,4 +59,4 @@ export default async function discordSendMessage(message: string) { } catch { console.error("Failed to send discord notification"); } -} +}; diff --git a/src/lib/notifications/notify.ts b/src/lib/notifications/notify.ts index 054dc9d9..c7429214 100644 --- a/src/lib/notifications/notify.ts +++ b/src/lib/notifications/notify.ts @@ -1,23 +1,15 @@ -import { settings } from "../helpers/index.js"; import { Video } from "../Video.js"; -import discordSendMessage from "./discord.js"; +import { discordSendEmbed, discordSendMessage } from "./discord.js"; import telegramSendMessage from "./telegram.js"; -const notifyAll = (message: string) => { - if (settings.notifications.telegram && settings.notifications.telegram.enabled) { - telegramSendMessage(message); - } - if (settings.notifications.discord && settings.notifications.discord.enabled) { - discordSendMessage(message); - } -}; - export const notifyDownloaded = (video: Video) => { const message = `Downloaded ${video.videoTitle} from ${video.channelTitle}`; - notifyAll(message); + telegramSendMessage(message); + discordSendEmbed("New video downloaded", video); }; -export const notifyError = (video: Video) => { - const message = `Error downloading ${video.videoTitle} from ${video.channelTitle}`; - notifyAll(message); +export const notifyError = (error: string, video: Video) => { + const message = `Error downloading ${video.videoTitle} from ${video.channelTitle} : ${error}`; + telegramSendMessage(message); + discordSendMessage(message); };