-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
131 lines (110 loc) · 3.51 KB
/
server.js
File metadata and controls
131 lines (110 loc) · 3.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
const express = require('express');
const { TwitterApi } = require('twitter-api-v2');
const axios = require('axios');
const fs = require('fs');
const path = require('path');
require('dotenv').config();
const app = express();
app.use(express.json({ limit: '50mb' }));
// Create uploads directory if it doesn't exist
const uploadsDir = path.join(__dirname, 'uploads');
if (!fs.existsSync(uploadsDir)) {
fs.mkdirSync(uploadsDir);
}
// Twitter client
const twitterClient = new TwitterApi({
appKey: process.env.TWITTER_API_KEY,
appSecret: process.env.TWITTER_API_SECRET,
accessToken: process.env.TWITTER_ACCESS_TOKEN,
accessSecret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
});
// Helper function to download image from URL
async function downloadImage(url, filepath) {
const response = await axios({
method: 'GET',
url: url,
responseType: 'stream'
});
return new Promise((resolve, reject) => {
const stream = fs.createWriteStream(filepath);
response.data.pipe(stream);
stream.on('finish', resolve);
stream.on('error', reject);
});
}
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'OK', service: 'Twitter API Server' });
});
// Post to Twitter
app.post('/api/twitter/post', async (req, res) => {
try {
const { content, hashtags, imageData } = req.body;
if (!content) {
return res.status(400).json({ error: 'Content is required' });
}
// Prepare tweet text
let tweetText = content;
if (hashtags && hashtags.length > 0) {
const hashtagText = hashtags.map(tag =>
tag.startsWith('#') ? tag : `#${tag}`
).join(' ');
tweetText = `${content} ${hashtagText}`;
}
// Keep under 280 characters
if (tweetText.length > 280) {
tweetText = tweetText.substring(0, 277) + '...';
}
let mediaId = null;
// Handle image if provided
if (imageData) {
try {
let imagePath;
if (imageData.startsWith('http')) {
// Download image from URL
imagePath = path.join(uploadsDir, `temp_${Date.now()}.jpg`);
await downloadImage(imageData, imagePath);
} else if (imageData.startsWith('data:image')) {
// Handle base64 image
const base64Data = imageData.replace(/^data:image\/\w+;base64,/, '');
imagePath = path.join(uploadsDir, `temp_${Date.now()}.jpg`);
fs.writeFileSync(imagePath, base64Data, 'base64');
}
if (imagePath && fs.existsSync(imagePath)) {
// Upload image to Twitter
mediaId = await twitterClient.v1.uploadMedia(imagePath);
// Clean up temporary file
fs.unlinkSync(imagePath);
}
} catch (imageError) {
console.error('Error processing image:', imageError);
// Continue without image if there's an error
}
}
// Post tweet
const tweetOptions = {
text: tweetText
};
if (mediaId) {
tweetOptions.media = { media_ids: [mediaId] };
}
const tweet = await twitterClient.v2.tweet(tweetOptions);
res.json({
success: true,
tweet_id: tweet.data.id,
text: tweetText,
has_image: !!mediaId,
url: `https://twitter.com/user/status/${tweet.data.id}`
});
} catch (error) {
console.error('Twitter API Error:', error);
res.status(500).json({
error: 'Failed to post to Twitter',
message: error.message
});
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Twitter API Server running on port ${PORT}`);
});