const axios = require('axios'); const cron = require('node-cron'); const fs = require('fs').promises; const path = require('path'); require('dotenv').config(); class SocialMediaBot { constructor() { this.platforms = { instagram: { enabled: process.env.INSTAGRAM_ENABLED === 'true', username: process.env.INSTAGRAM_USERNAME, password: process.env.INSTAGRAM_PASSWORD }, facebook: { enabled: process.env.FACEBOOK_ENABLED === 'true', accessToken: process.env.FACEBOOK_ACCESS_TOKEN, pageId: process.env.FACEBOOK_PAGE_ID }, tiktok: { enabled: process.env.TIKTOK_ENABLED === 'true', accessToken: process.env.TIKTOK_ACCESS_TOKEN }, mastodon: { enabled: process.env.MASTODON_ENABLED === 'true', accessToken: process.env.MASTODON_ACCESS_TOKEN, apiUrl: process.env.MASTODON_API_URL || 'https://mastodon.social' }, youtube: { enabled: process.env.YOUTUBE_ENABLED === 'true', apiKey: process.env.YOUTUBE_API_KEY, channelId: process.env.YOUTUBE_CHANNEL_ID } }; this.contentTemplates = this.loadContentTemplates(); } loadContentTemplates() { return { wedding: [ { text: "💐 Ein traumhafter Tag verdient traumhafte Blumen! Unser neuestes Hochzeitsarrangement vereint Eleganz und Romantik. #Hochzeit #Brautstrauß #FloraleEmotion #Blumen #Hochzeitsfloristik", hashtags: ["#Hochzeit", "#Brautstrauß", "#FloraleEmotion", "#Blumen", "#Hochzeitsfloristik", "#Romantik", "#Liebe"] }, { text: "🌹 Jede Hochzeit erzählt ihre eigene Geschichte - wir sorgen für die perfekte florale Begleitung. Von der Zeremonie bis zur Feier. #Hochzeitsplanung #Blumendeko #Traumhochzeit", hashtags: ["#Hochzeitsplanung", "#Blumendeko", "#Traumhochzeit", "#FloraleEmotion", "#Hochzeitsfloristik"] } ], funeral: [ { text: "🕊️ In stillen Momenten des Abschieds begleiten wir Sie mit würdevollen Arrangements. Unsere Trauerfloristik drückt aus, was Worte nicht können. #Trauerfloristik #Abschied #Erinnerung", hashtags: ["#Trauerfloristik", "#Abschied", "#Erinnerung", "#FloraleEmotion", "#Würde", "#Respekt"] } ], corporate: [ { text: "🏢 Professionelle Events verdienen professionelle Floristik. Wir gestalten Ihre Firmenfeier mit stilvollen Arrangements in Ihren Unternehmensfarben. #CorporateEvents #Firmenfeiern #Eventfloristik", hashtags: ["#CorporateEvents", "#Firmenfeiern", "#Eventfloristik", "#FloraleEmotion", "#Business"] } ], seasonal: [ { text: "🌸 Der Frühling erwacht und mit ihm die schönsten Blumen der Saison! Lassen Sie sich von der Natur inspirieren. #Frühling #Saisonblumen #Inspiration", hashtags: ["#Frühling", "#Saisonblumen", "#Inspiration", "#FloraleEmotion", "#Natur"] }, { text: "🍂 Herbstliche Arrangements mit warmen Farben und natürlichen Materialien - perfekt für gemütliche Events. #Herbst #Herbstdeko #Gemütlichkeit", hashtags: ["#Herbst", "#Herbstdeko", "#Gemütlichkeit", "#FloraleEmotion", "#Saison"] } ], tips: [ { text: "💡 Tipp des Tages: Schnittblumen halten länger, wenn Sie die Stiele schräg anschneiden und täglich frisches Wasser geben. #Blumentipps #Pflege #Ratgeber", hashtags: ["#Blumentipps", "#Pflege", "#Ratgeber", "#FloraleEmotion", "#Wissen"] }, { text: "🌺 Wussten Sie? Die Farbe der Blumen kann die Stimmung beeinflussen. Warme Töne wirken energetisierend, kühle Farben beruhigend. #Farbpsychologie #Blumen #Wissen", hashtags: ["#Farbpsychologie", "#Blumen", "#Wissen", "#FloraleEmotion", "#Psychologie"] } ] }; } async postToInstagram(content, imagePath = null) { if (!this.platforms.instagram.enabled) { console.log('Instagram posting disabled'); return; } try { // Note: Instagram API requires business account and approval // This is a placeholder for the actual Instagram API implementation console.log('Posting to Instagram:', content.text); // For actual implementation, you would use Instagram Basic Display API // or Instagram Graph API for business accounts return { success: true, platform: 'instagram' }; } catch (error) { console.error('Error posting to Instagram:', error); return { success: false, platform: 'instagram', error: error.message }; } } async postToFacebook(content, imagePath = null) { if (!this.platforms.facebook.enabled) { console.log('Facebook posting disabled'); return; } try { const url = `https://graph.facebook.com/v18.0/${this.platforms.facebook.pageId}/feed`; const postData = { message: content.text, access_token: this.platforms.facebook.accessToken }; if (imagePath) { // For image posts, you would need to upload the image first // This is a simplified version } const response = await axios.post(url, postData); console.log('Posted to Facebook:', response.data); return { success: true, platform: 'facebook', postId: response.data.id }; } catch (error) { console.error('Error posting to Facebook:', error); return { success: false, platform: 'facebook', error: error.message }; } } async postToMastodon(content, imagePath = null) { if (!this.platforms.mastodon.enabled) { console.log('Mastodon posting disabled'); return; } try { const url = `${this.platforms.mastodon.apiUrl}/api/v1/statuses`; const postData = { status: content.text + ' ' + content.hashtags.join(' ') }; const response = await axios.post(url, postData, { headers: { 'Authorization': `Bearer ${this.platforms.mastodon.accessToken}`, 'Content-Type': 'application/json' } }); console.log('Posted to Mastodon:', response.data); return { success: true, platform: 'mastodon', postId: response.data.id }; } catch (error) { console.error('Error posting to Mastodon:', error); return { success: false, platform: 'mastodon', error: error.message }; } } async postToTikTok(content, videoPath) { if (!this.platforms.tiktok.enabled) { console.log('TikTok posting disabled'); return; } try { // TikTok API implementation would go here // Note: TikTok for Business API has specific requirements console.log('TikTok posting not yet implemented'); return { success: false, platform: 'tiktok', error: 'Not implemented' }; } catch (error) { console.error('Error posting to TikTok:', error); return { success: false, platform: 'tiktok', error: error.message }; } } getRandomContent(category) { const templates = this.contentTemplates[category]; if (!templates || templates.length === 0) { return null; } return templates[Math.floor(Math.random() * templates.length)]; } async postToAllPlatforms(content, imagePath = null) { const results = []; if (this.platforms.instagram.enabled) { results.push(await this.postToInstagram(content, imagePath)); } if (this.platforms.facebook.enabled) { results.push(await this.postToFacebook(content, imagePath)); } if (this.platforms.mastodon.enabled) { results.push(await this.postToMastodon(content, imagePath)); } return results; } async scheduledPost() { console.log('Running scheduled social media post...'); // Determine content type based on day of week const today = new Date(); const dayOfWeek = today.getDay(); let contentCategory; switch (dayOfWeek) { case 1: // Monday - Tips contentCategory = 'tips'; break; case 3: // Wednesday - Wedding content contentCategory = 'wedding'; break; case 5: // Friday - Seasonal content contentCategory = 'seasonal'; break; default: contentCategory = 'wedding'; // Default to wedding content } const content = this.getRandomContent(contentCategory); if (!content) { console.log('No content available for category:', contentCategory); return; } const results = await this.postToAllPlatforms(content); // Log results results.forEach(result => { if (result.success) { console.log(`✅ Successfully posted to ${result.platform}`); } else { console.log(`❌ Failed to post to ${result.platform}: ${result.error}`); } }); // Save posting log await this.savePostingLog({ timestamp: new Date().toISOString(), category: contentCategory, content: content, results: results }); } async savePostingLog(logEntry) { try { const logFile = path.join(__dirname, 'logs', 'posting-log.json'); // Ensure logs directory exists await fs.mkdir(path.dirname(logFile), { recursive: true }); let logs = []; try { const existingLogs = await fs.readFile(logFile, 'utf8'); logs = JSON.parse(existingLogs); } catch (error) { // File doesn't exist yet, start with empty array } logs.push(logEntry); // Keep only last 100 entries if (logs.length > 100) { logs = logs.slice(-100); } await fs.writeFile(logFile, JSON.stringify(logs, null, 2)); } catch (error) { console.error('Error saving posting log:', error); } } startScheduler() { // Post Monday, Wednesday, Friday at 10:00 AM cron.schedule('0 10 * * 1,3,5', () => { this.scheduledPost(); }, { timezone: "Europe/Berlin" }); console.log('Social media scheduler started'); console.log('Posts will be published Monday, Wednesday, Friday at 10:00 AM (Berlin time)'); } async manualPost(category, platforms = ['all']) { const content = this.getRandomContent(category); if (!content) { throw new Error(`No content available for category: ${category}`); } let results = []; if (platforms.includes('all')) { results = await this.postToAllPlatforms(content); } else { for (const platform of platforms) { switch (platform) { case 'instagram': results.push(await this.postToInstagram(content)); break; case 'facebook': results.push(await this.postToFacebook(content)); break; case 'mastodon': results.push(await this.postToMastodon(content)); break; case 'tiktok': results.push(await this.postToTikTok(content)); break; } } } await this.savePostingLog({ timestamp: new Date().toISOString(), category: category, content: content, results: results, manual: true }); return results; } } // CLI interface if (require.main === module) { const bot = new SocialMediaBot(); const args = process.argv.slice(2); const command = args[0]; switch (command) { case 'start': bot.startScheduler(); break; case 'post': const category = args[1] || 'wedding'; const platforms = args.slice(2); bot.manualPost(category, platforms.length > 0 ? platforms : ['all']) .then(results => { console.log('Manual post results:', results); process.exit(0); }) .catch(error => { console.error('Error with manual post:', error); process.exit(1); }); break; case 'test': console.log('Testing bot configuration...'); console.log('Platforms configured:'); Object.entries(bot.platforms).forEach(([platform, config]) => { console.log(`${platform}: ${config.enabled ? '✅ Enabled' : '❌ Disabled'}`); }); break; default: console.log('Usage:'); console.log(' node bot.js start - Start the scheduler'); console.log(' node bot.js post [category] [platforms...] - Manual post'); console.log(' node bot.js test - Test configuration'); console.log(''); console.log('Categories: wedding, funeral, corporate, seasonal, tips'); console.log('Platforms: instagram, facebook, mastodon, tiktok'); } } module.exports = SocialMediaBot;