132 lines
4.3 KiB
JavaScript
132 lines
4.3 KiB
JavaScript
// ============================================================
|
||
// index.js — noctura newsbot
|
||
// Matrix Bot der täglich News-Feeds postet
|
||
// ============================================================
|
||
|
||
const { MatrixClient, SimpleFsStorageProvider, AutojoinRoomsMixin } = require('matrix-bot-sdk');
|
||
const RSSParser = require('rss-parser');
|
||
const cron = require('node-cron');
|
||
const { FEEDS, MAX_ITEMS_PER_FEED, HOURS_LOOKBACK } = require('./feeds');
|
||
const { formatDailyDigest, formatNoNews, formatError } = require('./formatter');
|
||
|
||
// ---- Konfiguration aus Umgebungsvariablen ----
|
||
const HOMESERVER = process.env.MATRIX_HOMESERVER || 'http://localhost:8008';
|
||
const ACCESS_TOKEN = process.env.MATRIX_ACCESS_TOKEN;
|
||
const ROOM_ID = process.env.MATRIX_ROOM_ID;
|
||
const CRON_SCHEDULE= process.env.CRON_SCHEDULE || '0 8 * * *'; // täglich 08:00 Uhr
|
||
|
||
if (!ACCESS_TOKEN) { console.error('❌ MATRIX_ACCESS_TOKEN fehlt!'); process.exit(1); }
|
||
if (!ROOM_ID) { console.error('❌ MATRIX_ROOM_ID fehlt!'); process.exit(1); }
|
||
|
||
// ---- Matrix Client Setup ----
|
||
const storage = new SimpleFsStorageProvider('/data/bot-storage.json');
|
||
const client = new MatrixClient(HOMESERVER, ACCESS_TOKEN, storage);
|
||
AutojoinRoomsMixin.setupOnClient(client);
|
||
|
||
const parser = new RSSParser({
|
||
timeout: 10000,
|
||
headers: { 'User-Agent': 'noctura-newsbot/1.0' }
|
||
});
|
||
|
||
// ---- RSS Feed abrufen ----
|
||
async function fetchFeed(feed) {
|
||
try {
|
||
const parsed = await parser.parseURL(feed.url);
|
||
const cutoff = Date.now() - HOURS_LOOKBACK * 60 * 60 * 1000;
|
||
|
||
return parsed.items
|
||
.filter(item => {
|
||
const pubDate = item.pubDate ? new Date(item.pubDate).getTime() : Date.now();
|
||
return pubDate >= cutoff;
|
||
})
|
||
.slice(0, MAX_ITEMS_PER_FEED)
|
||
.map(item => ({
|
||
title: item.title?.trim() || 'Kein Titel',
|
||
link: item.link || item.guid || '',
|
||
summary: item.contentSnippet
|
||
? item.contentSnippet.slice(0, 120).trim() + '…'
|
||
: '',
|
||
feedName: feed.name,
|
||
category: feed.category,
|
||
pubDate: item.pubDate
|
||
}));
|
||
} catch (err) {
|
||
console.error(`⚠️ Feed-Fehler [${feed.name}]: ${err.message}`);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
// ---- Alle Feeds abrufen & gruppieren ----
|
||
async function fetchAllNews() {
|
||
console.log('🔍 Feeds werden abgerufen...');
|
||
const results = await Promise.allSettled(FEEDS.map(fetchFeed));
|
||
|
||
const grouped = {};
|
||
results.forEach((result, i) => {
|
||
if (result.status !== 'fulfilled') return;
|
||
const items = result.value;
|
||
items.forEach(item => {
|
||
if (!grouped[item.category]) grouped[item.category] = [];
|
||
grouped[item.category].push(item);
|
||
});
|
||
});
|
||
|
||
return grouped;
|
||
}
|
||
|
||
// ---- Nachricht in Matrix Room senden ----
|
||
async function sendToMatrix(plain, html) {
|
||
await client.sendMessage(ROOM_ID, {
|
||
msgtype: 'm.text',
|
||
body: plain,
|
||
format: 'org.matrix.custom.html',
|
||
formatted_body: html
|
||
});
|
||
console.log('✅ Digest erfolgreich gesendet!');
|
||
}
|
||
|
||
// ---- Haupt-Job ----
|
||
async function runDigest() {
|
||
console.log(`\n⏰ [${new Date().toISOString()}] Täglicher Digest wird erstellt...`);
|
||
try {
|
||
const grouped = await fetchAllNews();
|
||
const totalItems = Object.values(grouped).flat().length;
|
||
console.log(`📊 ${totalItems} Artikel gefunden`);
|
||
|
||
if (totalItems === 0) {
|
||
const { plain, html } = formatNoNews();
|
||
await sendToMatrix(plain, html);
|
||
} else {
|
||
const { plain, html } = formatDailyDigest(grouped);
|
||
await sendToMatrix(plain, html);
|
||
}
|
||
} catch (err) {
|
||
console.error('❌ Fehler beim Digest:', err);
|
||
}
|
||
}
|
||
|
||
// ---- Bot starten ----
|
||
async function main() {
|
||
console.log('🚀 noctura newsbot startet...');
|
||
console.log(` Homeserver: ${HOMESERVER}`);
|
||
console.log(` Room: ${ROOM_ID}`);
|
||
console.log(` Cron: ${CRON_SCHEDULE}`);
|
||
|
||
await client.start();
|
||
console.log('✅ Matrix Client verbunden!');
|
||
|
||
// Cron Job registrieren
|
||
cron.schedule(CRON_SCHEDULE, runDigest, { timezone: 'Europe/Berlin' });
|
||
console.log(`📅 Cron Job aktiv: ${CRON_SCHEDULE} (Europe/Berlin)`);
|
||
|
||
// Beim Start einmal sofort ausführen wenn TEST_RUN gesetzt
|
||
if (process.env.TEST_RUN === 'true') {
|
||
console.log('🧪 TEST_RUN aktiv – einmalig sofort ausführen...');
|
||
await runDigest();
|
||
}
|
||
}
|
||
|
||
main().catch(err => {
|
||
console.error('❌ Bot-Fehler:', err);
|
||
process.exit(1);
|
||
});
|