Last active
July 22, 2023 14:29
-
-
Save kmelve/8f1738397a3d29fc8639bda890eeb116 to your computer and use it in GitHub Desktop.
Retroactively add Blurhash strings to image assets in your Sanity Content Lake.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Retroactively add Blurhash strings to image assets in your Sanity Content Lake. | |
* 1. yarn add got sharp blurhash | |
* 2. run sanity exec blurhash --with-user-token | |
* 3. repeat (patches 100 assets in 1 transaction pr run) | |
* | |
* Some images might take a while to process. | |
*/ | |
import client from 'part:@sanity/base/client' | |
import got from 'got' | |
import sharp from 'sharp' | |
import { encode } from "blurhash"; | |
const versionedClient = client.withConfig({ apiVersion: '2021-10-22' }) | |
const BASE_COMPONENT = 5 | |
const loadImage = async src => { | |
try { | |
const response = await got(src, { responseType: 'buffer' }) | |
const arr = new Uint8Array(response.body) | |
return arr | |
} | |
catch (error) { | |
console.log(error) | |
return undefined | |
} | |
} | |
const encodeImageToBlurhash = async ({ url, metadata }) => { | |
const { dimensions } = metadata | |
const dimensionedUrl = url | |
const imageBuffer = await loadImage(dimensionedUrl); | |
const { data, info } = await sharp(imageBuffer).raw().ensureAlpha().toBuffer({ resolveWithObject: true }) | |
const { height, width } = info | |
let componentX = BASE_COMPONENT | |
let componentY = BASE_COMPONENT | |
if (width > height) { | |
componentY = Math.ceil(BASE_COMPONENT * (height / width)) | |
} else { | |
componentX = Math.ceil(BASE_COMPONENT * (width / height)) | |
} | |
try { | |
return encode(data, width, height, componentX, componentY); | |
} catch (err) { | |
console.error(err) | |
return undefined | |
} | |
}; | |
async function run() { | |
// Fetch assets without blurhash, 100 at a time | |
const assets = await versionedClient | |
.fetch(`*[_type == "sanity.imageAsset" && metadata.blurHash == null][0...100]`) | |
if (!assets.length) { | |
return 'No assets to blurhash' | |
} | |
const createTransaction = patches => | |
patches.reduce((tx, patch) => tx.patch(patch.id, patch.patch), versionedClient.transaction()) | |
// build transaction, one by one | |
let patches = [] | |
for (const asset of assets) { | |
const hash = await encodeImageToBlurhash(asset) | |
console.log(`Created hash for ${asset._id}: ${hash}`) | |
if (hash) { | |
patches = [...patches, { | |
id: asset._id, | |
patch: { | |
set: { | |
'metadata.blurHash': hash | |
} | |
} | |
}] | |
} | |
} | |
console.log(`Creating ${patches.length} transactions…`) | |
const transaction = createTransaction(patches) | |
const result = await transaction.commit() | |
return JSON.stringify(result, null, 2) | |
} | |
run().then(result => console.log(result)) |
Worth mentioning that got
is now a pure ES6 package and will throw errors if you use got@latest. You probably want to do:
yarn add [email protected] sharp blurhash
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thanks for this @kmelve, i got a linting error when running this because of a missing
const
in yourfor (asset of assets) {...}
should be
for (const asset of assets) {...}
also i was running a script with
sanity exec
for the first time so i found this article useful.After changing this it works like a charm! Thanks again for your great work!