Book Image Shortcode for Hugo

Lets link to bookshop

Published April 28, 2020 #howto #hugo

HappyFunCorp helped build Bookshop.org which is an online bookstore that distributes 30% of the book profits to independant bookstores in your area. Basically it’s a place that people can link to that isn’t Amazon, and that will kick some money to your local community.

I wanted to find a way to easily create links to these product pages, and show images if needed. There’s no API to access bookshop (I asked on our internal dev channel) but I know how to write a script so I cobbled something together and made a hugo shortcode to render stuff on my blog.

{{< bookshop isbn="9780394719856” />}}

Which will generate this, a embedded link to the product page of the book with the title pulled from the server:

The Gay Science: With a Prelude in Rhymes and an Appendix of Songs is a great book.

Or

{{< bookshop isbn="9780394719856" img="left">}}
Here are my thoughts about this book
{{< /bookshop >}}

The Gay Science: With a Prelude in Rhymes and an Appendix of Songs Here are my thoughts about this book.

We are going to use a two step process here. The first is to use a bash script to pull the data from the site and store it in json and jpg, and then a shortcode to format this in the webpage. Most of my posts are directories, so this will be part of the page bundles.

Get the book information

Since there’s no API and I want to keep this simple, our strategy is to:

  1. Hit the search page with the ISBN
  2. Use awk to pull put the link from the search results.
  3. Load the product page.
  4. Use an unholy combination of grep, sed, and awk to pull out the meta data.
  5. Store this in ${ISBN}.json
  6. Download the cover image in ${ISBN}.jpg

bookshop_lookup.sh:

#!/bin/bash

ISBN=$1

if [ -z "$ISBN" ]; then
    echo Usage $0 ISBN
    exit 1
fi

if [ ! -f "${ISBN}.json" ]; then
    WORKFILE=$(mktemp)

    if [ ! -f "${ISBN}_search.html" ]; then
        echo "Searching isdn from bookshop"
        wget -O ${ISBN}_search.html "https://bookshop.org/books?keywords=${ISBN}"
    fi

    if [ ! -f "${ISBN}_book.html" ]; then
        echo "Looking up book info from bookshop"
        URL=$(awk '/class="cover"/ { print $3 }' ${ISBN}_search.html | sed -E 's/href="([^"]*).*/\1/')
        
        if [ -z "${URL}" ]; then
            echo Unable to find product link in search results
            exit 2
        fi

        wget -O ${ISBN}_book.html https://bookshop.org${URL}
    fi

    grep meta ${ISBN}_book.html | awk 'BEGIN {RS="<meta "} // { print } ' > ${WORKFILE}

    IMG_URL=$(grep twitter:image\" ${WORKFILE} | sed -E 's/.*content=\"([^"]*).*/\1/')
    echo Image $IMG_URL
    DESCRIPTION=$(grep twitter:description ${WORKFILE} | sed -E 's/.*content=\"([^"]*).*/\1/')
    echo Desc $DESCRIPTION
    TITLE=$(grep og:title ${WORKFILE} | sed -E 's/.*content=\"([^"]*).*/\1/')
    echo Title $TITLE
    AUTHOR=$(awk '/\(Author\)/ {print}' ${ISBN}_book.html | sed -E 's/\s*<[^>]*>//g' | sed -E 's/<\/a.*//')
    echo Author $AUTHOR
    
    echo "{\"title\": \"${TITLE}\", \"url\": \"https://bookshop.org${URL}\", \"img\": \"${IMG_URL}\", \"author\": \"${AUTHOR}\"}" | jq -r '.' > ${ISBN}.json

    if [ -f ${WORKFILE} ]; then
        rm ${WORKFILE}
    fi
fi

if [ ! -f ${ISBN}.jpg ]; then
    wget -O ${ISBN}.jpg $(jq -r '.img' ${ISBN}.json)
fi

The shortcode

I’m not an expert in hugo shortcodes, but this is what we’re doing.

  1. Look for the file ${ISBN}.json in the page bundle.
  2. Show a message if we don’t find it.
  3. Pull in data into a map using $jsonFile.Content | unmarshal
  4. If we are showing the cover image, choose which set of bootstrap utility classes we want to use.
  5. Wrap the output in <p class="clearfix"> to deal with the overfloat. Can’t believe I’m still doing this.
  6. Link the image or the title to the bookshop product page, data pulled from the json file.
  7. Add the {{ .Inner }} content inside of the tag.

bookshop.html:

{{ $isbn := .Get "isbn" }}
{{ $isbnJson := printf "%s.json" $isbn }}
{{ $jsonResources := .Page.Resources.Match $isbnJson }}
{{ $jsonFile := index $jsonResources 0 }}
{{ $showImage := .Get "img" }}
{{ if $jsonFile }}
  {{ $data := $jsonFile.Content | unmarshal }}
  {{ $isbnImage := printf "%s.jpg" $isbn }}
  {{ $classes := "float-left mr-3" }}
  {{ if eq $showImage "right" }}{{ $classes = "float-right ml-3" }}{{ end }}
  {{ if $showImage }}<p class="clearfix">{{ end }}
  <a href="{{ $data.url }}">
    {{ $imgResources := .Page.Resources.Match $isbnImage }}
    {{ $image := index $imgResources 0 }}
    {{ if $showImage }}
    <img src="{{ $image.RelPermalink }}" class="{{ $classes }}" style="max-height: 200px" alt="{{$data.title}}">
    {{ else }}
    {{ $title := .Get "title" }}
    {{ if $title }}{{ $title }}{{ else }}{{ $data.title }}{{ end }}
    {{ end }}
  </a>

  {{ .Inner }}
{{ if $showImage }}</p>{{ end }}
{{ else }}
{{ if $showImage }}<p>{{ end }}
  <b>Run <code>bookshop_lookup.sh {{ $isbn }}</code> to load the meta data into {{$isbn}}.json</b>
  {{ .Inner }}
{{ if $showImage }}</p>{{ end }}
{{ end }}

Example output:

Chuang Tzu: Basic Writings (Revised) Dui, id ornare arcu odio ut sem nulla pharetra diam sit amet nisl suscipit adipiscing bibendum est ultricies integer quis auctor! Odio eu feugiat pretium, nibh ipsum consequat nisl, vel. Ac tortor dignissim convallis? Tincidunt nunc pulvinar sapien et ligula ullamcorper? Egestas diam in arcu cursus euismod quis viverra nibh cras pulvinar mattis nunc, sed blandit libero volutpat sed cras ornare arcu dui vivamus?

References

  1. https://shindakun.dev/posts/adding-a-book-cover-shortcode-for-hugo/

Read next

Next Post: Playing with deno
Previous Post: Styling tables with Hugo

See also

Styling tables with Hugo

Markdown sometimes isn’t enough

Markdown is a nice format to write it, but sometimes you need to add HTML classes directly to the output to make it look how you want. Here’s a way to do that using hugo shortcodes. Create a table shortcode Put this in /layouts/shortcodes/table.html: {{ $htmlTable := .Inner | markdownify }} {{ $class := .Get 0 }} {{ $old := "<table>" }} {{ $new := printf "<table class=\"%s\">" $class }} {{ $htmlTable := replace $htmlTable $old $new }} {{ $htmlTable | safeHTML }} Create a table Like this:

Read more

Styling Hugo Diffs

Showing just what you changed

I often want to show small changes I’m making to a file and it would be nice for hugo to support styling patches directly. Lets see what we can do to make this process easier. Lets take the example of create node package.json file and add the following scripts worflow. How can we say this different than “copy this into your package.json file”? Create sample steps Lets first create the file using npm init -y and then immediately cp package.

Read more

Splitting Git Repos and Work Directories

all the fun things git can do

I found a tutorial on how to manage your dotfiles, that works by splitting up the git repository (normally the .git directory) from the work directory. Since I have a lot of code that I put in my tutorials, I adapted the technique to have individual article directories mirrored in their own github repository. Repositories and Work Directories The normal usage of git is to type git clone <remote> to get a copy of the local directory, mess with stuff, and then add and commit your changes.

Read more