HappyFunCorp helped build Bookshop.org which is an online bookstore that distributes 30% of the book profits to independent 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 >}}
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:
- Hit the search page with the ISBN
- Use
awk
to pull put the link from the search results. - Load the product page.
- Use an unholy combination of grep, sed, and awk to pull out the meta data.
- Store this in
${ISBN}.json
- Download the cover image in
${ISBN}.jpg
#!/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.
- Look for the file
${ISBN}.json
in the page bundle. - Show a message if we don’t find it.
- Pull in data into a map using
$jsonFile.Content | unmarshal
- If we are showing the cover image, choose which set of bootstrap utility classes we want to use.
- Wrap the output in
<p class="clearfix">
to deal with the overfloat. Can’t believe I’m still doing this. - Link the image or the title to the bookshop product page, data pulled from the json file.
- 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:
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?