]> git.r.bdr.sh - rbdr/pinboard-linkblog-updater/blame - index.js
tooting and fixes
[rbdr/pinboard-linkblog-updater] / index.js
CommitLineData
89326417
RBR
1const { exec } = require('child_process');
2const { resolve, join} = require('path');
3const { rm, writeFile } = require('fs/promises');
2390d230 4const { promisify } = require('util');
89326417
RBR
5const Pinboard = require('node-pinboard').default;
6
7const internals = {
8 exec: promisify(exec),
2390d230 9
89326417 10 apiToken: process.env.PINBOARD_TOKEN,
2390d230
RBR
11 blogUrl: process.env.BLOG_URL,
12 archiveUrl: process.env.ARCHIVE_URL,
278296c2 13 tootToken: process.env.TOOT_TOKEN,
2390d230 14
89326417
RBR
15 date: (new Date()).toISOString().split('T')[0],
16
f0b2faff 17 generateGemtext(title, text) {
89326417 18
f0b2faff
RBR
19 return `# ${title}\n\n${text}`;
20 },
89326417 21
f0b2faff
RBR
22 getText(posts) {
23
278296c2 24 return posts.map((post) => {
f0b2faff
RBR
25
26 return `=> ${post.href} ${post.description}\n${post.extended}`;
89326417 27 }).join('\n\n');
f0b2faff
RBR
28 },
29
30 getTitle(posts) {
89326417 31
f0b2faff 32 if (posts.length === 1) {
278296c2 33 return `Link: ${posts[0].description}`;
f0b2faff
RBR
34 }
35 return `${posts.length} links for ${internals.date}`;
36 },
37
38 slugify(text) {
39
40 return text.toLowerCase().replace(/[^a-z0-9 ]/g, '').replace(/ +/g, '-')
278296c2
RBR
41 },
42
43 async toot(title) {
44
45 const body = new FormData();
46 body.set(
47 'status',
48 `New post: ${title}\n\nAvailable on:\n\nā™Šļø the gemini archive gemini://gemini.unlimited.pizza/gemlog/\n\n or, the ephemeral blog šŸŒ: https://blog.unlimited.pizza`
49 );
50 return fetch('https://mastodon.social/api/v1/statuses', {
51 method: 'post',
52 headers: {
53 Authorization: `Bearer ${internals.tootToken}`,
54 },
55 body
56 });
89326417 57 }
278296c2 58
89326417
RBR
59};
60
61
62async function run() {
63 const pinboard = new Pinboard(internals.apiToken);
096cf8b1 64 const getPins = promisify(pinboard.all);
89326417
RBR
65 const addPin = promisify(pinboard.add);
66
89326417
RBR
67 const pins = await getPins({ tag: 'linkblog' });
68
28414efe 69 if (pins.length === 0) {
89326417
RBR
70 console.error('No links to post');
71 return;
72 }
73
278296c2
RBR
74 const title = internals.getTitle(pins);
75 const text = internals.getText(pins);
f0b2faff
RBR
76 const gemtext = internals.generateGemtext(title, text);
77 const filename = internals.slugify(title);
78
79 const gemfile = resolve(join(__dirname, `${filename}.gmi`));
89326417 80 await writeFile(gemfile, gemtext);
2390d230
RBR
81 await internals.exec(`blog --add ${gemfile}`);
82 await internals.exec(`blog --publish ${internals.blogUrl}`);
83 await internals.exec(`blog --publish-archive ${internals.archiveUrl}`);
89326417
RBR
84 await rm(gemfile);
85
28414efe 86 for (const pin of pins) {
89326417
RBR
87 await addPin({
88 url: pin.href,
89 description: pin.description,
90 extended: pin.extended,
91 dt: pin.time,
92 tags: pin.tags.replace('linkblog', 'linkblog-posted')
93 });
94 }
278296c2
RBR
95
96 if (internals.tootToken) {
97 await internals.toot(title);
98 }
89326417
RBR
99}
100
101run()
102 .then(() => process.exit(0))
103 .catch((err) => {
104 console.error(err);
105 process.exit(1);
106 })