]>
git.r.bdr.sh - rbdr/linkding-linkblog-updater/blob - index.js
ef06ad9301dd27f5f3085d8dfded3f574170fcbc
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 return `=> ${post.url} ${post.title}\n${post.notes}`;
35 if (posts
.length
=== 1) {
36 return `Link: ${posts[0].title}`;
38 return `${posts.length} links for ${internals.date}`;
43 return text
.toLowerCase().replace(/[^a
-z0
-9 ]/g
, '').replace(/ +/g
, '-')
48 const body
= new FormData();
51 `New post: ${title}\n\nAvailable on:\n\n♊️ the gemini archive ${internals.archivePublicUrl}\n\n or, the ephemeral blog 🌐: ${internals.blogPublicUrl}`
53 return fetch(`https://${internals.mastodonDomain}/api/v1/statuses`, {
56 Authorization: `Bearer ${internals.tootToken}`,
62 async
getBookmarks() {
64 const url
= join(internals
.apiUrl
, 'bookmarks') + '?q=%23linkblog';
65 const response
= await
fetch(url
, {
67 'Content-Type': 'application/json',
68 Authorization: `Token ${internals.apiToken}`
71 const data
= await response
.json();
76 async
updateBookmark(bookmark
) {
78 console
.log(bookmark
.tag_names
);
79 console
.log(bookmark
.tag_names
.map((tag
) => tag
=== 'linkblog' ? 'linkblog-posted' : tag
));
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}`
95 const data
= await response
.text();
102 async
function run() {
103 const bookmarks
= await internals
.getBookmarks();
105 if (bookmarks
.length
=== 0) {
106 console
.error('No links to post');
110 const title
= internals
.getTitle(bookmarks
);
111 const text
= internals
.getText(bookmarks
);
112 const gemtext
= internals
.generateGemtext(title
, text
);
113 const filename
= internals
.slugify(title
);
115 const gemfile
= resolve(join(__dirname
, `${filename}.gmi`));
116 await
writeFile(gemfile
, gemtext
);
117 await internals
.exec(`blog add ${gemfile}`);
118 await internals
.exec(`blog publish ${internals.blogUrl}`);
119 await internals
.exec(`blog publish-archive ${internals.archiveUrl}`);
122 for (const bookmark
of bookmarks
) {
123 await internals
.updateBookmark(bookmark
);
126 if (internals
.tootToken
) {
127 await internals
.toot(title
);
132 .then(() => process
.exit(0))