this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add multiple Discord webhook support for Discord.

+129 -62
+3
.env.example
··· 3 3 CHANNEL_ID=@your_channel_name_or_id 4 4 5 5 # Discord Configuration 6 + # For multiple webhooks, use a comma-separated list: 7 + # DISCORD_WEBHOOK_URLS=https://discord.com/api/webhooks/xxx/yyy,https://discord.com/api/webhooks/aaa/bbb 8 + # For a single webhook (legacy): 6 9 DISCORD_WEBHOOK_URL=your_discord_webhook_url_here 7 10 DISCORD_ENABLED=true 8 11
+78 -59
bot/discordWebhook.js
··· 9 9 10 10 class DiscordWebhook { 11 11 constructor() { 12 - this.webhookUrl = config.discord?.webhookUrl; 12 + // Support multiple webhook URLs (array or single string) 13 + let urls = config.discord?.webhookUrls || config.discord?.webhookUrl; 14 + if (typeof urls === 'string') { 15 + urls = [urls]; 16 + } 17 + this.webhookUrls = Array.isArray(urls) ? urls.filter(Boolean) : []; 13 18 this.enabled = config.discord?.enabled; 14 - 15 - if (!this.webhookUrl) { 16 - console.warn('Discord webhook URL not configured. Discord integration disabled.'); 19 + 20 + if (!this.webhookUrls.length) { 21 + console.warn('Discord webhook URL(s) not configured. Discord integration disabled.'); 17 22 } else if (this.enabled === false) { 18 - console.log('Discord webhook URL is configured but integration is disabled in settings.'); 23 + console.log('Discord webhook URL(s) configured but integration is disabled in settings.'); 19 24 } else { 20 - console.log('Discord webhook integration initialized.'); 25 + console.log(`Discord webhook integration initialized for ${this.webhookUrls.length} webhook(s).`); 21 26 } 22 27 } 23 28 ··· 26 31 * @returns {boolean} - Whether Discord integration is enabled 27 32 */ 28 33 isEnabled() { 29 - // Only return true if both the webhook URL is set AND explicitly enabled in config 30 - return !!this.webhookUrl && this.enabled !== false; 34 + // Only return true if at least one webhook URL is set AND explicitly enabled in config 35 + return this.webhookUrls.length > 0 && this.enabled !== false; 31 36 } 32 37 33 38 /** ··· 148 153 } 149 154 150 155 // Send the embed 151 - try { 152 - await axios.post(this.webhookUrl, { 153 - embeds: [embed] 154 - }, { 155 - headers: { 156 - 'Content-Type': 'application/json' 156 + for (const url of this.webhookUrls) { 157 + try { 158 + await axios.post(url, { 159 + embeds: [embed] 160 + }, { 161 + headers: { 162 + 'Content-Type': 'application/json' 163 + } 164 + }); 165 + console.log(`Successfully sent embed to Discord webhook: ${url}`); 166 + } catch (error) { 167 + console.error(`Error sending embed to ${url}:`, error.message); 168 + if (error.response) { 169 + console.error('Discord API response:', error.response.data); 157 170 } 158 - }); 159 - console.log('Successfully sent embed to Discord'); 160 - } catch (error) { 161 - console.error('Error sending embed:', error.message); 162 - if (error.response) { 163 - console.error('Discord API response:', error.response.data); 164 171 } 165 - throw error; 166 172 } 167 173 } 168 174 ··· 218 224 } 219 225 220 226 // Send the embeds 221 - try { 222 - await axios.post(this.webhookUrl, { 223 - embeds: embeds 224 - }, { 225 - headers: { 226 - 'Content-Type': 'application/json' 227 + for (const url of this.webhookUrls) { 228 + try { 229 + await axios.post(url, { 230 + embeds: embeds 231 + }, { 232 + headers: { 233 + 'Content-Type': 'application/json' 234 + } 235 + }); 236 + console.log(`Successfully sent ${embeds.length} embeds to Discord webhook: ${url}`); 237 + } catch (error) { 238 + console.error(`Error sending multiple embeds to ${url}:`, error.message); 239 + if (error.response) { 240 + console.error('Discord API response:', error.response.data); 227 241 } 228 - }); 229 - console.log(`Successfully sent ${embeds.length} embeds to Discord`); 230 - } catch (error) { 231 - console.error('Error sending multiple embeds:', error.message); 232 - if (error.response) { 233 - console.error('Discord API response:', error.response.data); 234 242 } 235 - throw error; 236 243 } 237 244 } else { 238 245 // If we only have one image or no array, fall back to single image embed ··· 280 287 embed.description = "This post contains a video. Click the title to watch."; 281 288 282 289 // Send the embed 283 - try { 284 - await axios.post(this.webhookUrl, { 285 - embeds: [embed] 286 - }, { 287 - headers: { 288 - 'Content-Type': 'application/json' 290 + for (const url of this.webhookUrls) { 291 + try { 292 + await axios.post(url, { 293 + embeds: [embed] 294 + }, { 295 + headers: { 296 + 'Content-Type': 'application/json' 297 + } 298 + }); 299 + console.log(`Successfully sent video embed to Discord webhook: ${url}`); 300 + } catch (error) { 301 + console.error(`Error sending video embed to ${url}:`, error.message); 302 + if (error.response) { 303 + console.error('Discord API response:', error.response.data); 289 304 } 290 - }); 291 - console.log('Successfully sent video embed to Discord'); 292 - } catch (error) { 293 - console.error('Error sending video embed:', error.message); 294 - if (error.response) { 295 - console.error('Discord API response:', error.response.data); 296 305 } 297 - throw error; 298 306 } 299 307 } 300 308 ··· 349 357 }); 350 358 351 359 // Send the form 352 - await axios.post(this.webhookUrl, form, { 353 - headers: form.getHeaders() 354 - }); 355 - 356 - console.log(`Successfully sent local file embed with ${filePath}`); 360 + for (const url of this.webhookUrls) { 361 + try { 362 + await axios.post(url, form, { 363 + headers: form.getHeaders() 364 + }); 365 + console.log(`Successfully sent local file embed with ${filePath} to Discord webhook: ${url}`); 366 + } catch (error) { 367 + console.error(`Error sending local file embed to ${url}:`, error.message); 368 + } 369 + } 357 370 } catch (error) { 358 371 console.error(`Error sending local file embed: ${error.message}`); 359 372 // Fall back to text message ··· 367 380 * @returns {Promise<void>} 368 381 */ 369 382 async sendTextMessage(mediaData) { 370 - await axios.post(this.webhookUrl, { 371 - content: `${mediaData.title || 'New post'} from ${mediaData.siteName}: ${mediaData.sourceUrl}` 372 - }, { 373 - headers: { 374 - 'Content-Type': 'application/json' 383 + for (const url of this.webhookUrls) { 384 + try { 385 + await axios.post(url, { 386 + content: `${mediaData.title || 'New post'} from ${mediaData.siteName}: ${mediaData.sourceUrl}` 387 + }, { 388 + headers: { 389 + 'Content-Type': 'application/json' 390 + } 391 + }); 392 + console.log(`Sent text-only message to Discord webhook: ${url}`); 393 + } catch (error) { 394 + console.error(`Error sending text message to ${url}:`, error.message); 375 395 } 376 - }); 377 - console.log('Sent text-only message to Discord webhook'); 396 + } 378 397 } 379 398 380 399 /**
+5 -1
config.js
··· 8 8 9 9 // Discord configuration 10 10 discord: { 11 - webhookUrl: process.env.DISCORD_WEBHOOK_URL, 11 + // Support multiple webhook URLs (comma-separated) 12 + webhookUrls: process.env.DISCORD_WEBHOOK_URLS 13 + ? process.env.DISCORD_WEBHOOK_URLS.split(',').map(url => url.trim()).filter(Boolean) 14 + : undefined, 15 + webhookUrl: process.env.DISCORD_WEBHOOK_URL, // fallback for single webhook 12 16 enabled: process.env.DISCORD_ENABLED === 'true' 13 17 }, 14 18
+2 -2
queue/alert-state.json
··· 1 1 { 2 2 "lowQueueAlertSent": true, 3 3 "emptyQueueAlertSent": false, 4 - "lastLowQueueAlertTime": 1749155645693, 4 + "lastLowQueueAlertTime": 1751412078653, 5 5 "lastEmptyQueueAlertTime": 1749155676860, 6 - "lastSaved": 1749157762521 6 + "lastSaved": 1751412115858 7 7 }
+41
reset.js
··· 1 + const { Client, REST, Routes } = require('discord.js'); 2 + 3 + const TOKEN = 'OTEyMjEyNjU4NTM3NzgzMzU3.G5HWhO.RKahCMywL_GMrr5xpoxBaNlGWfrJLFfkkMn5jc'; 4 + const CLIENT_ID = '912212658537783357'; 5 + 6 + if (!TOKEN || !CLIENT_ID) { 7 + console.error('Please set TOKEN and CLIENT_ID in your environment variables.'); 8 + process.exit(1); 9 + } 10 + 11 + const client = new Client({ intents: [] }); 12 + 13 + async function deleteAllCommands() { 14 + const rest = new REST({ version: '10' }).setToken(TOKEN); 15 + 16 + try { 17 + console.log('Fetching registered commands...'); 18 + const commands = await rest.get(Routes.applicationCommands(CLIENT_ID)); 19 + 20 + if (commands.length === 0) { 21 + console.log('No commands to delete.'); 22 + } else { 23 + console.log(`Deleting ${commands.length} commands...`); 24 + for (const command of commands) { 25 + await rest.delete(`${Routes.applicationCommands(CLIENT_ID)}/${command.id}`); 26 + console.log(`Deleted command: ${command.name}`); 27 + } 28 + } 29 + } catch (error) { 30 + console.error('Error deleting commands:', error); 31 + } 32 + } 33 + 34 + client.once('ready', async () => { 35 + console.log(`Logged in as ${client.user.tag}`); 36 + await deleteAllCommands(); 37 + console.log('Logging out...'); 38 + client.destroy(); 39 + }); 40 + 41 + client.login(TOKEN).catch(console.error);