Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save machiq/a7952a880e4fb4bcd041b63f8ee60a18 to your computer and use it in GitHub Desktop.
Save machiq/a7952a880e4fb4bcd041b63f8ee60a18 to your computer and use it in GitHub Desktop.
Frame.io Folder Templater for Zapier Code Steps (Node 10.x+)
/**
/ This sample code demonstrates applying a Folder template to a Frame.io Project.
/ A Zapier Code Step must be configured to catch webhook events emitted by Frame.io.
/ Learn about Frame.io webhooks: https://docs.frame.io/docs/webhooks
/ Learn about using JavaScript in Zapier: https://zapier.com/help/create/code-webhooks/use-javascript-code-in-zaps
*/
// Destructure Zapier-defined variables
const { teamId, userId, resourceId, AUTH_TOKEN_KEY } = inputData;
// Frame.io variables. To run on Zapier you must provide your API Token
const AuthHeader = {
Authorization: `Bearer ${AUTH_TOKEN_KEY}`,
'Content-Type': 'application/json'
};
const API_URL = "https://api.frame.io/v2";
// This template defines a folder tree three levels deep
const template = [
{
"name": "01_Audio",
"type": "folder",
"folders": [
{
"name": "01_VO",
"type": "folder"
},
{
"name": "02_Audio_Inputs",
"type": "folder"
},
{
"name": "03_Music",
"type": "folder"
},
{
"name": "04_Audio_Outputs",
"type": "folder"
},
{
"name": "05_SFX",
"type": "folder"
}
]
},
{
"name": "02_Color",
"type": "folder",
"folders": [
{
"name": "01_Projects",
"type": "folder"
},
{
"name": "02_Color_Inputs",
"type": "folder"
},
{
"name": "03_Color_Reference",
"type": "folder"
},
{
"name": "04_Color_Outputs",
"type": "folder"
}
]
},
{
"name": "03_Editorial",
"type": "folder",
"folders": [
{
"name": "01_Projects",
"type": "folder",
"folders": [
{
"name": "_Archive",
"type": "folder"
}
]
}
]
},
{
"name": "04_Online",
"type": "folder",
"folders": [
{
"name": "01_Projects",
"type": "folder"
},
{
"name": "02_Online_Inputs",
"type": "folder",
"folders": [
{
"name": "01_WorkPix",
"type": "folder"
},
{
"name": "02_EDL",
"type": "folder"
},
{
"name": "03_XML",
"type": "folder"
}
]
},
{
"name": "03_Online_Reference",
"type": "folder"
},
{
"name": "04_Online_Outputs",
"type": "folder"
}
]
},
{
"name": "05_Graphics",
"type": "folder",
"folders": [
{
"name": "01_AEP",
"type": "folder"
},
{
"name": "02_C4D",
"type": "folder",
"folders": [
{
"name": "01_Scenes",
"type": "folder"
},
{
"name": "02_Output",
"type": "folder"
},
{
"name": "03_Models",
"type": "folder"
}
]
},
{
"name": "03_Nuke",
"type": "folder"
},
{
"name": "04_Houdini",
"type": "folder"
},
{
"name": "05_Tracking",
"type": "folder"
}
]
},
{
"name": "06_Images",
"type": "folder",
"folders": [
{
"name": "Client_Files",
"type": "folder"
},
{
"name": "Internal_Files",
"type": "folder",
"folders": [
{
"name": "01_Projects",
"type": "folder"
},
{
"name": "02_Flattened",
"type": "folder"
}
]
}
]
},
{
"name": "07_Misc",
"type": "folder",
"folders": [
{
"name": "Fonts",
"type": "folder"
},
{
"name": "Slates",
"type": "folder"
},
{
"name": "Scripts",
"type": "folder"
}
]
},
{
"name": "08_Footage",
"type": "folder",
"folders": [
{
"name": "Shoot_Files",
"type": "folder"
},
{
"name": "Stock_Files",
"type": "folder"
}
]
},
{
"name": "09_Outputs",
"type": "folder",
"folders": [
{
"name": "01_Postings",
"type": "folder"
},
{
"name": "02_Approvals",
"type": "folder"
},
{
"name": "03_Masters",
"type": "folder"
}
]
}
];
/* Every Project in Frame.io has a root_asset_id acting as a 'parent'
/ node to 'children' beneath it. This function returns the
/ root_asset_id for a Project. */
async function getRootAssetId(resourceId) {
let url = `${API_URL}/projects/${resourceId}`;
let options = {
method: 'GET',
headers: AuthHeader,
};
let response = await fetch(url, options).catch(err => {
console.error(`Error fetching root id for ${resourceId}: ${err}`);
throw err;
});
if (!response.ok) {
throw new Error(`Network error fetching root id for ${resourceId}: ${response.status}, ${response.statusText}`);
} else {
let jsonResponse = await response.json();
return jsonResponse.root_asset_id;
}
}
async function createFolder(name, parentId) {
let url = `${API_URL}/assets/${parentId}/children`;
let body = {
type: "folder",
name: name,
};
let options = {
method: 'POST',
headers: AuthHeader,
body: JSON.stringify(body)
};
console.log(`Attempting to create folder: ${name}`);
let response = await fetch(url, options).catch(err => {
console.error(`Error creating folder: ${name}: ${err}`);
throw err;
});
if (!response.ok) {
throw new Error(`[Network error creating folder ${name}: ${response.status}, ${response.statusText}`);
} else {
let result = await response.json();
return result.id;
}
}
/* Recursive function creates each folder in the template using preorder traversal */
const runTemplater = async (template, parentId) => {
while (template.length) {
let item = template.shift();
if (item.type === 'folder') {
let newParentId = await createFolder(item.name, parentId).catch(err => {
console.error(`folder creation error: ${item.name}: ${err}`);
throw err;
});
console.log(`runTemplater successfully created folder: ${item.name}`);
if (item.folders) {
await runTemplater(item.folders, newParentId);
}
}
}
return;
};
let root = await getRootAssetId(resourceId);
await runTemplater(template, root);
return {};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment