Skip to content

Instantly share code, notes, and snippets.

@rsms
Created November 18, 2019 23:33
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save rsms/358cf71df065c825c6dea7617cdec082 to your computer and use it in GitHub Desktop.
Script to fetch thumbnails of figma files
// 1. Make sure you have imagemagick installed (`brew install imagemagick` on macos)
// 2. Visit https://www.figma.com/developers/api#authentication and click "Get personal access token"
// 3. Add your file links below, replacing the example links
// 4. Run with `FIGMA_API_TOKEN=YOUR_TOKEN_FROM_STEP_2_HERE node fig-thumbnails.js`
// [ host:string, filekey:string ][]
const fileKeys = `
https://www.figma.com/file/FILEKEY/
https://staging.figma.com/file/FILEKEY/
https://www.figma.com/file/FILEKEY/
https://staging.figma.com/file/FILEKEY/
https://www.figma.com/file/FILEKEY/
https://staging.figma.com/file/FILEKEY/
`.replace(/\s*https:\/\/([^\/]+)\/file\/([A-Za-z0-9]+).*\n/mg, "$1 $2\n").trim()
.split("\n").map(s => s.split(" "))
.map(([host, filekey]) => [
host.indexOf("staging") != -1 ? "staging-api.figma.com" : "api.figma.com",
filekey,
])
const https = require("https")
const fs = require("fs")
const child_process = require("child_process")
const API_TOKEN = process.env["FIGMA_API_TOKEN"]
if (!API_TOKEN) {
console.error(`FIGMA_API_TOKEN not set in env`)
process.exit(1)
}
function fetchInfo(host, filekey) {
let path = `/v1/files/${filekey}?depth=1`
console.log(`HTTP GET https://${host}${path}`)
return new Promise((resolve, reject) => {
https.get({
host,
path,
headers: {
"X-FIGMA-TOKEN": API_TOKEN,
},
}, (res) => {
if (res.statusCode < 200 || res.statusCode >= 300) {
console.error(`GET ${host}${path}`)
console.error('response HTTP', res.statusCode)
console.error('headers', res.headers)
res.on('data', ()=>{})
res.on('end', () => { reject(new Error(`HTTP ${res.statusCode}`)) })
} else {
res.setEncoding("utf8")
let body = ""
res.on('data', s => { body += s })
res.on('end', () => {
// async branch with concurren file fetch
handleFileData(filekey, JSON.parse(body))
resolve()
// sync pipeline with file fetch
// resolve(handleFileData(filekey, JSON.parse(body)))
})
}
}).on('error', reject)
})
}
function fetchFile(url, file) {
console.log(`HTTP GET ${url.substr(0, 20)}... -> ${file}`)
return new Promise((resolve, reject) => {
https.get(url, {
headers: {
"X-FIGMA-TOKEN": API_TOKEN,
},
}, res => {
if (res.statusCode < 200 || res.statusCode >= 300) {
console.error(`GET ${url}`)
console.error('response HTTP', res.statusCode)
console.error('headers', res.headers)
res.on('data', ()=>{})
res.on('end', () => { reject(new Error(`HTTP ${res.statusCode}`)) })
} else {
const ws = fs.createWriteStream(file)
res.pipe(ws)
let refs = 2
let maybeEnd = () => {
if (--refs == 0) {
ws.close()
resolve()
}
}
ws.on('close', maybeEnd)
res.on('end', maybeEnd)
}
}).on('error', reject)
})
}
function handleFileData(filekey, f) {
let slug = f.name.replace(/[^a-zA-Z0-9_\-\.]+/g, "-")
let file = `fig-thumbnails/${filekey}-${slug}.png`
return fetchFile(f.thumbnailUrl, file)
.then(() => postProcessThumbnail(file, f))
}
async function postProcessThumbnail(file, f) {
let bgcolorf = f.document.children[0].backgroundColor
let r = (bgcolorf.r * 255).toFixed(0)
let g = (bgcolorf.g * 255).toFixed(0)
let b = (bgcolorf.b * 255).toFixed(0)
// convert YBy1QZD6kHYjS9J8B3BRFekn-Notifications-1.1.png -bordercolor "rgba(255,0,100)" -border 50 out2.png
let args = [
file,
"-bordercolor", `rgb(${r},${g},${b})`,
"-border", "50",
file,
]
try {
let output = child_process.execFileSync("convert", args, {
cwd: __dirname,
encoding: "utf8",
})
if (output.trim()) {
console.error("convert: " + output)
}
} catch (err) {
console.error("[IM error]", String(err))
}
}
async function main() {
// console.log(fileKeys)
try { fs.mkdirSync("fig-thumbnails") } catch(_) {}
for (let [ host, filekey ] of fileKeys) {
await fetchInfo(host, filekey)
}
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment