@bagalobsta/moltbook-analytics 1.0.0
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/bin/analytics.js +73 -0
- package/lib/index.js +74 -0
- package/package.json +35 -0
package/bin/analytics.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { MoltbookAnalytics } = require('../lib/index.js');
|
|
6
|
+
|
|
7
|
+
const apiKey = process.env.MOLTBOOK_API_KEY;
|
|
8
|
+
if (!apiKey) {
|
|
9
|
+
console.error(chalk.red('Error: MOLTBOOK_API_KEY not set'));
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const analytics = new MoltbookAnalytics(apiKey);
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name('moltanalytics')
|
|
17
|
+
.version('1.0.0')
|
|
18
|
+
.description('Moltbook analytics and insights');
|
|
19
|
+
|
|
20
|
+
program
|
|
21
|
+
.command('trending [submolt]')
|
|
22
|
+
.description('Show trending posts')
|
|
23
|
+
.action(async (submolt = 'builds') => {
|
|
24
|
+
try {
|
|
25
|
+
const posts = await analytics.getTrending(submolt, 10);
|
|
26
|
+
console.log(chalk.cyan(`\n🔥 Trending on m/${submolt}\n`));
|
|
27
|
+
|
|
28
|
+
posts.slice(0, 5).forEach((p, i) => {
|
|
29
|
+
const analyzed = analytics.analyzePost(p);
|
|
30
|
+
console.log(`${i + 1}. ${chalk.yellow(analyzed.title)}`);
|
|
31
|
+
console.log(` ↑${analyzed.upvotes} | ${analyzed.engagement_rate} engagement | ${analyzed.age_hours}h old`);
|
|
32
|
+
});
|
|
33
|
+
console.log();
|
|
34
|
+
} catch (err) {
|
|
35
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
program
|
|
40
|
+
.command('topics [submolt]')
|
|
41
|
+
.description('Show trending topics/keywords')
|
|
42
|
+
.action(async (submolt = 'builds') => {
|
|
43
|
+
try {
|
|
44
|
+
const posts = await analytics.getTrending(submolt, 50);
|
|
45
|
+
const topics = analytics.getTrendingTopics(posts, 15);
|
|
46
|
+
|
|
47
|
+
console.log(chalk.cyan(`\n📊 Trending Topics in m/${submolt}\n`));
|
|
48
|
+
topics.forEach((t, i) => {
|
|
49
|
+
console.log(`${i + 1}. ${chalk.yellow(t.word)} (score: ${t.engagement})`);
|
|
50
|
+
});
|
|
51
|
+
console.log();
|
|
52
|
+
} catch (err) {
|
|
53
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
program
|
|
58
|
+
.command('optimal [submolt]')
|
|
59
|
+
.description('Find optimal posting time')
|
|
60
|
+
.action(async (submolt = 'builds') => {
|
|
61
|
+
try {
|
|
62
|
+
const posts = await analytics.getTrending(submolt, 30);
|
|
63
|
+
const timing = analytics.analyzeOptimalTime(posts);
|
|
64
|
+
|
|
65
|
+
console.log(chalk.cyan(`\n⏰ Optimal Posting Time\n`));
|
|
66
|
+
console.log(`Best hour: ${chalk.yellow(timing.bestTime)}`);
|
|
67
|
+
console.log(`(Posts at this time get highest engagement)\n`);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
program.parse(process.argv);
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
class MoltbookAnalytics {
|
|
2
|
+
constructor(apiKey) {
|
|
3
|
+
this.apiKey = apiKey;
|
|
4
|
+
this.baseUrl = 'https://www.moltbook.com/api/v1';
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// Get trending posts
|
|
8
|
+
async getTrending(submolt = 'builds', limit = 10) {
|
|
9
|
+
try {
|
|
10
|
+
const res = await fetch(`${this.baseUrl}/feed?submolt=${submolt}&sort=hot&limit=${limit}`, {
|
|
11
|
+
headers: { 'Authorization': `Bearer ${this.apiKey}` }
|
|
12
|
+
});
|
|
13
|
+
const data = await res.json();
|
|
14
|
+
return data.posts || [];
|
|
15
|
+
} catch (err) {
|
|
16
|
+
throw new Error(`Failed to fetch trending: ${err.message}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Analyze post performance
|
|
21
|
+
analyzePost(post) {
|
|
22
|
+
const engagement = post.upvotes + (post.comment_count || 0) * 2;
|
|
23
|
+
const engagement_rate = engagement > 100 ? 'high' : engagement > 50 ? 'medium' : 'low';
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
title: post.title,
|
|
27
|
+
upvotes: post.upvotes,
|
|
28
|
+
comments: post.comment_count || 0,
|
|
29
|
+
engagement_score: engagement,
|
|
30
|
+
engagement_rate,
|
|
31
|
+
author: post.author.name,
|
|
32
|
+
age_hours: Math.round((Date.now() - new Date(post.created_at)) / (1000 * 60 * 60))
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Get optimal posting time (stub for API expansion)
|
|
37
|
+
analyzeOptimalTime(posts) {
|
|
38
|
+
const times = posts.map(p => new Date(p.created_at).getHours());
|
|
39
|
+
const avgEngagement = {};
|
|
40
|
+
|
|
41
|
+
times.forEach((h, i) => {
|
|
42
|
+
avgEngagement[h] = (avgEngagement[h] || 0) + posts[i].upvotes;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const best = Object.entries(avgEngagement)
|
|
46
|
+
.sort((a, b) => b[1] - a[1])[0];
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
bestHour: best ? parseInt(best[0]) : 12,
|
|
50
|
+
bestTime: best ? `${best[0]}:00 UTC` : 'noon UTC'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Keyword frequency (what topics trend)
|
|
55
|
+
getTrendingTopics(posts, limit = 10) {
|
|
56
|
+
const words = {};
|
|
57
|
+
const stopwords = ['the', 'a', 'is', 'to', 'and', 'in', 'of', 'for', 'with', 'that'];
|
|
58
|
+
|
|
59
|
+
posts.forEach(p => {
|
|
60
|
+
p.title.toLowerCase().split(/\s+/).forEach(word => {
|
|
61
|
+
if (word.length > 4 && !stopwords.includes(word)) {
|
|
62
|
+
words[word] = (words[word] || 0) + p.upvotes;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return Object.entries(words)
|
|
68
|
+
.sort((a, b) => b[1] - a[1])
|
|
69
|
+
.slice(0, limit)
|
|
70
|
+
.map(([word, score]) => ({ word, engagement: score }));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = { MoltbookAnalytics };
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bagalobsta/moltbook-analytics",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Analytics for Moltbook. Track post performance, trending topics, optimal posting times.",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"moltanalytics": "bin/analytics.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo 'ready'"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"moltbook",
|
|
14
|
+
"analytics",
|
|
15
|
+
"social",
|
|
16
|
+
"posts",
|
|
17
|
+
"engagement"
|
|
18
|
+
],
|
|
19
|
+
"author": "Bagalobsta <bagalobsta@protonmail.com>",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/bagalobsta/moltbook-analytics.git"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"chalk": "^4.1.2",
|
|
27
|
+
"commander": "^11.1.0"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=14.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|