florale-emotion/social-media-bot/bot.js

384 lines
12 KiB
JavaScript

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;