diff --git a/backend/app.js b/backend/app.js index e183a0c..114f7ae 100644 --- a/backend/app.js +++ b/backend/app.js @@ -685,7 +685,7 @@ app.use(function(req, res, next) { next(); } else if (req.query.apiKey && config_api.getConfigItem('ytdl_use_api_key') && req.query.apiKey === config_api.getConfigItem('ytdl_api_key')) { next(); - } else if (req.path.includes('/api/stream/') || req.path.includes('/api/thumbnail/') || req.path.includes('/api/rss')) { + } else if (req.path.includes('/api/stream/') || req.path.includes('/api/thumbnail/') || req.path.includes('/api/rss') || req.path.includes('/api/telegramRequest')) { next(); } else { logger.verbose(`Rejecting request - invalid API use for endpoint: ${req.path}. API key received: ${req.query.apiKey}`); @@ -1784,6 +1784,10 @@ app.post('/api/cancelDownload', optionalJwt, async (req, res) => { app.post('/api/getTasks', optionalJwt, async (req, res) => { const tasks = await db_api.getRecords('tasks'); for (let task of tasks) { + if (!tasks_api.TASKS[task['key']]) { + logger.verbose(`Task ${task['key']} does not exist!`); + continue; + } if (task['schedule']) task['next_invocation'] = tasks_api.TASKS[task['key']]['job'].nextInvocation().getTime(); } res.send({tasks: tasks}); @@ -2092,6 +2096,24 @@ app.post('/api/deleteAllNotifications', optionalJwt, async (req, res) => { res.send({success: success}); }); +app.post('/api/telegramRequest', async (req, res) => { + if (!req.body.message && !req.body.message.text) { + logger.error('Invalid Telegram request received!'); + res.sendStatus(400); + return; + } + const text = req.body.message.text; + const regex_exp = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)?/gi; + const url_regex = new RegExp(regex_exp); + if (text.match(url_regex)) { + downloader_api.createDownload(text, 'video', {}, req.query.user_uid ? req.query.user_uid : null); + res.sendStatus(200); + } else { + logger.error('Invalid Telegram request received! Make sure you only send a valid URL.'); + res.sendStatus(400); + } +}); + // rss feed app.get('/api/rss', async function (req, res) { diff --git a/backend/notifications.js b/backend/notifications.js index 0cb51d1..a2f4810 100644 --- a/backend/notifications.js +++ b/backend/notifications.js @@ -8,11 +8,14 @@ const { uuid } = require('uuidv4'); const fetch = require('node-fetch'); const { gotify } = require("gotify"); -const TelegramBot = require('node-telegram-bot-api'); +const TelegramBotAPI = require('node-telegram-bot-api'); +let telegram_bot = null; const REST = require('@discordjs/rest').REST; const API = require('@discordjs/core').API; const EmbedBuilder = require('@discordjs/builders').EmbedBuilder; +const debugMode = process.env.YTDL_MODE === 'debug'; + const NOTIFICATION_TYPE_TO_TITLE = { task_finished: 'Task finished', download_complete: 'Download complete', @@ -113,6 +116,8 @@ function notificationEnabled(type) { return config_api.getConfigItem('ytdl_enable_notifications') && (config_api.getConfigItem('ytdl_enable_all_notifications') || config_api.getConfigItem('ytdl_allowed_notification_types').includes(type)); } +// ntfy + function sendNtfyNotification({body, title, type, url, thumbnail}) { logger.verbose('Sending notification to ntfy'); fetch(config_api.getConfigItem('ytdl_ntfy_topic_url'), { @@ -127,6 +132,8 @@ function sendNtfyNotification({body, title, type, url, thumbnail}) { }); } +// Gotify + async function sendGotifyNotification({body, title, type, url, thumbnail}) { logger.verbose('Sending notification to gotify'); await gotify({ @@ -145,15 +152,49 @@ async function sendGotifyNotification({body, title, type, url, thumbnail}) { }); } -async function sendTelegramNotification({body, title, type, url, thumbnail}) { - logger.verbose('Sending notification to Telegram'); +// Telegram + +setupTelegramBot(); +config_api.config_updated.subscribe(change => { + const use_telegram_api = config_api.getConfigItem('ytdl_use_telegram_API'); const bot_token = config_api.getConfigItem('ytdl_telegram_bot_token'); + if (!use_telegram_api || !bot_token) return; + if (!change) return; + if (change['key'] === 'ytdl_use_telegram_API' || change['key'] === 'ytdl_telegram_bot_token') { + logger.debug('Telegram bot setting up'); + setupTelegramBot(); + } +}); + +async function setupTelegramBot() { + const use_telegram_api = config_api.getConfigItem('ytdl_use_telegram_API'); + const bot_token = config_api.getConfigItem('ytdl_telegram_bot_token'); + if (!use_telegram_api || !bot_token) return; + + telegram_bot = new TelegramBotAPI(bot_token); + const webhook_url = `${utils.getBaseURL()}/api/telegramRequest`; + telegram_bot.setWebHook(webhook_url); +} + +async function sendTelegramNotification({body, title, type, url, thumbnail}) { + if (!telegram_bot){ + logger.error('Telegram bot not found!'); + return; + } + const chat_id = config_api.getConfigItem('ytdl_telegram_chat_id'); - const bot = new TelegramBot(bot_token); - if (thumbnail) await bot.sendPhoto(chat_id, thumbnail); - bot.sendMessage(chat_id, `${title}\n\n${body}\n${url}`, {parse_mode: 'HTML'}); + if (!chat_id){ + logger.error('Telegram chat ID required!'); + return; + } + + logger.verbose('Sending notification to Telegram'); + if (thumbnail) await telegram_bot.sendPhoto(chat_id, thumbnail); + telegram_bot.sendMessage(chat_id, `${title}\n\n${body}\n${url}`, {parse_mode: 'HTML'}); } +// Discord + async function sendDiscordNotification({body, title, type, url, thumbnail}) { const discord_webhook_url = config_api.getConfigItem('ytdl_discord_webhook_url'); const url_split = discord_webhook_url.split('webhooks/'); @@ -177,6 +218,8 @@ async function sendDiscordNotification({body, title, type, url, thumbnail}) { return result; } +// Slack + function sendSlackNotification({body, title, type, url, thumbnail}) { const slack_webhook_url = config_api.getConfigItem('ytdl_slack_webhook_url'); logger.verbose(`Sending slack notification to ${slack_webhook_url}`); @@ -236,6 +279,8 @@ function sendSlackNotification({body, title, type, url, thumbnail}) { }); } +// Generic + function sendGenericNotification(data) { const webhook_url = config_api.getConfigItem('ytdl_webhook_url'); logger.verbose(`Sending generic notification to ${webhook_url}`);