NA of Moles

Automating your Now page with Hugo

A week ago on Hacker News someone shared their setup for an automated /now page. Their idea was nice but I felt like they didn’t take full advantage of Hugo. This is how I reimplemented some of that functionality in an alternative way.

Fun fact: Hugo supports downloading JSON, CSV, XML, Images and is also capable of processing them at render time.

Movies

Like the original blog I also used letterboxd becuase it’s free. (Usually I use Trakt + Showly but it requires a subscription). We create a simple shortcode and then call it from the markdown.

markdown
1
{{< letterboxd >}}
go-html-template
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{{ $data := dict }}
{{ $url := "https://letterboxd.com/yourusername/rss/" }}
{{ with resources.GetRemote $url }}
  {{ with .Err }}
    {{ errorf "%s" . }}
  {{ else }}
    {{ $data = . | transform.Unmarshal }}
  {{ end }}
{{ else }}
  {{ errorf "Unable to get remote resource %q" $url }}
{{ end }}

{{ with $data.channel.item }}
  <ul class="consumed-list">
    {{ range first 3 . }}
        {{ $title := .filmTitle }}
        {{ $year := .filmYear }}
        {{ $posterUrl := index (findRE `(https://.+\.jpg)` .description ) 0 }}
      <li class="consumed-element">
        <a href="https://www.themoviedb.org/movie/{{ .movieId }}" >
        {{ with $thumbnail := resources.GetRemote $posterUrl }}
        {{ with .Err }}
            {{ warnf "%s" . }}
            <img src="$posterUrl" 
            width="100" 
            loading="lazy" 
            alt="Poster of {{ $title }}">
        {{ else }} 
            {{ $filter := images.Process "resize 100x q90 webp" }}
            {{ with . | images.Filter $filter }}
            <img src="{{ .RelPermalink }}" 
            width="{{ .Width }}" 
            height="{{ .Height }}" 
            alt="Poster Image of {{ $title }}" 
            loading="lazy">
            {{ end }}
        {{end}}
        {{end}}
        </a>
        <p><a href="https://www.themoviedb.org/movie/{{ .movieId }}" >{{ $title }}</a> ({{$year}})</p>
    </li>
    {{ end }}
  </ul>
{{ end }}


{{/*  <pre>{{ debug.Dump $data }}</pre>  */}}

This will automatically download and parse the RSS, download the posters from TMDB and optimize them.

Books

This time instead I used OpenLibrary because it has a slightly more complete collection.

markdown
1
2
{{< openlibrary "currently-reading" >}}
{{< openlibrary "already-read" >}}
go-html-template
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
{{ $type := (index .Params 0) }}
{{/*  types: already-read currently-reading want-to-read https://openlibrary.org/dev/docs/api/mybooks  */}}
{{ $data := dict }}
{{ $url := printf "https://openlibrary.org/people/mekBot/books/%s.json"  $type }}
{{ with resources.GetRemote $url }}
  {{ with .Err }}
    {{ errorf "%s" . }}
  {{ else }}
    {{ $data = . | transform.Unmarshal }}
  {{ end }}
{{ else }}
  {{ errorf "Unable to get remote resource %q" $url }}
{{ end }}

{{/*  {{ $data.reading_log_entries }}  */}}

{{ with $data.reading_log_entries }}
<ul class="consumed-list">
    {{ range first 3 . }}
      {{ $date := index . "logged_date" }}
      {{ $title := index . "work" "title" }}
      {{ $url := index . "work" "key" }}
      {{ $year := index . "work" "first_publish_year" }}
      {{ $cover :=  index . "work" "cover_id" | string}}
      {{ $thumbnailUrl := printf "https://covers.openlibrary.org/b/id/%s-L.jpg" $cover }}
      {{ $authors := index . "work" "author_names" }}
      <li class="consumed-element">
        <a href="https://openlibrary.org{{ $url }}">
        {{ with $thumbnail := resources.GetRemote $thumbnailUrl }}
        {{ with .Err }}
            {{ warnf "%s" . }}
            <img 
            src="https://covers.openlibrary.org/b/id/{{ string  $cover }}-S.jpg" 
            width="100" 
            loading="lazy" 
            alt="Cover Image of {{$title}}">
        {{ else }} 
            {{ $filter := images.Process "resize 100x q90 webp" }}
            {{ with . | images.Filter $filter }}
                <img src="{{ .RelPermalink }}" 
                width="{{ .Width }}" 
                height="{{ .Height }}" 
                alt="Cover Image of {{$title}}" 
                loading="lazy">
            {{ end }}
        {{end}}
        {{end}}
        </a>
        <div>
            <a href="https://openlibrary.org{{ $url }}">{{ $title }}</a> ({{$year}})
            <p>written by <em>{{ delimit $authors ", " " and "}}</em></p>
        </div> 
    </li>

    {{ end }}
  </ul>
{{ end }}

Like before, it downloads the file, parses the JSON, looks up the cover and embeddeds it into the page.

It has some quirks like: the JSON orders the entries based the logged date when it was added in your “general” collection and not when it was moved in a specific collection, so when you change a book from “reading” to “finished reading” it won’t be in the first entry.

Games and TV

I don’t play that many games tbh so I didn’t bother.

For TV, I’m sort of interested, also because it’s slightly more feasible than parsing the HTML in Hugo.

Final result

My now page is visible here.


Tags: