From b99f7d2c2cca62638ee1755854b3a2958f1415cc Mon Sep 17 00:00:00 2001 From: a Date: Sat, 23 Nov 2024 19:09:04 -0600 Subject: [PATCH] WIP: Add content adapter and basic user profile layout --- .gitignore | 1 + README.md | 1 + content/mastodon-archive/_content.gotmpl | 166 +++++++++++++ .../mastodon-live-activitypub/_content.gotmpl | 72 ++++++ hugo.toml | 7 + layouts/mastodon/baseof.html | 15 ++ layouts/mastodon/status.html | 38 +++ layouts/mastodon/statuses.html | 28 +++ layouts/mastodon/user.html | 226 ++++++++++++++++++ layouts/partials/mastodon/status.html | 18 ++ 10 files changed, 572 insertions(+) create mode 100644 README.md create mode 100644 content/mastodon-archive/_content.gotmpl create mode 100644 content/mastodon-live-activitypub/_content.gotmpl create mode 100644 hugo.toml create mode 100644 layouts/mastodon/baseof.html create mode 100644 layouts/mastodon/status.html create mode 100644 layouts/mastodon/statuses.html create mode 100644 layouts/mastodon/user.html create mode 100644 layouts/partials/mastodon/status.html diff --git a/.gitignore b/.gitignore index d816e73..ad5742a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.hugo_build.lock assets/mastodon-archive/*.json assets/mastodon-archive/avatar.* assets/mastodon-archive/header.* diff --git a/README.md b/README.md new file mode 100644 index 0000000..410193f --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# hugo-content-adapter-mastodon \ No newline at end of file diff --git a/content/mastodon-archive/_content.gotmpl b/content/mastodon-archive/_content.gotmpl new file mode 100644 index 0000000..8ca5afc --- /dev/null +++ b/content/mastodon-archive/_content.gotmpl @@ -0,0 +1,166 @@ +{{ with resources.GetMatch "mastodon-archive/avatar.*" }} + + {{ $avatar_content := dict "mediaType" .MediaType.Type "value" .Content }} + {{ $avatar_resource := dict + "path" (printf "avatar.%s" (index .MediaType.Suffixes 0)) + "content" $avatar_content + }} + {{ $.AddResource $avatar_resource }} + +{{ end }} + +{{ with resources.GetMatch "mastodon-archive/header.*" }} + + {{ $header_content := dict "mediaType" .MediaType.Type "value" .Content }} + {{ $header_resource := dict + "path" (printf "header.%s" (index .MediaType.Suffixes 0)) + "content" $header_content + }} + {{ $.AddResource $header_resource }} + +{{ end }} + +{{ with unmarshal (resources.Get "mastodon-archive/actor.json") }} + + {{ $account_page := dict + "path" "." + "kind" "section" + "title" .name + "summary" (.summary | plainify) + "content" (dict + "mediaType" "text/html" + "value" "" + ) + "type" "mastodon" + "layout" "user" + "params" (dict + "mastodon" (dict + "_model" "Account" + "username" .preferredUsername + "created_at" (.published | time) + "note" .summary + "display_name" .name + ) + ) + }} + {{ $.AddPage $account_page }} + +{{ end }} + +{{ with unmarshal (resources.Get "mastodon-archive/outbox.json") }} + + {{ $total := .totalItems }} + {{ $activities := last 1000 .orderedItems }} + + {{ range $activities }} + + {{ $published := .published | time }} + + {{/* Extract database ID to use as a path later */}} + {{ $status_id := + .id + | strings.TrimPrefix .actor + | strings.TrimPrefix "/statuses/" + | strings.TrimSuffix "/activity" + }} + + {{/* Calculate Mastodon-style visibility scope */}} + {{ $followers := printf "%s/followers" .actor }} + {{ $visibility := "direct" }} + {{ if or + (in .to "https://www.w3.org/ns/activitystreams#Public") + (in .to "as:Public") + (in .to "Public") + }} + {{ $visibility = "public" }} + {{ else if or + (in .cc "https://www.w3.org/ns/activitystreams#Public") + (in .cc "as:Public") + (in .cc "Public") + }} + {{ $visibility = "unlisted" }} + {{ else if or + (in .to $followers) + (in .cc $followers) + }} + {{ $visibility = "private" }} + {{ end }} + + {{/* Convert Create activities into a status */}} + {{ if eq .type "Create" }} + + {{/* Initialize Hugo Page and add it */}} + {{ $page := dict + "path" $status_id + "content" (dict + "mediaType" "text/html" + "value" .object.content + ) + "dates" (dict + "date" $published + ) + "type" "mastodon" + "layout" "status" + "params" (dict + "mastodon" (dict + "_model" "Status" + "_post_type" "original" + "id" $status_id + "visibility" $visibility + "spoiler_text" .object.summary + ) + ) + }} + {{ $.AddPage $page }} + + {{ else if eq .type "Announce" }} + + {{ $page := dict + "path" $status_id + "dates" (dict + "date" $published + ) + "type" "mastodon" + "layout" "status" + "params" (dict + "mastodon" (dict + "_model" "Status" + "_post_type" "reblog" + "_reblog_of_uri" .object + ) + ) + }} + {{ $.AddPage $page }} + + {{ else }} + + {{ $page := dict + "path" $status_id + "dates" (dict + "date" $published + ) + "params" (dict + "mastodon" (dict + "_model" "" + "_post_type" "unknown" + ) + ) + }} + {{ $.AddPage $page }} + + {{ end }} + + {{/* Add the activity as a resource */}} + + {{ $resource := dict + "path" (printf "%s/activity" $status_id) + "content" (dict + "mediaType" "application/json" + "value" (jsonify .) + ) + }} + {{ $.AddResource $resource }} + + {{ end }} + +{{ end }} \ No newline at end of file diff --git a/content/mastodon-live-activitypub/_content.gotmpl b/content/mastodon-live-activitypub/_content.gotmpl new file mode 100644 index 0000000..a98f7b9 --- /dev/null +++ b/content/mastodon-live-activitypub/_content.gotmpl @@ -0,0 +1,72 @@ +{{ $actor_data := dict }} +{{ $actor_url := "https://mastodon.social/users/trwnh.json" }} +{{ with resources.GetRemote $actor_url }} + {{ with .Err }} + {{ errorf "Unable to get remote resource %s: %s" $actor_url . }} + {{ else }} + {{ $actor_data = . | unmarshal }} + {{ end }} +{{ else }} + {{ errorf "Unable to get remote resource %s" $actor_url }} +{{ end }} + +{{ with $actor_data }} + + {{ $username := .preferredUsername }} + + {{/* Fetch and save avatar */}} + {{ $avatar_url := .icon.url }} + {{ with resources.GetRemote $avatar_url }} + {{ with .Err }} + {{ warnf "Unable to get avatar from %s with error: %s" $avatar_url . }} + {{ else }} + {{ $avatar_content := dict "mediaType" .MediaType.Type "value" .Content }} + {{ $avatar_resource := dict + "path" (printf "avatar.%s" (index .MediaType.Suffixes 0)) + "content" $avatar_content + }} + {{ $.AddResource $avatar_resource }} + {{ end }} + {{ end }} + + {{/* Fetch and save header */}} + {{ $header_url := .image.url }} + {{ with resources.GetRemote $header_url }} + {{ with .Err }} + {{ warnf "Unable to get header from %s with error: %s" $avatar_url . }} + {{ else }} + {{ $header_content := dict "mediaType" .MediaType.Type "value" .Content }} + {{ $header_resource := dict + "path" (printf "header.%s" (index .MediaType.Suffixes 0)) + "content" $header_content + }} + {{ $.AddResource $header_resource }} + {{ end }} + {{ end }} + + {{/* Add account page */}} + {{ $account_page := dict + "path" "." + "kind" "section" + "title" .name + "summary" (.summary | plainify) + "content" (dict + "mediaType" "text/html" + "value" "" + ) + "type" "mastodon" + "layout" "user" + "params" (dict + "mastodon" (dict + "_model" "Account" + "username" .preferredUsername + "created_at" (.published | time) + "note" .summary + "display_name" .name + + ) + ) + }} + {{ $.AddPage $account_page }} + +{{ end }} \ No newline at end of file diff --git a/hugo.toml b/hugo.toml new file mode 100644 index 0000000..56e4dc4 --- /dev/null +++ b/hugo.toml @@ -0,0 +1,7 @@ +baseURL = 'https://example.org/' +languageCode = 'en-us' +title = 'My New Hugo Site' + +[caches.getresource] +dir = ':resourceDir/_cache/:project' +maxage = -1 \ No newline at end of file diff --git a/layouts/mastodon/baseof.html b/layouts/mastodon/baseof.html new file mode 100644 index 0000000..7349dcc --- /dev/null +++ b/layouts/mastodon/baseof.html @@ -0,0 +1,15 @@ + + + + + + {{.Title}} + {{ block "head" . }} + {{ end }} + +{{ block "body" . }} + + + +{{ end }} + \ No newline at end of file diff --git a/layouts/mastodon/status.html b/layouts/mastodon/status.html new file mode 100644 index 0000000..0161bdd --- /dev/null +++ b/layouts/mastodon/status.html @@ -0,0 +1,38 @@ +{{ define "head" }} + +{{ end }} + +{{ define "body" }} + +
+

Mastodon/Status view

+ +

Status

+ + {{ with .Params.mastodon.spoiler_text }} +

{{.}}

+ {{ end }} + + {{ with .Content }} +
{{.}}
+ {{ end }} + +

Status params

+ +
+ {{ range $k, $v := .Params.mastodon }} +
{{$k}}
+
{{$v}}
+ {{ end }} +
+ +

Activity

+ {{ with .Resources.Get "activity" }} +
{{.Content | unmarshal | jsonify (dict "indent" "  ") }}
+ {{ end }} + +
+ +{{ end }} \ No newline at end of file diff --git a/layouts/mastodon/statuses.html b/layouts/mastodon/statuses.html new file mode 100644 index 0000000..6ae68ab --- /dev/null +++ b/layouts/mastodon/statuses.html @@ -0,0 +1,28 @@ +{{ define "head" }} + +{{ end }} + +{{ define "body" }} + +
+

Mastodon/Statuses view

+ +
+ +{{ end }} \ No newline at end of file diff --git a/layouts/mastodon/user.html b/layouts/mastodon/user.html new file mode 100644 index 0000000..0bb8c06 --- /dev/null +++ b/layouts/mastodon/user.html @@ -0,0 +1,226 @@ +{{ define "head" }} + +{{ end }} + +{{ define "body" }} + +
+

Mastodon/User view

+ +
+

Statuses

+ {{ with where .RegularPages "Params.mastodon.visibility" "public" }} +
    + {{ range . }} +
  • + {{ partial "mastodon/status.html" (dict "status_ctx" . "account_ctx" $) }} +
  • + {{ end }} +
+ {{ else }} +

No statuses

+ {{ end }} +
+
+ +{{ end }} \ No newline at end of file diff --git a/layouts/partials/mastodon/status.html b/layouts/partials/mastodon/status.html new file mode 100644 index 0000000..7fb188d --- /dev/null +++ b/layouts/partials/mastodon/status.html @@ -0,0 +1,18 @@ +{{ $status := .status_ctx }} +{{ $account := .account_ctx }} +{{ $avatar := $account.Resources.GetMatch "avatar.*" }} +
+
+ +

{{ $account.Params.mastodon.display_name }}

+

+
+
+ {{ with $status.Params.mastodon.spoiler_text }} +

{{ . }}

+ {{ end }} +
+
+ {{ $status.Content }} +
+
\ No newline at end of file