Making the library.json file more useful
I’ve had something sitting on the todo list for a long time: make the library.json file that bookshelves.dev a bit better by providing a full image path to the locally cached cover image for each book, as opposed to just dumping the source url for the image.
The site’s library.json output is generated by a nunjucks template page, which loops through all the books identified on the site and displays each one using the “book” shortcode, which can take an ISBN and optionally a layout. Here, we pass the JSON layout.
---
permalink: '/library.json'
---
{
"name": "{{ site.title }}",
"url": "{{ site.url }}",
"bio": "{{ site.description }}",
"lists": [
{%- for item in booksOnShelves.shelves %}
{
"title": "{{ item.shelfTitle }}",
"shelfID": "{{ item.shelfID }}",
"url": "{{ site.url }}/{{ item.shelfID }}",
"books": [
{%- for ISBN in item.shelfItems %}
{
{% book ISBN, 'json' %}
}{% if not loop.last %},{% endif %}
{%- endfor %}
]
}{% if not loop.last %},{% endif %}
{%- endfor %}
]
}
That book shortcode script passes some details to the layout to, and what it was passing was the path to the source of the image. This could be a local image or (more likely) a URL to an image on Amazon, identified by the build script using the ISBN. But on the site we don’t just use that URL, we use the image plugin to fetch, cache and create responsive markup for that image. That image plugin code is in a different script, so I modified that to return not just that resource, but also the path to the cached image.
const html = `<picture>
${Object.values(metadata)
.map((imageFormat) => {
return ` <source type="${
imageFormat[0].sourceType
}" srcset="${imageFormat
.map((entry) => entry.srcset)
.join(", ")}" sizes="${sizes}">`;
})
.join("\n")}
<img
src="${lowsrc.url}"
alt="${alt}"
class="${cls}"
loading="lazy"
decoding="async">
</picture>`;
return { html, highsrc, lowsrc };
After updating the cacheImage script, I updated all references to it. Now, when build the site, the library.json should have absolute paths to my cached resource, and not the scraped URL of the image I used.
Along the way I noticed that shareLibrary.njk was using the booksOnShelves.json directly, and not filtering out anything whose visibility is not set to “true”. I could have either filtered that in the nunjucks conditional on that generating page, or refactored it to use the booksOnShelf collection in eleventy, where the “hidden” books have already been filtered out. For now, I’ve done the former, which is easier. But I’m not sure where I would land if I thought about that a bit more deeply.
Anyway, this was satisfyingly straightforward. May it serve as a reminder that doing the less exciting items on the todo list can feel really good. Sometimes I only want to work on the daunting new epics and deny myself the pleasure of shipping even a small piece of code.