moltkeeper 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/molter.js +74 -0
- package/lib/molter.js +84 -0
- package/package.json +33 -0
package/bin/molter.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { Molter } = require('../lib/molter.js');
|
|
6
|
+
|
|
7
|
+
const molter = new Molter();
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.name('molter')
|
|
11
|
+
.version('1.0.0')
|
|
12
|
+
.description('Schedule and manage Moltbook posts');
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.command('draft <title>')
|
|
16
|
+
.option('-s, --submolt <submolt>', 'Submolt (default: general)', 'general')
|
|
17
|
+
.option('-c, --content <content>', 'Post content')
|
|
18
|
+
.action((title, options) => {
|
|
19
|
+
const draft = molter.saveDraft(title, options.content || '', options.submolt);
|
|
20
|
+
console.log(chalk.green(`ā
Draft saved (ID: ${draft.id})`));
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
program
|
|
24
|
+
.command('drafts')
|
|
25
|
+
.description('List all drafts')
|
|
26
|
+
.action(() => {
|
|
27
|
+
const drafts = molter.listDrafts();
|
|
28
|
+
if (drafts.length === 0) {
|
|
29
|
+
console.log(chalk.yellow('No drafts yet'));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
console.log(chalk.cyan('\nš Drafts\n'));
|
|
33
|
+
drafts.forEach(d => {
|
|
34
|
+
console.log(`[${d.id}] ${d.title}`);
|
|
35
|
+
console.log(` m/${d.submolt} ⢠Created: ${new Date(d.created).toLocaleDateString()}`);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
program
|
|
40
|
+
.command('schedule <draftId> <time>')
|
|
41
|
+
.description('Schedule draft for posting (time: ISO-8601 or "tomorrow 9am")')
|
|
42
|
+
.action((draftId, time) => {
|
|
43
|
+
try {
|
|
44
|
+
const scheduled = molter.schedulePost(parseInt(draftId), time);
|
|
45
|
+
console.log(chalk.green(`ā
Scheduled for ${time}`));
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.log(chalk.red(`ā ${err.message}`));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
program
|
|
52
|
+
.command('upcoming')
|
|
53
|
+
.description('Show upcoming scheduled posts')
|
|
54
|
+
.action(() => {
|
|
55
|
+
const upcoming = molter.getUpcoming();
|
|
56
|
+
if (upcoming.length === 0) {
|
|
57
|
+
console.log(chalk.yellow('No posts scheduled'));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
console.log(chalk.cyan('\nš
Upcoming Posts\n'));
|
|
61
|
+
upcoming.forEach(p => {
|
|
62
|
+
console.log(`${new Date(p.scheduledTime).toLocaleString()} ā ${p.title}`);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
program
|
|
67
|
+
.command('posted <draftId>')
|
|
68
|
+
.description('Mark draft as posted')
|
|
69
|
+
.action((draftId) => {
|
|
70
|
+
molter.markPosted(parseInt(draftId));
|
|
71
|
+
console.log(chalk.green('ā
Marked as posted'));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
program.parse(process.argv);
|
package/lib/molter.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
|
|
5
|
+
class Molter {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.dataDir = path.join(process.env.HOME || '/tmp', '.molter');
|
|
8
|
+
this.draftsFile = path.join(this.dataDir, 'drafts.json');
|
|
9
|
+
this.scheduleFile = path.join(this.dataDir, 'schedule.json');
|
|
10
|
+
this.initDirs();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
initDirs() {
|
|
14
|
+
fs.ensureDirSync(this.dataDir);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Save draft post
|
|
18
|
+
saveDraft(title, content, submolt = 'general') {
|
|
19
|
+
const drafts = this.readFile(this.draftsFile, []);
|
|
20
|
+
const draft = {
|
|
21
|
+
id: Date.now(),
|
|
22
|
+
title,
|
|
23
|
+
content,
|
|
24
|
+
submolt,
|
|
25
|
+
created: new Date().toISOString()
|
|
26
|
+
};
|
|
27
|
+
drafts.push(draft);
|
|
28
|
+
fs.writeJsonSync(this.draftsFile, drafts, { spaces: 2 });
|
|
29
|
+
return draft;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// List drafts
|
|
33
|
+
listDrafts() {
|
|
34
|
+
return this.readFile(this.draftsFile, []);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Schedule post
|
|
38
|
+
schedulePost(draftId, scheduledTime) {
|
|
39
|
+
const schedule = this.readFile(this.scheduleFile, []);
|
|
40
|
+
const draft = this.listDrafts().find(d => d.id === draftId);
|
|
41
|
+
|
|
42
|
+
if (!draft) {
|
|
43
|
+
throw new Error('Draft not found');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const scheduled = {
|
|
47
|
+
...draft,
|
|
48
|
+
scheduledTime,
|
|
49
|
+
status: 'scheduled'
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
schedule.push(scheduled);
|
|
53
|
+
fs.writeJsonSync(this.scheduleFile, schedule, { spaces: 2 });
|
|
54
|
+
return scheduled;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Get upcoming scheduled posts
|
|
58
|
+
getUpcoming() {
|
|
59
|
+
const schedule = this.readFile(this.scheduleFile, []);
|
|
60
|
+
return schedule.filter(p => p.status === 'scheduled').sort((a, b) =>
|
|
61
|
+
new Date(a.scheduledTime) - new Date(b.scheduledTime)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Mark as posted
|
|
66
|
+
markPosted(draftId) {
|
|
67
|
+
const schedule = this.readFile(this.scheduleFile, []);
|
|
68
|
+
const post = schedule.find(p => p.id === draftId);
|
|
69
|
+
if (post) {
|
|
70
|
+
post.status = 'posted';
|
|
71
|
+
post.postedTime = new Date().toISOString();
|
|
72
|
+
}
|
|
73
|
+
fs.writeJsonSync(this.scheduleFile, schedule, { spaces: 2 });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
readFile(filepath, defaultVal) {
|
|
77
|
+
if (fs.existsSync(filepath)) {
|
|
78
|
+
return fs.readJsonSync(filepath);
|
|
79
|
+
}
|
|
80
|
+
return defaultVal;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = { Molter };
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "moltkeeper",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Schedule and bulk-manage Moltbook posts. Calendar, drafts, analytics.",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"moltkeeper": "bin/molter.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo 'tests ready'"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"moltbook",
|
|
14
|
+
"scheduler",
|
|
15
|
+
"social",
|
|
16
|
+
"posting",
|
|
17
|
+
"calendar"
|
|
18
|
+
],
|
|
19
|
+
"author": "Bagalobsta <bagalobsta@protonmail.com>",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/bagalobsta/moltkeeper.git"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"chalk": "^4.1.2",
|
|
27
|
+
"commander": "^11.1.0",
|
|
28
|
+
"fs-extra": "^11.2.0"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=14.0.0"
|
|
32
|
+
}
|
|
33
|
+
}
|