ExtendScript Working with Compositions

<- Previous article ExtendScript Working with files





In the last two articles, I've covered how to make a script that runs in After Effects. Our script created a window in the program interface where we can write and execute ExtenScript code. But this is a toy, it can only be useful for a beginner. Let's do something more useful in real life.





One of the most common tasks that I encountered in my work was the dynamic placement of titles in videos. Video is one of the most popular content formats today. One of the limitations imposed by the browser is the inability to launch sound in the video without user action. The natural way out of this situation is to replace the sound with titles. If it is 5 - 10 titles, then you can make them by hand. Well, what if you need to release five videos a day and they contain not 10, but 50 - 70 titles? Moreover, each video is in 2 - 3 formats. Plus, in several languages? If this situation seems unusual to you, then I encounter it every day.





So let's make this task as easy as possible. We will make a more or less universal script that will interpret the text into titles in the After Effects scene. Although I have solved this problem many times already, I will write my script right at the time of writing the article, so as not to miss anything and make my story as detailed as possible. Let's get started.





We will enter the title text as follows





#simple   
   simple

#simple  simple      

#double   
   double
      
      



Titles are separated from each other by double hyphenation. Lines of one title are separated by hyphenation. The first word with a # character is a tag that defines the type of title. By this tag, we will subsequently determine what layout we need to create this title. But more on that later, for now, take this text structure for granted.





. . , init, , .





{
(function init(){
   
//       

})();
}
      
      







var editText = win.add(
   'edittext',
   [0, 0, 300, 300],
   '  ',
   {multiline: true}
);
      
      



run , createTitres





btnRun.onClick = function () {
   try {
       createTitres(editText.text.getTitresData());
   } catch (err) {
       alert(err)
   }
};
      
      



createTitres, .





function createTitres(data) {

}
      
      



String, getTitresData, , . Array, map. .





String.prototype.getTitresData = function() {
   return this
       .replace(/(^\n|^ |^"|\n+$| +$|"+$)/g, "")
       .split("\n\n")
       .map(function(d) {
           var str = d.replace(/(^\n|^ |\n+$| +$)/g, "")
           var tag = str.split(" ")[0];
           var text = str.replace(tag + ' ', '');
           return {
               type: tag.replace('#', ''),
               text: text,
           }
       });
}
Array.prototype.map = function(callback) {
   var arr = [];
   for (var i = 0; i < this.length; i++) {
       arr.push(callback(this[i]));
   }
   return arr;
}
      
      



, . getTitresData . , , , , .





this.replace(/(^\n|^ |^"|\n+$| +$|"+$)/g, "")
      
      







.split("\n\n")
      
      



,





.map(function(d) {
  var str = d.replace(/(^\n|^ |^"|\n+$| +$|"+$)/g, "")
  var tag = str.split(" ")[0];
  var text = str.replace(tag + ' ', '');
  return {
    type: tag.replace('#', ''),
    text: text,
  }
});
      
      



. createTitres . . .





. After Effects. . Project   , 1x1. ModelScene_1x1





ModelScene , ,   . 1x1 , . , , . .





.





, , , . Duration , . .





. . createTitres .





function createTitres(data) {
   var scenesData = getScenesData();
}

function getScenesData() {
   var doc = app.project;
   var data = [];
   for (var i = 1; i <= doc.numItems; i++) {
       var item = doc.item(i);

       if (item instanceof CompItem &&
           /^ModelScene/.test(item.name)) {
           data.push({
               type: item.name.split('_')[1],
               width: item.width,
               height: item.height,
               frameRate: Math.floor(1 / item.frameDuration),
               duration: item.duration
           });
       }
   }
   return data;
}
      
      



getScenesData . , . numItems.





for (var i = 1; i <= doc.numItems; i++)
      
      



, ModelScene.





if (item instanceof CompItem &&
    /^ModelScene/.test(item.name))
      
      



, .





data.push({
    type: item.name.split('_')[1],
    width: item.width,
    height: item.height,
    frameRate: Math.floor(1 / item.frameDuration),
    duration: item.duration
});
      
      



, . , , . frameDuration - .





, , , .





function createTitres(data) {
   var scenesData = getScenesData();

   for(var i = 0; i < scenesData.length; i++) {
       var scene = getScene(scenesData[i]);
   }
}

function getScene(data) {
   var sceneName = 'scene-' + data.type;
   return getItem(sceneName, CompItem) ||
       app.project.items.addComp(
           sceneName,
           data.width,
           data.height,
           1,
           data.duration,
           data.frameRate
       );
}

function getItem(name, type) {
   var doc = app.project;

   for (var i = 1; i <= doc.numItems; i++) {
       if (doc.item(i).name === name) {
           if (type) {
               if (doc.item(i) instanceof type) {
                   return doc.item(i);
               }
           } else {
               return doc.item(i);
           }
       }
   }
   return null;
}
      
      



getScene





getItem(sceneName, CompItem)
      
      



, ,





app.project.items.addComp(
    sceneName,
    data.width,
    data.height,
    1,
    data.duration,
    data.frameRate
);
      
      



. , scene-1x1. . .









, .





<- Previous article ExtendScript Working with files








All Articles