X-Git-Url: https://git.r.bdr.sh/rbdr/linkding-linkblog-updater/blobdiff_plain/f0b2faff6e6e69de483fccb940f7fc989c4c9030..913b63d6a02cebc976273794b6d4cf7b9a9d69a8:/index.js?ds=sidebyside diff --git a/index.js b/index.js index 549e223..275b96c 100644 --- a/index.js +++ b/index.js @@ -2,14 +2,18 @@ const { exec } = require('child_process'); const { resolve, join} = require('path'); const { rm, writeFile } = require('fs/promises'); const { promisify } = require('util'); -const Pinboard = require('node-pinboard').default; const internals = { exec: promisify(exec), - apiToken: process.env.PINBOARD_TOKEN, + apiUrl: process.env.API_URL, + apiToken: process.env.API_TOKEN, blogUrl: process.env.BLOG_URL, archiveUrl: process.env.ARCHIVE_URL, + blogPublicUrl: process.env.BLOG_PUBLIC_URL, + archivePublicUrl: process.env.ARCHIVE_PUBLIC_URL, + tootToken: process.env.TOOT_TOKEN, + mastodonDomain: process.env.MASTODON_DOMAIN, date: (new Date()).toISOString().split('T')[0], @@ -20,16 +24,19 @@ const internals = { getText(posts) { - const linkText = posts.map((post) => { + return posts.map((post) => { - return `=> ${post.href} ${post.description}\n${post.extended}`; + const title = post.title || post.website_title + return `=> ${post.url} ${title}\n${post.notes}`; }).join('\n\n'); }, getTitle(posts) { + const title = posts[0].title || posts[0].website_title + if (posts.length === 1) { - return posts[0].description; + return `Link: ${title}`; } return `${posts.length} links for ${internals.date}`; }, @@ -37,42 +44,83 @@ const internals = { slugify(text) { return text.toLowerCase().replace(/[^a-z0-9 ]/g, '').replace(/ +/g, '-') + }, + + async toot(title) { + + const body = new FormData(); + body.set( + 'status', + `New post: ${title}\n\nAvailable on:\n\n♊️ the gemini archive ${internals.archivePublicUrl}\n\n or, the ephemeral blog 🌐: ${internals.blogPublicUrl}` + ); + return fetch(`https://${internals.mastodonDomain}/api/v1/statuses`, { + method: 'POST', + headers: { + Authorization: `Bearer ${internals.tootToken}`, + }, + body + }); + }, + + async getBookmarks() { + + const url = join(internals.apiUrl, 'bookmarks') + '?q=%23linkblog'; + const response = await fetch(url, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Token ${internals.apiToken}` + } + }); + const data = await response.json(); + + return data.results; + }, + + async updateBookmark(bookmark) { + + const url = join(internals.apiUrl, 'bookmarks', `${bookmark.id}`) + const response = await fetch(url, { + method: 'PATCH', + body: JSON.stringify( + { + tag_names: bookmark.tag_names.map((tag) => tag === 'linkblog' ? 'linkblog-posted' : tag) + } + ), + headers: { + 'Content-Type': 'application/json', + Authorization: `Token ${internals.apiToken}` + } + }); } }; async function run() { - const pinboard = new Pinboard(internals.apiToken); - const getPins = promisify(pinboard.all); - const addPin = promisify(pinboard.add); + const bookmarks = await internals.getBookmarks(); - const pins = await getPins({ tag: 'linkblog' }); - - if (pins.length === 0) { + if (bookmarks.length === 0) { console.error('No links to post'); return; } - const title = internals.getTitle(posts); - const text = internals.getText(posts); + const title = internals.getTitle(bookmarks); + const text = internals.getText(bookmarks); const gemtext = internals.generateGemtext(title, text); const filename = internals.slugify(title); const gemfile = resolve(join(__dirname, `${filename}.gmi`)); await writeFile(gemfile, gemtext); - await internals.exec(`blog --add ${gemfile}`); - await internals.exec(`blog --publish ${internals.blogUrl}`); - await internals.exec(`blog --publish-archive ${internals.archiveUrl}`); + await internals.exec(`blog add ${gemfile}`); + await internals.exec(`blog publish ${internals.blogUrl}`); + await internals.exec(`blog publish-archive ${internals.archiveUrl}`); await rm(gemfile); - for (const pin of pins) { - await addPin({ - url: pin.href, - description: pin.description, - extended: pin.extended, - dt: pin.time, - tags: pin.tags.replace('linkblog', 'linkblog-posted') - }); + for (const bookmark of bookmarks) { + await internals.updateBookmark(bookmark); + } + + if (internals.tootToken) { + await internals.toot(title); } }