--- /dev/null
+node_modules
--- /dev/null
+# Pinboard Linkblog Updater
+
+This only works with [blog][blog].
+
+
+[blog]: https://git.sr.ht/~rbdr/blog
--- /dev/null
+const { exec } = require('child_process');
+const { resolve, join} = require('path');
+const { rm, writeFile } = require('fs/promises');
+const { debuglog, promisify } = require('util');
+const Pinboard = require('node-pinboard').default;
+
+const internals = {
+ exec: promisify(exec),
+ debuglog: debuglog('blog'),
+ apiToken: process.env.PINBOARD_TOKEN,
+ date: (new Date()).toISOString().split('T')[0],
+
+ generateGemtext(posts) {
+
+ const title = posts.length === 1 ? 'A link' : `${posts.length} links`;
+
+ const linkText = posts.map((pin) => {
+ return `=> ${pin.href} ${pin.description}\n${pin.extended}`;
+ }).join('\n\n');
+
+ return `# ${title} for ${internals.date}\n\n${linkText}`;
+ }
+};
+
+
+async function run() {
+ const pinboard = new Pinboard(internals.apiToken);
+ const getPins = promisify(pinboard.get);
+ const addPin = promisify(pinboard.add);
+
+ internals.debuglog('Fetching Pins');
+ const pins = await getPins({ tag: 'linkblog' });
+
+ internals.debuglog(`Found ${pins.posts.length} pins`);
+ if (pins.posts.length === 0) {
+ console.error('No links to post');
+ return;
+ }
+
+ internals.debuglog('Generating gemtext');
+ const gemtext = internals.generateGemtext(pins.posts);
+ const gemfile = resolve(join(__dirname, `linkblog-${internals.date}.gmi`));
+ internals.debuglog(`Writing to ${gemfile}`);
+ await writeFile(gemfile, gemtext);
+ internals.debuglog('Adding gemfile to log');
+ const output = await internals.exec(`blog --add ${gemfile}`);
+ internals.debuglog(output.stderr);
+ internals.debuglog(`Removing ${gemfile}`);
+ await rm(gemfile);
+
+ for (const pin of pins.posts) {
+ internals.debuglog(`Updating ${pin.href}`);
+ await addPin({
+ url: pin.href,
+ description: pin.description,
+ extended: pin.extended,
+ dt: pin.time,
+ tags: pin.tags.replace('linkblog', 'linkblog-posted')
+ });
+ }
+}
+
+run()
+ .then(() => process.exit(0))
+ .catch((err) => {
+ console.error(err);
+ process.exit(1);
+ })
--- /dev/null
+{
+ "name": "pinboard-linkblog-updater",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "pinboard-linkblog-updater",
+ "version": "1.0.0",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "node-pinboard": "^2.0.1"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-pinboard": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/node-pinboard/-/node-pinboard-2.0.1.tgz",
+ "integrity": "sha512-TvFjnLQRW/mEJmBDbBaL3APOxx1bCxCt1iw37YqgtLzWNUnu9zez2JTARd4qjcXp6uvJ8oaRhFNRJsLBhR7epQ==",
+ "dependencies": {
+ "node-fetch": "^2.6.0"
+ },
+ "engines": {
+ "node": ">= 8.0"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ }
+ },
+ "dependencies": {
+ "node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "requires": {
+ "whatwg-url": "^5.0.0"
+ }
+ },
+ "node-pinboard": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/node-pinboard/-/node-pinboard-2.0.1.tgz",
+ "integrity": "sha512-TvFjnLQRW/mEJmBDbBaL3APOxx1bCxCt1iw37YqgtLzWNUnu9zez2JTARd4qjcXp6uvJ8oaRhFNRJsLBhR7epQ==",
+ "requires": {
+ "node-fetch": "^2.6.0"
+ }
+ },
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "requires": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ }
+ }
+}
--- /dev/null
+{
+ "name": "pinboard-linkblog-updater",
+ "version": "1.0.0",
+ "description": "A linkblog automation for blog, using pinboard as a source, intended to run with cron",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@git.sr.ht/~rbdr/pinboard-linkblog-updater.git"
+ },
+ "author": "",
+ "license": "Apache-2.0",
+ "bugs": {
+ "url": "https://todo.sr.ht/~rbdr/pinboard-linkblog-updater"
+ },
+ "homepage": "https://git.sr.ht/~rbdr/pinboard-linkblog-updater#readme",
+ "dependencies": {
+ "node-pinboard": "^2.0.1"
+ }
+}