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)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Worth mentioning that
got
is now a pure ES6 package and will throw errors if you use got@latest. You probably want to do: