Skip to content

Instantly share code, notes, and snippets.

@nocodesupplyco
Last active February 14, 2024 14:46
Show Gist options
  • Save nocodesupplyco/319a7db6866f7f3251a01dc8712c6482 to your computer and use it in GitHub Desktop.
Save nocodesupplyco/319a7db6866f7f3251a01dc8712c6482 to your computer and use it in GitHub Desktop.
Optimize Images w/ Airtable Script
// Define settings fields and descriptions
const config = input.config({
title: "Compress Images",
description: "Check and compress an image in each record of a view using the [Kraken.io API](https://kraken.io/docs/getting-started). Script created by [Base Scripts](https://nocodesupply.co/basescripts) — use at your own discretion.",
items: [
input.config.text("krakenAPIKey", {
label: "Kraken API Key",
description: "Sign up for a Kraken account, and get your key from the Account > API Credentials page.",
}),
input.config.text("krakenAPISecret", {
label: "Kraken API Secret",
description: "Sign up for a Kraken account, and get your secret from the Account > API Credentials page.",
}),
input.config.text("minImageSize", {
label: "Minimum Image Size (kb)",
description: "When an image is checked, if its current file size is above this value then it will get compressed, if its below it will remain as is.",
}),
input.config.text("imageResizeWidth", {
label: "Resize Image Width",
description: "When an image is compressed, what is the width it should be resized too?",
}),
input.config.select("imageOrientation", {
label: "Rezied Image Orientation",
description: "When the image is compressed, what orientation should it retain?",
options: [
{ label: "Landscape", value: "landscape" },
{ label: "Portrait", value: "portrait" },
],
}),
input.config.select("convertWebp", {
label: "Convert Image to WebP?",
description: "When the image is compressed, do you want it also converted to a Webp file type?",
options: [
{ label: "True", value: "true" },
{ label: "False", value: "false" },
],
}),
input.config.table("tableSelect", {
label: "Table",
description: "Select the table where the images should be checked and compressed.",
}),
input.config.view("viewSelect", {
label: "View",
description: "Select the view where the images should be checked and compressed.",
parentTable: "tableSelect",
}),
input.config.field("imageSelect", {
label: "Image Field",
description: "Select the attachment field where the image to check and compress is currently stored.",
parentTable: "tableSelect",
}),
input.config.field("imageSizeSelect", {
label: "Image Size Field",
description: "Select the text field where the size of the image should be output.",
parentTable: "tableSelect",
}),
input.config.field("imageTypeSelect", {
label: "Image Type Field",
description: "Select the text field where the file type of the image should be output.",
parentTable: "tableSelect",
}),
input.config.field("imageErrorSelect", {
label: "Image Error Field",
description: "Select the checkbox field that gets checked if there is any error when trying to compress the image.",
parentTable: "tableSelect",
}),
],
});
// Set config choices to variables
const configAPIKey = config.krakenAPIKey;
const configAPISecret = config.krakenAPISecret;
const configMinSize = parseInt(config.minImageSize, 10); // Convert to number
const configImageResize = parseInt(config.imageResizeWidth, 10); // Convert to number
const configImageOrientation = config.imageOrientation;
const configConvertWebp = config.convertWebp === "true"; // Convert string to boolean
const configTable = config.tableSelect.name;
const configView = config.viewSelect.name;
const configImage = config["imageSelect"].name;
const configImageSize = config["imageSizeSelect"].name;
const configImageType = config["imageTypeSelect"].name;
const configImageError = config["imageErrorSelect"].name;
// Set table and view
const table = base.getTable(configTable);
const view = table.getView(configView);
// Loop through each image field to get size
let query = await view.selectRecordsAsync({ fields: [configImage, "Name"] });
for (let record of query.records) {
// Get image size
let imageSize = record.getCellValue(configImage)[0].size / 1000;
// Get image URL
let imageToResizeUrl = record.getCellValue(configImage)[0].url;
// Get image type
let imageType = record.getCellValue(configImage)[0].type;
// Get record name
let imageRecordName = record.getCellValue("Name");
if (imageSize >= configMinSize) {
// IF image size is over minimum size set then compress the image via API
let callToKraken = await remoteFetchAsync("https://api.kraken.io/v1/url", {
method: "POST",
body: JSON.stringify({
auth: {
api_key: configAPIKey,
api_secret: configAPISecret,
},
// "dev": true,
url: imageToResizeUrl,
wait: true,
lossy: true,
webp: configConvertWebp,
resize: [
{
id: "compressed",
strategy: configImageOrientation,
width: configImageResize,
},
],
}),
headers: {
"Content-type": "application/json",
Accept: "application/json",
},
});
let returnedImages = await callToKraken.json();
if (!callToKraken.ok) {
// IF Kraken throws an error message, then continue to compress the next image
console.error(callToKraken);
await table.updateRecordAsync(record, {
[configImageError]: true,
});
continue;
} else {
// IF successful update image and size fields
await table.updateRecordAsync(record, {
[configImage]: [{ url: returnedImages.results.compressed.kraked_url }],
[configImageSize]: returnedImages.results.compressed.kraked_size / 1000,
[configImageType]: "image/webp",
});
console.log("Compressed image to " + returnedImages.results.compressed.kraked_size / 1000 + "KB (" + imageRecordName + ")");
}
} else {
//IF image size that is under the minimum size set then just update image size field
await table.updateRecordAsync(record, {
[configImageSize]: imageSize,
[configImageType]: imageType,
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment