M .gitignore => .gitignore +7 -0
@@ 5,6 5,9 @@ public/
# script-generated files
static/files/dominic-ricottone.html
static/files/dominic-ricottone.pdf
+layouts/partials/bsky.html
+layouts/partials/lastfm.html
+layouts/partials/openring.html
# (la|odf)?tex compilation artifacts
**/*.aux
@@ 13,3 16,7 @@ static/files/dominic-ricottone.pdf
**/*.pdf
**/*.tex
+# API keys
+bsky-passwd
+lastfm-passwd
+
M Makefile => Makefile +15 -3
@@ 19,12 19,24 @@ static/files/dominic-ricottone.html: content/cv.md
cat content/cv.md \
| scripts/cv_html.awk > static/files/dominic-ricottone.html
-.PHONY:
-dev: static/files/dominic-ricottone.pdf static/files/dominic-ricottone.html
+layouts/partials/bsky.html:
+ scripts/bsky.sh > layouts/partials/bsky.html
+
+layouts/partials/lastfm.html:
+ scripts/lastfm.sh > layouts/partials/lastfm.html
+
+layouts/partials/openring.html:
+ scripts/openring.sh > layouts/partials/openring.html
+
+PREGEN_HTML=static/files/dominic-ricottone.pdf static/files/dominic-ricottone.html layouts/partials/bsky.html layouts/partials/lastfm.html layouts/partials/openring.html
+.PHONY: $(PREGEN_HTML)
+
+.PHONY: dev
+dev: $(PREGEN_HTML)
hugo server --buildDrafts --bind 127.0.0.1 --port 8080
.PHONY: build
-build: clean static/files/dominic-ricottone.pdf static/files/dominic-ricottone.html
+build: clean $(PREGEN_HTML)
hugo
.PHONY: check
M layouts/index.html => layouts/index.html +26 -2
@@ 4,10 4,10 @@
<h1>{{ .Title }}</h1>
{{ .Content }}
-
- <hr />
</div>
+<hr class="content-width" />
+
<div id="blog-content">
<p>These are my three most recent blog posts. More posts can be found on the 'Blog' tab.<p>
@@ 27,5 27,29 @@
</ul>
</div>
+<hr class="content-width" />
+
+<div id="bsky-content">
+ <p>I occasionally post on <a href="https://bsky.app/profile/dricottone.bsky.social">Bluesky</a>, mostly about concerts and music.</p>
+
+ {{ partial "bsky.html" . }}
+</div>
+
+<hr class="content-width" />
+
+<div id="lastfm-content">
+ <p>Here's my most listened to music from the last 30 days. See more on <a href="https://www.last.fm/user/al__dente">LastFM</a></p>
+
+ {{ partial "lastfm.html" . }}
+</div>
+
+<hr class="content-width" />
+
+<div id="openring-content">
+ <p>Articles from the internet that I've been reading</p>
+
+ {{ partial "openring.html" . }}
+</div>
+
{{ end }}
M layouts/posts/single.html => layouts/posts/single.html +7 -0
@@ 24,5 24,12 @@
{{ end }}
</div>
+ <hr class="content-width" />
+
+ <div id="openring-content">
+ <p>Articles from the internet that I've been reading</p>
+
+ {{ partial "openring.html" . }}
+ </div>
</div>
{{ end }}
A scripts/bsky.sh => scripts/bsky.sh +31 -0
@@ 0,0 1,31 @@
+#!/bin/sh
+
+API_PASSWD="$(cat bsky-passwd)"
+
+DID_HANDLE='handle=dricottone.bsky.social'
+DID_URI='https://bsky.social/xrpc/com.atproto.identity.resolveHandle'
+DID="$(curl --get --no-progress-meter --data-urlencode "$DID_HANDLE" "$DID_URI" | jq --raw-output .did)"
+
+APIKEY_URI='https://bsky.social/xrpc/com.atproto.server.createSession'
+APIKEY_HEADER='Content-Type: application/json'
+APIKEY_DATA="{ \"identifier\": \"$DID\", \"password\": \"$API_PASSWD\" }"
+APIKEY="$(curl -X POST --no-progress-meter --header "$APIKEY_HEADER" --data "$APIKEY_DATA" "$APIKEY_URI" | jq --raw-output .accessJwt)"
+
+FEED_URI='https://bsky.social/xrpc/app.bsky.feed.getAuthorFeed'
+FEED_HEADER="Authorization: Bearer $APIKEY"
+FEED_ACTOR="actor=$DID"
+FEED_LIMIT='limit=3'
+FEED="$(curl --get --no-progress-meter --header "$FEED_HEADER" --data-urlencode "$FEED_ACTOR" --data-urlencode "$FEED_LIMIT" "$FEED_URI" | jq --raw-output .feed)"
+
+echo "<ul>"
+echo " <li>"
+echo "${FEED}" | jq --raw-output '.[0].post.record.text' | sed -e 's/.*/ <p>&<\/p>/'
+echo " </li>"
+echo " <li>"
+echo "${FEED}" | jq --raw-output '.[1].post.record.text' | sed -e 's/.*/ <p>&<\/p>/'
+echo " </li>"
+echo " <li>"
+echo "${FEED}" | jq --raw-output '.[2].post.record.text' | sed -e 's/.*/ <p>&<\/p>/'
+echo " </li>"
+echo "</ul>"
+
A scripts/lastfm.sh => scripts/lastfm.sh +16 -0
@@ 0,0 1,16 @@
+#!/bin/sh
+
+PASSWD="$(cat lastfm-passwd)"
+
+USER="al__dente"
+URI="https://ws.audioscrobbler.com/2.0/?method=user.gettoptracks&user=${USER}&api_key=${PASSWD}&format=json&period=1month&limit=5"
+FEED="$(curl --get --no-progress-meter "$URI" | jq --raw-output '[.toptracks.track[] | {track: .name, artist: .artist.name}]')"
+
+echo "<ol>"
+echo "${FEED}" | jq --raw-output '.[0] | " <li>\(.track) by \(.artist)</li>"'
+echo "${FEED}" | jq --raw-output '.[1] | " <li>\(.track) by \(.artist)</li>"'
+echo "${FEED}" | jq --raw-output '.[2] | " <li>\(.track) by \(.artist)</li>"'
+echo "${FEED}" | jq --raw-output '.[3] | " <li>\(.track) by \(.artist)</li>"'
+echo "${FEED}" | jq --raw-output '.[4] | " <li>\(.track) by \(.artist)</li>"'
+echo "</ol>"
+
A scripts/openring.html => scripts/openring.html +14 -0
@@ 0,0 1,14 @@
+<div>
+ <ul>
+ {{range .Articles}}
+ <li>
+ <p><a href="{{.Link}}">{{.Title}}</a></p>
+ <p>{{.Summary}}</p>
+ <p>via <a href="{{.SourceLink}}">{{.SourceTitle}}</a></p>
+ <p>{{.Date | datef "January 2, 2006"}}</p>
+ </li>
+ {{end}}
+ </ul>
+ <p>Generated by <a href="https://git.sr.ht/~sircmpwn/openring">openring</a></p>
+</div>
+
A scripts/openring.sh => scripts/openring.sh +15 -0
@@ 0,0 1,15 @@
+#!/bin/sh
+
+openring \
+ -s https://drewdevault.com/feed.xml \
+ -s https://emersion.fr/blog/rss.xml \
+ -s https://gregoryszorc.com/blog/feed/ \
+ -s https://words.filippo.io/rss/ \
+ -s https://www.supergoodcode.com/feed.xml \
+ -s https://bitfehler.srht.site/index.xml \
+ -s https://research.swtch.com/feed.atom \
+ -s https://andrewkelley.me/rss.xml \
+ -s https://christianbrickhouse.com/feed.xml \
+ -s https://andreabergia.com/post/index.xml \
+ < scripts/openring.html
+
M static/css/blog.css => static/css/blog.css +80 -0
@@ 4,6 4,86 @@ div#blog-content {
padding: 0 0 0 10px;
}
+div#bsky-content {
+ margin: 0;
+ max-width: 800px;
+ padding: 0 0 0 10px;
+}
+
+div#bsky-content ul {
+ margin: 0 10px 0 30px;
+}
+
+div#bsky-content li {
+ position: relative;
+ margin: 0.5em 0;
+ padding: 0.5em;
+ border-radius: 1.25em;
+ list-style: none;
+ background-color: #bbffbb;
+}
+
+div#bsky-content li::before {
+ position: absolute;
+ width: 0;
+ height: 0;
+ content: '';
+ bottom: -0.75em;
+ left: -0.75em;
+ transform: rotate(90deg);
+ border-top: 1.5em solid transparent;
+ border-bottom: 1.5em solid transparent;
+ border-right: 1.5em solid #bbffbb;
+}
+
+div#openring-content {
+ margin: 0;
+ max-width: 800px;
+ padding: 0.5em;
+}
+
+div#openring-content div {
+ margin: 1em;
+ border-radius: 1.25em;
+ background-color: #bbffff;
+}
+
+
+div#openring-content div > p {
+ margin: 0 0 1em 1em;
+ line-height: 1.5em;
+ color: #777;
+ font-style: italic;
+}
+
+div#openring-content div > p a {
+ color: #777;
+}
+
+div#openring-content ul {
+ margin: 0;
+ padding: 0.25em 0 0.25em 0;
+ list-style: none;
+}
+
+div#openring-content li {
+ margin: 0.5em;
+ padding: 0.5em;
+ border-radius: 1.25em;
+ background-color: #fff;
+}
+
+div#lastfm-content {
+ margin: 0;
+ max-width: 800px;
+ padding: 0 0 0 10px;
+}
+
+hr.content-width {
+ max-width: 800px;
+ padding-left: 10px;
+}
+
ul#blog-list {
margin: 0;
padding: 0;