]>
git.r.bdr.sh - rbdr/linkding-linkblog-updater/blob - index.js
1 const { exec
} = require('child_process');
2 const { resolve
, join
} = require('path');
3 const { rm
, writeFile
} = require('fs/promises');
4 const { promisify
} = require('util');
9 apiUrl: process
.env
.API_URL
,
10 apiToken: process
.env
.API_TOKEN
,
11 blogUrl: process
.env
.BLOG_URL
,
12 archiveUrl: process
.env
.ARCHIVE_URL
,
13 blogPublicUrl: process
.env
.BLOG_PUBLIC_URL
,
14 archivePublicUrl: process
.env
.ARCHIVE_PUBLIC_URL
,
15 tootToken: process
.env
.TOOT_TOKEN
,
16 mastodonDomain: process
.env
.MASTODON_DOMAIN
,
18 date: (new Date()).toISOString().split('T')[0],
20 generateGemtext(title
, text
) {
22 return `# ${title}\n\n${text}`;
27 return posts
.map((post
) => {
29 const title
= post
.title
|| post
.website_title
30 return `=> ${post.url} ${title}\n${post.notes}`;
36 const title
= posts
[0].title
|| posts
[0].website_title
38 if (posts
.length
=== 1) {
39 return `Link: ${title}`;
41 return `${posts.length} links for ${internals.date}`;
46 return text
.toLowerCase().replace(/[^a
-z0
-9 ]/g
, '').replace(/ +/g
, '-')
51 const body
= new FormData();
54 `New post: ${title}\n\nAvailable on:\n\n♊️ the gemini archive ${internals.archivePublicUrl}\n\n or, the ephemeral blog 🌐: ${internals.blogPublicUrl}`
56 return fetch(`https://${internals.mastodonDomain}/api/v1/statuses`, {
59 Authorization: `Bearer ${internals.tootToken}`,
65 async
getBookmarks() {
67 const url
= join(internals
.apiUrl
, 'bookmarks') + '?q=%23linkblog';
68 const response
= await
fetch(url
, {
70 'Content-Type': 'application/json',
71 Authorization: `Token ${internals.apiToken}`
74 const data
= await response
.json();
79 async
updateBookmark(bookmark
) {
81 const url
= join(internals
.apiUrl
, 'bookmarks', `${bookmark.id}`)
82 const response
= await
fetch(url
, {
86 tag_names: bookmark
.tag_names
.map((tag
) => tag
=== 'linkblog' ? 'linkblog-posted' : tag
)
90 'Content-Type': 'application/json',
91 Authorization: `Token ${internals.apiToken}`
98 async
function run() {
99 const bookmarks
= await internals
.getBookmarks();
101 if (bookmarks
.length
=== 0) {
102 console
.error('No links to post');
106 const title
= internals
.getTitle(bookmarks
);
107 const text
= internals
.getText(bookmarks
);
108 const gemtext
= internals
.generateGemtext(title
, text
);
109 const filename
= internals
.slugify(title
);
111 const gemfile
= resolve(join(__dirname
, `${filename}.gmi`));
112 await
writeFile(gemfile
, gemtext
);
113 await internals
.exec(`blog add ${gemfile}`);
114 await internals
.exec(`blog publish ${internals.blogUrl}`);
115 await internals
.exec(`blog publish-archive ${internals.archiveUrl}`);
118 for (const bookmark
of bookmarks
) {
119 await internals
.updateBookmark(bookmark
);
122 if (internals
.tootToken
) {
123 await internals
.toot(title
);
128 .then(() => process
.exit(0))