Skip to content

Instantly share code, notes, and snippets.

@hyrsky
Created November 11, 2020 15:03
Show Gist options
  • Save hyrsky/6aa0169c47285d32fd2c4a7d4e559dfb to your computer and use it in GitHub Desktop.
Save hyrsky/6aa0169c47285d32fd2c4a7d4e559dfb to your computer and use it in GitHub Desktop.
Create Premiere project from CSV using Adobe extended scrip.
main();
function splitLine(strData, strDelimiter) {
// Check to see if the delimiter is defined. If not,
// then default to comma.
strDelimiter = strDelimiter || ",";
// Create a regular expression to parse the CSV values.
var objPattern = new RegExp((
// Delimiters.
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
// Quoted fields.
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
// Standard fields.
"([^\"\\" + strDelimiter + "\\r\\n]*))"
), "gi");
// Create an array to hold our data. Give the array
// a default empty first row.
var arrData = [];
// Create an array to hold our individual pattern
// matching groups.
var arrMatches = null;
// Keep looping over the regular expression matches
// until we can no longer find a match.
while (arrMatches = objPattern.exec(strData)) {
var strMatchedValue;
// Now that we have our delimiter out of the way,
// let's check to see which kind of value we
// captured (quoted or unquoted).
if (arrMatches[ 2 ]) {
// We found a quoted value. When we capture
// this value, unescape any double quotes.
strMatchedValue = arrMatches[ 2 ].replace(new RegExp( "\"\"", "g" ), "\"");
} else {
// We found a non-quoted value.
strMatchedValue = arrMatches[ 3 ];
}
// Now that we have our value string, let's add
// it to the data array.
arrData.push( strMatchedValue );
}
// Return the parsed data.
return arrData;
}
function readLines(file, skipLines) {
skipLines = skipLines || 0;
lines = [];
// Skip skipLines lines.
while (file.tell() < file.length && skipLines > 0) {
file.readln();
skipLines -= 1;
}
while (file.tell() < file.length) {
lines.push(splitLine(file.readln()));
}
return lines;
}
function isWindows() {
return $.os.indexOf("Windows") != -1;
}
function isMac() {
return $.os.indexOf("Darwin") != -1;
}
/** Format date from DD.MM.YYYY to iso8601 */
function formatDate(date) {
var pattern = new RegExp("^(\\d+)\.(\\d+)\.(\\d+)$");
var result = pattern.exec(date)
if (result && result.length > 3) {
return ("0000" + result[3]).slice(-4) + '-' + ("00" + result[2]).slice(-2) + '-' + ("00" + result[1]).slice(-2);
}
return null;
}
function getObjectKeys(obj) {
var keys = [];
for (var key in obj) {
keys.push(key);
}
return keys;
}
// Good tutorial: https://www.youtube.com/watch?v=jtImTeLrkLE&t=294s
function main() {
var project = app.project;
if (project == null) {
return alert("You must have empty premiere project open to run this")
}
var fileMask;
if(isWindows()) fileMask = '*.csv';
if(isMac()) fileMask = function(file) { file.name.match(/\.csv$/i) ? true : false; }
var logFile = File.openDialog ("Open CSV file", fileMask, false);
if (logFile == null) {
return alert("No CSV file selected");
}
// Read CSV lines.
logFile.open('r');
var csvData = readLines(logFile, 5);
logFile.close();
var sourceFolder = Folder.selectDialog ("Choose the Source folder");
if (sourceFolder == null) {
return alert("No source folder selected");
}
var byDate = {};
var byClipName = {};
var byFileName = {};
for (var i = 0; i < csvData.length; ++i) {
var csvRow = csvData[i];
var filePath = sourceFolder;
var date = formatDate(csvRow[0]);
if (date) {
filePath += '/' + date;
}
var camera = csvRow[3];
if (camera) {
filePath += '/' + camera;
}
var filename = csvRow[2];
filePath += '/' + filename;
byFileName[filePath] = byFileName[filePath] || [];
byFileName[filePath].push(csvRow);
byDate[date] = byDate[date] || {};
byDate[date][filename] = true;
byClipName[filename] = byClipName[filename] || [];
byClipName[filename].push(csvRow);
}
var clipsBin = project.rootItem.createBin("Clips");
var importedClips = [];
project.importFiles(getObjectKeys(byFileName), false, clipsBin);
for (var i = 0; i < clipsBin.children.length; ++i) {
importedClips.push(clipsBin.children[i]);
}
for (var date in byDate) {
// Collect succesfully imported clips from current date.
var currentDateClips = [];
// Collect imported clips:
for (var i = 0; i < clipsBin.children.length; ++i) {
var importedClip = clipsBin.children[i];
if (byDate[date][importedClip.name]) {
currentDateClips.push(importedClip);
}
}
// Execute reogranize:
if (currentDateClips.length > 0) {
var dateBin = clipsBin.createBin(date);
for (var i = 0; i < currentDateClips.length; ++i) {
currentDateClips[i].moveBin(dateBin);
}
}
}
$.writeln("Clip import finished");
var sequence = project.createNewSequence("Sequence", "1234567890");
var videoTrack = sequence.videoTracks[0];
var audioTrack = sequence.audioTracks[0];
var time = new Time();
time.ticks = sequence.timebase.toString();
var startTime = 0;
for (var i = 0; i < importedClips.length; ++i) {
var clip = importedClips[i];
var csvEntries = byClipName[clip.name] || [];
for (var j = 0; j < csvEntries.length; ++j) {
var csvRow = csvEntries[j];
var clipStart = getClipStartTime(csvRow);
var clipDuration = getClipDuration(csvRow, 10);
videoTrack.insertClip(clip, startTime);
setTrackProperty(videoTrack.clips[videoTrack.clips.length - 1], "end", asTimeObject(videoTrack.clips[videoTrack.clips.length - 1].start.seconds + clipDuration));
setTrackProperty(videoTrack.clips[videoTrack.clips.length - 1], "inPoint", asTimeObject(clipStart));
setTrackProperty(videoTrack.clips[videoTrack.clips.length - 1], "outPoint", asTimeObject(clipStart + clipDuration));
setTrackProperty(audioTrack.clips[audioTrack.clips.length - 1], "end", asTimeObject(audioTrack.clips[audioTrack.clips.length - 1].start.seconds + clipDuration));
setTrackProperty(audioTrack.clips[audioTrack.clips.length - 1], "inPoint", asTimeObject(clipStart));
setTrackProperty(audioTrack.clips[audioTrack.clips.length - 1], "outPoint", asTimeObject(clipStart + clipDuration));
startTime += clipDuration;
}
}
}
function asTimeObject(seconds) {
var time = new Time();
time.seconds = seconds;
return time;
}
// Workaround for adobe bug:
// https://community.adobe.com/t5/premiere-pro/cannot-assign-values-to-trackitem-start-or-end/td-p/10973632?page=1
function setTrackProperty(trackItem, property, time) {
try {
if (property == "start") {
trackItem.start = time
}
else if (property == "end") {
trackItem.end = time;
}
else if (property == "inPoint") {
trackItem.inPoint = time;
}
else if (property == "outPoint") {
trackItem.outPoint = time;
}
} catch (e) {
}
}
/** Get MM:SS as seconds */
function asSeconds(time) {
var split = time.split(':');
return parseInt(split[0]) * 60 + parseInt(split[1]);
}
/** Get clip start time in seconds from csvRow */
function getClipStartTime(csvRow) {
return asSeconds(csvRow[4]);
}
/** Get clip duration in seconds from csvRow */
function getClipDuration(csvRow, defaultDuration) {
var endTime = csvRow[5];
if (endTime) {
return asSeconds(csvRow[4]) - asSeconds(endTime);
}
return defaultDuration;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment