diff --git a/.envrc b/.envrc index d4b93ce..d5c89b4 100644 --- a/.envrc +++ b/.envrc @@ -1,2 +1,7 @@ +#!/usr/bin/env bash use flake layout node + +export MB_DATA_URL='' # musicbrainz +export LB_DATA_URL='' # listenbrainz +export OSM_DATA_URL='' # openstreetmap diff --git a/package.json b/package.json index 6047217..224f627 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "seedrandom": "^3.0.5" }, "dependencies": { + "@11ty/eleventy-fetch": "^4.0.0", "@11ty/eleventy-plugin-rss": "^1.1.2", "@11ty/eleventy-plugin-syntaxhighlight": "^4.1.0", "@junwatu/markdown-it-lazy-loading": "1.0.0-beta.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c12e2f..9bb8503 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2,6 +2,7 @@ lockfileVersion: 5.4 specifiers: '@11ty/eleventy': ^2.0.0 + '@11ty/eleventy-fetch': ^4.0.0 '@11ty/eleventy-plugin-rss': ^1.1.2 '@11ty/eleventy-plugin-syntaxhighlight': ^4.1.0 '@junwatu/markdown-it-lazy-loading': 1.0.0-beta.4 @@ -21,6 +22,7 @@ specifiers: seedrandom: ^3.0.5 dependencies: + '@11ty/eleventy-fetch': 4.0.0 '@11ty/eleventy-plugin-rss': 1.1.2 '@11ty/eleventy-plugin-syntaxhighlight': 4.1.0 '@junwatu/markdown-it-lazy-loading': 1.0.0-beta.4 @@ -70,6 +72,19 @@ packages: - utf-8-validate dev: true + /@11ty/eleventy-fetch/4.0.0: + resolution: {integrity: sha512-wGAd0r+8DUWr22fK5r07dOKuNY6ltA7hX+sJzngGZL1yJmuUVdM/xPQZ+iq0BFgf/ZeRdpVEzf2D0cpVZUuiTg==} + engines: {node: '>=14'} + dependencies: + debug: 4.3.4 + flat-cache: 3.0.4 + node-fetch: 2.6.7 + p-queue: 6.6.2 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /@11ty/eleventy-plugin-rss/1.1.2: resolution: {integrity: sha512-QdXMl29MzMtyMj9Y1lYijPX4vGMnBDo4Peyi4GCJznCO4+eryAZiyVYciLBCek893EXL3RLOuVSshYo+jvjZ0w==} dependencies: @@ -383,7 +398,6 @@ packages: /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true /bcp-47-match/1.0.3: resolution: {integrity: sha512-LggQ4YTdjWQSKELZF5JwchnBa1u0pIQSZf5lSdOHEdbVP55h0qICA/FUp3+W99q0xqxYa1ZQizTUH87gecII5w==} @@ -421,7 +435,6 @@ packages: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true /brace-expansion/2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} @@ -576,7 +589,6 @@ packages: /concat-map/0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} - dev: true /constantinople/4.0.1: resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==} @@ -682,7 +694,6 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: true /decodeuricomponent/0.3.1: resolution: {integrity: sha512-8PuirnWM7fdE54vRKoVT60RQlkFXgKsi7ToV4pdVbj9jc9qGSFt4P10Oi3UK+FPHZi+lhqRdPyG2QqhSfIhtQQ==} @@ -927,6 +938,10 @@ packages: es5-ext: 0.10.61 dev: false + /eventemitter3/4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + dev: false + /ext/1.6.0: resolution: {integrity: sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==} dependencies: @@ -994,6 +1009,18 @@ packages: - supports-color dev: true + /flat-cache/3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.7 + rimraf: 3.0.2 + dev: false + + /flatted/3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + dev: false + /follow-redirects/1.14.9: resolution: {integrity: sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==} engines: {node: '>=4.0'} @@ -1019,7 +1046,6 @@ packages: /fs.realpath/1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true /fsevents/2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} @@ -1065,7 +1091,6 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true /globby/13.1.2: resolution: {integrity: sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==} @@ -1194,7 +1219,6 @@ packages: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true /inherits/2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -1549,7 +1573,6 @@ packages: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 - dev: true /minimatch/5.1.0: resolution: {integrity: sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==} @@ -1702,7 +1725,6 @@ packages: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 - dev: true /optimist/0.6.1: resolution: {integrity: sha1-2j6nRob6IaGaERwybpDrFaAZZoY=} @@ -1711,6 +1733,26 @@ packages: wordwrap: 0.0.3 dev: false + /p-finally/1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + dev: false + + /p-queue/6.6.2: + resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} + engines: {node: '>=8'} + dependencies: + eventemitter3: 4.0.7 + p-timeout: 3.2.0 + dev: false + + /p-timeout/3.2.0: + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} + dependencies: + p-finally: 1.0.0 + dev: false + /parse-srcset/1.0.2: resolution: {integrity: sha1-8r0iH2zJcKk42IVWq8WJyqqiveE=} @@ -1735,7 +1777,6 @@ packages: /path-is-absolute/1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - dev: true /path-key/3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} @@ -2068,6 +2109,13 @@ packages: glob: 7.2.0 dev: true + /rimraf/3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.0 + dev: false + /rss-parser/3.12.0: resolution: {integrity: sha512-aqD3E8iavcCdkhVxNDIdg1nkBI17jgqF+9OqPS1orwNaOgySdpvq6B+DoONLhzjzwV8mWg37sb60e4bmLK117A==} dependencies: @@ -2235,7 +2283,7 @@ packages: dev: true /tr46/0.0.3: - resolution: {integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=} + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: false /tslib/2.3.1: @@ -2302,11 +2350,11 @@ packages: dev: true /webidl-conversions/3.0.1: - resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=} + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: false /whatwg-url/5.0.0: - resolution: {integrity: sha1-lmRU6HZUYuN2RNNib2dCzotwll0=} + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 @@ -2350,7 +2398,6 @@ packages: /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true /ws/8.12.1: resolution: {integrity: sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==} diff --git a/src/_includes/posts.njk b/src/_includes/posts.njk index d21d908..ab8c886 100644 --- a/src/_includes/posts.njk +++ b/src/_includes/posts.njk @@ -11,8 +11,11 @@ {% block sidebar %}
+{% set tableOfContents = content | toc(tags=['h2']) %} +{% if tableOfContents %}

Content

-{{ content | toc(tags=['h2']) | safe }} +{{ tableOfContents | safe }} +{% endif %} Go Back Home
{% endblock %} diff --git a/src/assets/style.scss b/src/assets/style.scss index 8d4bfc6..f5e327e 100644 --- a/src/assets/style.scss +++ b/src/assets/style.scss @@ -307,7 +307,7 @@ footer { article { display: none; } } -.posts { +.posts, .gardening { aside { a { color: $alternative-links; diff --git a/src/gardening/gardening.11tydata.js b/src/gardening/gardening.11tydata.js new file mode 100644 index 0000000..2418ee8 --- /dev/null +++ b/src/gardening/gardening.11tydata.js @@ -0,0 +1,51 @@ +const { MB_DATA_URL, LB_DATA_URL, OSM_DATA_URL } = require('process').env +const eleventyFetch = require('@11ty/eleventy-fetch') + +const osmChangeSets = async (baseUrl) => { + let lastTime = null + let changesets = [] + while (true) { + const url = baseUrl + (lastTime != null ? `&time=2021-01-01T00:00:00Z,${lastTime}` : '') + // console.log('eleventyFetching osm data', url) + const res = await eleventyFetch(url, { duration: '1d', type: 'json' }) + changesets = changesets.concat(res.changesets) + if (res.changesets.length > 0) { + lastTime = res.changesets[res.changesets.length - 1].created_at + } else { + break + } + } + return changesets +} + +module.exports = async _config => { + const [ + musicBrainz, + listenBrainzRaw, + openStreetMapRaw + ] = await Promise.all([ + eleventyFetch(MB_DATA_URL, { duration: '1d', type: 'json' }), + eleventyFetch(LB_DATA_URL, { duration: '1d', type: 'json' }), + osmChangeSets(OSM_DATA_URL) + ]) + + const listenBrainz = { + firstYear: listenBrainzRaw.payload.listening_activity.find(activity => activity.listen_count > 0).time_range, + total: listenBrainzRaw.payload.listening_activity.map(activity => activity.listen_count).reduce((a, b) => a + b) + } + + const openStreetMap = { + changesets: openStreetMapRaw, + stats: { + doneInStreetComplete: openStreetMapRaw.filter(c => /^streetcomplete/i.exec(c.tags != null ? c.tags.created_by : '') != null).length, + doneInOsmand: openStreetMapRaw.filter(c => /^osmand/i.exec(c.tags != null ? c.tags.created_by : '') != null).length, + } + } + + return { + layout: "posts.njk", + listenBrainz, + musicBrainz, + openStreetMap, + } +} diff --git a/src/gardening/index.md b/src/gardening/index.md new file mode 100644 index 0000000..42d755b --- /dev/null +++ b/src/gardening/index.md @@ -0,0 +1,12 @@ +--- +title: Gardening the commons 🪴 +--- +# Gardening the commons 🪴 + +This page holds information about open data platforms that I participate in. Text that is marked `like this` will update whenever this site is rebuilt. + +I have submitted `{{ musicBrainz.edits.total }}` edits to [MusicBrainz](https://musicbrainz.org/), adding `{{ musicBrainz.addedEntities.coverArt }}` pieces of cover art, `{{ musicBrainz.addedEntities.release }}` releases and `{{ musicBrainz.addedEntities.artist }}` artists which now exist in the database. Music is something deeply personal for me and it feels good to know that work I put into furthering information about the music I like is available in the public domain. Oftentimes these submissions are directly related to the artists and songs I listen to, of which I tracked `{{ listenBrainz.total }}` on [ListenBrainz](https://listenbrainz.org/). My listening history goes back to `{{ listenBrainz.firstYear }}`, and I have even created a Markov-Chain based playlist generation tool by exporting it to SQLite. Maybe I'll write about that some time. + +[OpenStreetMap](https://www.openstreetmap.org/) is one other place I regularly submit data to. I use different apps to navigate using OpenStreetMap data and to find my way around when I'm somewhere I don't know well. I have added `{{ openStreetMap.changesets.length }}` changes, many of which were locations of benches or water fountains — things I found useful when being outside. For this I mostly use [OsmAnd](https://osmand.net/) (`{{ openStreetMap.stats.doneInOsmand }}` times). It's an Android application that has very many toggles and switches for a map application. I have also completed `{{ openStreetMap.stats.doneInStreetComplete }}` quests in [StreetComplete](https://streetcomplete.app/), which prompts you with tasks to complete OpenStreetMap around you. It's very fun. Common topics are questions around wheelchair accessibility of certain places, lighting conditions, public transit or more generally outside amenities. + +I have in the past also used the tools provided by the [Humanitarian OpenStreetMap Team](https://www.hotosm.org/), which use OpenStreetMap data to support local humanitarian aid and disaster relief efforts, but only rarely. It's mind-boggling to think that people got together and started cataloging all of the physical stuff outside your window and _it actually works_, with all of the idiosyncrasies that the real world readily provides. The data in OpenStreetMap is incredibly rich, getting as fine grained as "what does the connection on the fire hydrant you find on this street corner look like", and all of it is available for third parties to do useful or silly stuff with.