@aikeytake/social-automation 2.0.5 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/index.js +92 -69
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aikeytake/social-automation",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "Content research and aggregation tool for AI agents",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"author": "aikeytake",
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@aikeytake/social-automation": "2.0.
|
|
27
|
+
"@aikeytake/social-automation": "2.0.5",
|
|
28
28
|
"@supabase/supabase-js": "^2.47.0",
|
|
29
29
|
"axios": "^1.7.9",
|
|
30
30
|
"cheerio": "^1.0.0",
|
package/src/index.js
CHANGED
|
@@ -133,20 +133,26 @@ function getDateString() {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
async function saveSourceData(source, items, today) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
fs.
|
|
136
|
+
try {
|
|
137
|
+
const todayFolder = path.join(__dirname, '../data', today);
|
|
138
|
+
if (!fs.existsSync(todayFolder)) {
|
|
139
|
+
fs.mkdirSync(todayFolder, { recursive: true });
|
|
140
|
+
}
|
|
141
|
+
const filePath = path.join(todayFolder, `${source}.json`);
|
|
142
|
+
const data = {
|
|
143
|
+
date: today,
|
|
144
|
+
source: source,
|
|
145
|
+
total_items: items.length,
|
|
146
|
+
scraped_at: new Date().toISOString(),
|
|
147
|
+
items: items
|
|
148
|
+
};
|
|
149
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
150
|
+
} catch (err) {
|
|
151
|
+
// Vercel ephemeral filesystem - ignore write errors when saving to filesystem
|
|
152
|
+
if (err.code !== 'ENOENT' && err.code !== 'EACCES') {
|
|
153
|
+
logger.warn(`saveSourceData skipped: ${err.message}`);
|
|
154
|
+
}
|
|
139
155
|
}
|
|
140
|
-
|
|
141
|
-
const filePath = path.join(todayFolder, `${source}.json`);
|
|
142
|
-
const data = {
|
|
143
|
-
date: today,
|
|
144
|
-
source: source,
|
|
145
|
-
total_items: items.length,
|
|
146
|
-
scraped_at: new Date().toISOString(),
|
|
147
|
-
items: items
|
|
148
|
-
};
|
|
149
|
-
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
async function saveToSupabase(supabase, items, date) {
|
|
@@ -177,66 +183,83 @@ async function saveToSupabase(supabase, items, date) {
|
|
|
177
183
|
}
|
|
178
184
|
|
|
179
185
|
async function generateCombinedFiles(results, today) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
// Load all source files
|
|
183
|
-
const allItems = [];
|
|
184
|
-
const sourceFiles = fs.readdirSync(todayFolder)
|
|
185
|
-
.filter(f => f.endsWith('.json') && f !== 'all.json' && f !== 'trending.json');
|
|
186
|
-
for (const file of sourceFiles) {
|
|
187
|
-
const filePath = path.join(todayFolder, file);
|
|
188
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
189
|
-
const data = JSON.parse(content);
|
|
190
|
-
allItems.push(...(data.items || []));
|
|
191
|
-
}
|
|
186
|
+
try {
|
|
187
|
+
const todayFolder = path.join(__dirname, '../data', today);
|
|
192
188
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
for (const item of scoredItems) {
|
|
213
|
-
const source = item.source || 'unknown';
|
|
214
|
-
if (!trendingBySource[source]) trendingBySource[source] = 0;
|
|
215
|
-
if (trendingBySource[source] < 5) {
|
|
216
|
-
trendingBySource[source]++;
|
|
217
|
-
finalTrending.push(item);
|
|
189
|
+
// Load all source files
|
|
190
|
+
const allItems = [];
|
|
191
|
+
let sourceFiles = [];
|
|
192
|
+
try {
|
|
193
|
+
sourceFiles = fs.readdirSync(todayFolder)
|
|
194
|
+
.filter(f => f.endsWith('.json') && f !== 'all.json' && f !== 'trending.json');
|
|
195
|
+
} catch {
|
|
196
|
+
// Folder may not exist - skip loading
|
|
197
|
+
sourceFiles = [];
|
|
198
|
+
}
|
|
199
|
+
for (const file of sourceFiles) {
|
|
200
|
+
try {
|
|
201
|
+
const filePath = path.join(todayFolder, file);
|
|
202
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
203
|
+
const data = JSON.parse(content);
|
|
204
|
+
allItems.push(...(data.items || []));
|
|
205
|
+
} catch {
|
|
206
|
+
// Skip unreadable files
|
|
207
|
+
}
|
|
218
208
|
}
|
|
219
|
-
if (finalTrending.length >= 20) break;
|
|
220
|
-
}
|
|
221
209
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
210
|
+
// Save all.json
|
|
211
|
+
const allData = {
|
|
212
|
+
date: today,
|
|
213
|
+
generated_at: new Date().toISOString(),
|
|
214
|
+
total_items: allItems.length,
|
|
215
|
+
sources: results.sources,
|
|
216
|
+
items: allItems
|
|
217
|
+
};
|
|
218
|
+
fs.writeFileSync(path.join(todayFolder, 'all.json'), JSON.stringify(allData, null, 2));
|
|
219
|
+
|
|
220
|
+
// Generate trending.json (top 20 by score with source diversity)
|
|
221
|
+
const scoredItems = allItems
|
|
222
|
+
.filter(item => item.metadata?.score || item.engagement?.upvotes || item.engagement?.points || 0)
|
|
223
|
+
.map(item => ({ ...item, combined_score: calculateScore(item) }))
|
|
224
|
+
.sort((a, b) => b.combined_score - a.combined_score);
|
|
225
|
+
|
|
226
|
+
// Apply source diversity: max 5 items per source
|
|
227
|
+
const trendingBySource = {};
|
|
228
|
+
const finalTrending = [];
|
|
229
|
+
for (const item of scoredItems) {
|
|
230
|
+
const source = item.source || 'unknown';
|
|
231
|
+
if (!trendingBySource[source]) trendingBySource[source] = 0;
|
|
232
|
+
if (trendingBySource[source] < 5) {
|
|
233
|
+
trendingBySource[source]++;
|
|
234
|
+
finalTrending.push(item);
|
|
235
|
+
}
|
|
236
|
+
if (finalTrending.length >= 20) break;
|
|
237
|
+
}
|
|
237
238
|
|
|
238
|
-
|
|
239
|
-
|
|
239
|
+
const trendingData = {
|
|
240
|
+
date: today,
|
|
241
|
+
generated_at: new Date().toISOString(),
|
|
242
|
+
total_items: finalTrending.length,
|
|
243
|
+
items: finalTrending.map((item, index) => ({
|
|
244
|
+
rank: index + 1,
|
|
245
|
+
score: item.combined_score,
|
|
246
|
+
sources: getItemSources(item),
|
|
247
|
+
title: item.title,
|
|
248
|
+
url: item.url || item.link,
|
|
249
|
+
summary: extractSummary(item),
|
|
250
|
+
keywords: extractKeywords(item),
|
|
251
|
+
engagement: item.engagement || item.metadata || {}
|
|
252
|
+
}))
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
fs.writeFileSync(path.join(todayFolder, 'trending.json'), JSON.stringify(trendingData, null, 2));
|
|
256
|
+
logger.success(`✅ Generated: trending.json (${finalTrending.length} items)`);
|
|
257
|
+
} catch (err) {
|
|
258
|
+
// Vercel ephemeral filesystem - ignore write errors
|
|
259
|
+
if (err.code !== 'ENOENT' && err.code !== 'EACCES') {
|
|
260
|
+
logger.warn(`generateCombinedFiles skipped: ${err.message}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
240
263
|
}
|
|
241
264
|
|
|
242
265
|
function calculateScore(item) {
|