Created
November 11, 2020 15:03
-
-
Save hyrsky/6aa0169c47285d32fd2c4a7d4e559dfb to your computer and use it in GitHub Desktop.
Create Premiere project from CSV using Adobe extended scrip.
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
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