Created
November 18, 2019 23:33
Star
You must be signed in to star a gist
Script to fetch thumbnails of figma files
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
// 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