Difference between revisions of "Afx Javascript Temp"

From bernie's
Jump to navigation Jump to search
Line 56: Line 56:
}
}
//alert(app.project.items[2])
//alert(app.project.items[2])
</pre>
=== Auto Expose ===
<pre>
function e(s){
    $.writeln(s);
}
app.beginUndoGroup("Analyze animation");
var layers = app.project.activeItem.selectedLayers;
curlayer = layers[0];
var duplicatelayer = curlayer.duplicate();
curlayer.moveBefore(duplicatelayer);
var futureprecompindex = duplicatelayer.index;
var precomp = app.project.activeItem.layers.precompose([duplicatelayer.index],duplicatelayer.name+"_anim_detection",true);
var precomplayer =  app.project.activeItem.layer(futureprecompindex);
precomplayer.guideLayer = true;
var toplayer = precomp.layers[1];
var props = toplayer.property("ADBE Effect Parade");
while(props.numProperties>0){
    props.property(1).remove();
}
var newlayer = toplayer.duplicate();
newlayer.blendingMode = BlendingMode.CLASSIC_DIFFERENCE;
newlayer.startTime += app.project.activeItem.frameDuration;
newlayer.timeRemapEnabled = true;
newlayer.inPoint -= app.project.activeItem.frameDuration;
var explainer = new MarkerValue("1 frame shift + difference blendmode = highlight pixel changes");
newlayer.property("Marker").setValueAtTime(.5, explainer);
var blackSolid = precomp.layers.addSolid([0,0,0], "Black", precomp.width, precomp.height, 1);
blackSolid.moveToEnd();
var sliderctrl = precomplayer.Effects.addProperty("ADBE Slider Control");
sliderctrl.name = "Resolution";
sliderctrl.property("ADBE Slider Control-0001").setValue(3);
var detectorctrl = precomplayer.Effects.addProperty("ADBE Slider Control");
detectorctrl.name = "Detector";
detectorexpression = "\
resolution = effect(\"Resolution\")(\"ADBE Slider Control-0001\");\
resolution = (resolution<1)?1:resolution;\
a = [0,0,0,0];\
for(i=0;i<resolution;i++){\
for(j=0;j<resolution;j++){\
center = [thisComp.width/resolution/2+thisComp.width/resolution * j ,thisComp.height/resolution/2+thisComp.height/resolution * i ];\
sampledistance = [thisComp.width/resolution/2,thisComp.height/resolution/2];\
a+= sampleImage(center, sampledistance , postEffect = true, t = time);\
}\
}\
\
(a[0]+a[1]+a[2]+a[3])/(resolution*resolution)*10000-10000;\
";
detectorctrl.property("ADBE Slider Control-0001").expression = detectorexpression;
detectorctrl.property("ADBE Slider Control-0001").selected = true;
app.executeCommand(app.findMenuCommandId("Convert Expression to Keyframes"));
detectorctrl.property("ADBE Slider Control-0001").selected = false;
app.endUndoGroup();
</pre>
<pre>
var rez = parseFloat(prompt("Resolution to detect movement. 10 is a good start, don't go above 50",10));
//step 1: iterate through sampleImage, add more rez if no change is detected, bake keys at end -- the heavy bit
//rez = 10;
exp = "steps = "+rez+";\ntot = 0;\nfor(j=height/steps/2;j<height;j = j + height/steps){\n\t";
exp += "for(i= width/steps/2;i<width;i = i + width/steps){\n\t\t";
exp += "s = sampleImage([i,j], [width/steps/2,height/steps/2], postEffect = true, t = time);\n\t\ttot += (s[0]+s[1]+s[2]+s[3]);\n";
exp += "\t}\n}\ntot";
s = app.project.activeItem.selectedLayers[0];
v = s.Effects.addProperty("ADBE Slider Control");
slider = v.property("ADBE Slider Control-0001");
slider.expression = exp;
slider.selected = true;
app.executeCommand(2639);
//step 2: if current value is similar to the previous' frame value, write 0 else, write 1, bake result
exp = "f = effect('"+v.name+"')('ADBE Slider Control-0001');\n";
expB = exp + "f-f.valueAtTime(time-thisComp.frameDuration)==0?0:1;";
slider.expression = expB;
app.executeCommand(2639);
mainKeys = [];
for(i=1;i<=slider.numKeys;i++){
    mainKeys[mainKeys.length] = slider.keyValue(i);
}
//step 3: iterate through every frame and add which frame it corresponds to
exp += "a = 0;\nfor(i=0;i<=time*(1/thisComp.frameDuration);i++){\n\t";
exp += "if(f.valueAtTime(i*thisComp.frameDuration)==1){\n\t\ta = i*thisComp.frameDuration;\n\t}\n}\na;";
slider.expression = exp;
app.executeCommand(2639);
slider.expression = "";
slider.expressionEnabled = false;
//step 4: clean up keys
for(i=mainKeys.length-1;i>0;i--){
    if(mainKeys[i]==0){
        slider.removeKey(i+1);
    }else{
        slider.setInterpolationTypeAtKey(i+1,KeyframeInterpolationType.HOLD,KeyframeInterpolationType.HOLD);
    }
}
slider.setInterpolationTypeAtKey(1,KeyframeInterpolationType.HOLD,KeyframeInterpolationType.HOLD);
</pre>
</pre>



Revision as of 12:04, 3 January 2024

Keyframes and Layers counter

wip, doesn't work with animated shapes for now


layersCount = 0;
keyframesCount = 0;
collection = app.project.items;
for(i = 1;i<=collection.length;i++){
    curItem = collection[i];
    if(curItem instanceof CompItem){
        len = curItem.layers.length;
        layersCount += len;
        for(j = 1;j<=len;j++){
            curLayer = curItem.layers[j];
            for(k = 1;k <= curLayer.numProperties;k++){
                for(l = 1;l <= curLayer.property(k).numProperties; l++){
                    //$.writeln(keyframesCount);
                    if(curLayer.property(k).property(l).numProperties>0){
                         for(m = 1;m <= curLayer.property(k).property(l).numProperties; m++){
                            nKeys = curLayer.property(k).property(l).property(m).numKeys;
                            if(nKeys > 0){
                                 keyframesCount += nKeys;
                            }
                            //ugh i wish i was better at recursiveness
                            //$.writeln(curLayer.property(k).property(l).property(m).matchName);
                            //$.writeln(curLayer.property(k).property(l).property(m).numKeys);     
                        }
                    }else{
                            nkeys = curLayer.property(k).property(l).numKeys;
                            if(nKeys > 0){
                                keyframesCount += nKeys;
                            }
                            //keyframesCount += curLayer.property(k).property(l).numKeys;
                            //$.writeln(curLayer.property(k).property(l).matchName);
                            //$.writeln(curLayer.property(k).property(l).numKeys);     
                    }
                }  
            }
        }
    }
}
alert(keyframesCount+" keyframes found and\n"+layersCount+" layers counted in the project");
    
    
function iterateProperties(prop){
           // $.writeln(prop.numProperties);    
    if(prop.numProperties > 0){
        for(i = 1;i<=prop.numProperties;i++){
            iterateProperties(prop.property(i));
        }
    }else{
    //    $.writeln(prop.matchName);
    }
    //$.writeln(prop.matchName);
}
//alert(app.project.items[2])

Batch render project items

Select project footage and it will render them with the chosen rq preset

template = "QTJPG2000"; // chosen by hand, for now

selectedItems = app.project.selection;
rq = app.project.renderQueue;

for(i=0;i<selectedItems.length;i++){
    
    item = selectedItems[i];
    path = item.mainSource.file.path.toString()+'/'+item.name;
    p = app.project.items.addComp(item.name,item.width,item.height,1.0,item.duration,item.frameRate);
    p.layers.add(item);
    rqitem = rq.items.add(p);
	rqitem.outputModules[1].file = new File(path);
	rqitem.outputModules[1].applyTemplate(template);
    
}

Auto Comp to Renderqueue with Template

//todo: be able to select existing RQ items instead of simply comps, and edit their existing paths


function e(s){$.writeln(s)} //debug fn

var win;

function renderAll(){
	//prefTemplate = (app.settings.haveSetting("renderCompWithTemplate", "template"))?(app.settings.getSetting("renderCompWithTemplate", "template")):false;
	
	sel = app.project.selection;
	
	if(sel.length>0){

		
		//needs a comp to create a render item to get templates

		getTemplateUI(sel[0]);
		
		
		//if ui worked fine, there should be a template setting string, if there's a bug or user cancelled, fuck it.

		prefTemplate = (app.settings.haveSetting("renderCompWithTemplate", "template"))?(app.settings.getSetting("renderCompWithTemplate", "template")):false;

		if(prefTemplate != false && prefTemplate != "null" ){
			
			for(i=0;i<sel.length;i++){  

				renderCompWithTemplate(sel[i],prefTemplate) 

			}

		}else{


			writeLn("Send to renderqueue cancelled.");

		}
	}else{
		alert("Select at least one comp or render queue element");
	}
}

function getTemplateUI(nullComp){

	
	// get previous render settings, so we can use it as default selection later

	prefTemplate = (app.settings.haveSetting("renderCompWithTemplate", "template"))?(app.settings.getSetting("renderCompWithTemplate", "template")):false;

	// void render settings if user clicks cancel, to be changed

	app.settings.saveSetting("renderCompWithTemplate", "template","null");

	ai = app.project.activeItem;
	

	// must have at least one comp selected, and the project saved to know where to place the renders
	// eventually the user shouldn't have to save his AEP, but have it appear as a warning somewhere that he should

	if( nullComp != null && nullComp instanceof CompItem && app.project.file != null ){
		
		rq = app.project.renderQueue;

		//create null render comp to fetch templates, delete it right afterwards

		rqitem = rq.items.add( nullComp );
		rqtemplates = rqitem.outputModules[1].templates;
		rqitem.remove();

		// dockable window to do
		//res = "dialog { properties:{ resizeable:true }, preferredSize: [690, 20],  alignChildren: 'fill',orientation:'column',\
		res = "dialog {  \
				properties:{ resizeable:true }, alignChildren: 'fill',orientation:'column',\
				templatesPnl: Panel { \
					orientation:'column', alignChildren:['left', 'top'],text: 'Choose a rendering template',\
					templates: DropDownList {}, \
				}, \
				filePnl: Panel { \
					orientation:'column', alignChildren:['left', 'top'],text: 'Display Paths',\
					pathRbs: Group { \
						orientation:'row',  alignment: 'left', alignChildren:['left', 'bottom'] \
						txt: StaticText { alignment:'left', text:'File path style:' }, \
						unixStylePathRb: RadioButton { text:'Unix (mac)' }, \
						winStylePathRb: RadioButton { text:'Windows', value:true } \
					}, \
					showPathText: StaticText {alignment: 'fill'},  \
					edithPathGrp: Group { \
						orientation:'row', spacing:2, alignment: 'left', \
						editPathBox: EditText { alignment: ['fill','center'],  margins: 8, text:'', properties:{borderless:true}},  \
						testBtn: Button { alignement:[center','center'], text:'Test', properties:{name:'test'} } ,\
					}, \
					explainPathText: StaticText {alignment: 'fill', properties:{multiline: true } }, \
					explainPathTextGrp: Group { \
						orientation:'row',  alignment: 'left', alignChildren:['left', 'center'] \
						c1: StaticText {alignment: 'fill', properties:{multiline: true } },  \
						c2: StaticText {alignment: 'fill', properties:{multiline: true } } \
					}  \
				}, \
				buttons: Group { orientation: 'row', alignment: 'right', \
					okBtn: Button { text:'OK', properties:{name:'ok'} }, \
					cancelBtn: Button { text:'Cancel', properties:{name:'cancel'} }, \
				}, \
			}";

		
		// get/set the display path preference (it will always be unix style internally) 1=windows 0=mac/unix


		
	  
		//input base text 

		explanationText = "You can use the following variables ( and can't use * ? \" < > or | ): \n";
		/*explanationText += "\t{compname}\t\t{compfolder}\n";
		explanationText += "\t{projpath}\t\t\t{compid}\n";
		explanationText += "\t{projname}\t\t\t{date}\n";
		explanationText += "\t[#], [##], [####]... \t(padding)\n";*/

		// create window resource

		win = new Window (res);
        
        //set the preferred template

		preferredItem = 0;

		for(i=0;i<rqtemplates.length;i++){

			//skip hidden templates
			if(rqtemplates[i].indexOf('_HIDDEN') != 0 ){
				item = win.templatesPnl.templates.add ('item',rqtemplates[i]);
				if(rqtemplates[i] == prefTemplate){
					preferredItem = i;
				}
			}
		}
		win.templatesPnl.templates.selection = win.templatesPnl.templates.items[preferredItem];

		// can't add newline \n character in res, so fill in text now

		win.filePnl.explainPathText.text = explanationText;
		
		// set os choice radio button, figure out if it's in prefs 
		// eventually users shouldn't see this, the script should be tailored for mac or windows

		os = $.os.toLowerCase().indexOf("windows") != -1;

		if( app.settings.haveSetting("renderCompWithTemplate", "oschoice") ){
			os = ( app.settings.getSetting("renderCompWithTemplate", "oschoice") == 1 ) ? 1 : 0 ;
		}else{
			app.settings.saveSetting("renderCompWithTemplate", "oschoice", os);
		}

		win.filePnl.pathRbs.unixStylePathRb.value = !os;

		// set path template box, if it doesn't have one, use a default;

		inputBox = win.filePnl.edithPathGrp.editPathBox;
		outPutBox = win.filePnl.showPathText;

		var pathTemplate = "";

		if( app.settings.haveSetting("renderCompWithTemplate", "pathtemplate") ){
			pathTemplate = app.settings.getSetting("renderCompWithTemplate", "pathtemplate");
		}else{
			pathTemplate = "{projpath}/RENDER/{date:ymd}_{compname}/{compname}.[####]";
			app.settings.saveSetting("renderCompWithTemplate", "pathtemplate", pathTemplate);
		}

		inputBox.text = pathTemplate;

		//add ui callbacks

		//call once, to fill the result text box
		
		updatePath(inputBox, outPutBox);

		inputBox.onChange = inputBox.onChanging = function() { updatePath(inputBox, outPutBox) };

		/*-----TO BE CUT---------*/
		win.filePnl.pathRbs.unixStylePathRb.onClick = win.filePnl.pathRbs.winStylePathRb.onClick = function() {
			//save preferences

			app.settings.saveSetting("renderCompWithTemplate", "oschoice", (!win.filePnl.pathRbs.unixStylePathRb.value)?1:0);
			updatePath(inputBox, outPutBox);
		}
		/*-----END CUT-----------*/


		win.filePnl.edithPathGrp.testBtn.onClick = function(){
			fp = descriptionToFilePath("",1,inputBox.text, 0);
			fpFolder = new Folder(fp);
			e(fpFolder.absoluteURI);
		}

		win.buttons.okBtn.onClick = function(){
			//save preferences
			prefTemplate = win.templatesPnl.templates.selection;
			app.settings.saveSetting("renderCompWithTemplate", "pathtemplate", inputBox.text);	
			//app.settings.saveSetting("renderCompWithTemplate", "oschoice", (!win.filePnl.pathRbs.unixStylePathRb.value)?1:0);
			app.settings.saveSetting("renderCompWithTemplate", "template",prefTemplate);
			win.close();
		}

		win.layout.layout(true);

		win.onResizing = win.onResize = function () {this.layout.resize()};
	
	
		
		win.center();
		win.show();

	}else{

		//alert dialogs suck, but they are efficient

		alert("Select at least one comp to render, and make sure your After Effects file is saved to disk.");
	}
}

function resizeUI(windowObj){
	//nasty function which creates a new textbox to figure out how big the editbox is, so no text is clipped

	var textbox = windowObj.filePnl.edithPathGrp.editPathBox;
	//var testbutton = windowObj.filePnl.edithPathGrp.testBtn;

	g = windowObj.filePnl.add("group", [0,0,0,0]);
	g.enabled = g.visible = false;
	tmp = g.add("edittext", undefined, textbox.text, {enabled:false, visible:false});

	var preferredWidth = tmp.preferredSize[0];

	//e("newpref: "+r.preferredSize[0]);
	windowObj.filePnl.remove(g);

	textbox.size = [preferredWidth, textbox.preferredSize[1] ];
	//testbutton.size = testbutton.preferredSize;

	windowObj.layout.layout(true);

}

function updatePath( inputRes, outputRes){
	
	os = ( app.settings.getSetting("renderCompWithTemplate", "oschoice") == 1 ) ? 1 : 0 ;
	
	input = inputRes.text;

	input = descriptionToFilePath("",1,input, 1);
	input = setPathStyle(input, !os) ;  //backslashes to slashes
	outputRes.text = input;

	resizeUI(inputRes.parent.parent.parent);

	//windowObj.layout.layout(true);

}

function descriptionToFilePath(comp, rqid, descriptionString,forDisplay){

	// takes a description like {projpath}/{projname}_{compname}/{compname}_[#####] and transforms it into a usable unix path
	// if there is no comp fed, use the first in the selection.
	// 'forDisplay' int decides if it's for display (add frame count and turn %20s to spaces) or actual path to be used
	// 'rqid' is the number of the comp in the renderqueue, default is 1

	var str = descriptionString;

	if(comp == "" || comp == null){
		comp = app.project.selection[0];
	}
	var projName = app.project.file.name.toString();

	//standard stuff, comp path name etc....

	str = str.replace(/\{projpath\}/gi, app.project.file.path.toString());
	projName = projName.substr(0, projName.lastIndexOf('.')) || projName;
	str = str.replace(/\{projname\}/gi, projName);
	str = str.replace(/\{compname\}/gi, comp.name);
	var parentFolder = (comp.parentFolder.name == "Root") ? "" : comp.parentFolder.name ;
	str = str.replace(/\{compfolder\}/gi, parentFolder);

	//if we use {id}, make sure it's padded 

	var rq = app.project.renderQueue;
	str = str.replace(/\{id\}/gi, pad(rq.items.length.toString().length, rqid.toString(),"0") );


	//figure out padding, if it's forDisplay, show it to the user

	startPad = str.indexOf("[#");
	endPad = str.lastIndexOf("#]");

	if(startPad > 0  && endPad > 0 && endPad > startPad && forDisplay){
		startFrame = comp.workAreaStart/comp.frameDuration;
		str = str.substring(0,startPad)+pad(endPad-startPad, startFrame.toString(), "0")+str.substring(endPad+2,str.length);
	}

	//date

	var datesArray = str.split("{date:");
	var tempstr = "";

	if(datesArray.length > 0){

		var today = new Date();
		var dd = today.getDate().toString();
		var mm = (today.getMonth()+1).toString();
		var yyyy = today.getFullYear();

		tempstr = datesArray[0];

		for(i = 1 ; i < datesArray.length; i++ ){
			endBracketPos = datesArray[i].indexOf("}");
			nextBracketPos =  datesArray[i].indexOf("{");
			nextBracketPos = (nextBracketPos == -1)? 9999 : nextBracketPos; //case if date is the last used tag
			if(endBracketPos > -1 && endBracketPos < nextBracketPos){
				dateString = datesArray[i].substring(0, endBracketPos );
				dateString = dateString.replace(/y/gi, yyyy);
				dateString = dateString.replace(/d/gi, pad(2, dd, "0"));
				dateString = dateString.replace(/m/gi, pad(2, mm, "0"));
				tempstr += dateString + datesArray[i].substring(endBracketPos+1,datesArray[i].length);
			}else{
				tempstr = str;
			}
		}
		str = tempstr;
	}

	if(forDisplay){
		str += ".ext";
	}

	return str;
}

function renderCompWithTemplate(comp,template){
	//sends the comp to the renderqueue with the selected file path, creating folders and subfolders if needed

	rq = app.project.renderQueue;
	rqitem = rq.items.add(comp);
	rqtemplates = rqitem.outputModules[1].templates;

	filename = app.project.file.name;
	filepath = app.project.file.toString();
	projpath = filepath.slice(0,filepath.length-filename.length);

	savePath = projpath+comp.name+"/"+filename.slice(0,filename.length-4)+"/";
	saveFile = comp.name+".[####].tif";
	saveFolder = new Folder(savePath);
	saveFolder.create();
	rqitem.outputModules[1].file = new File(savePath+"/"+saveFile);
	rqitem.outputModules[1].applyTemplate(template);

}

function setPathStyle(path, toUnixPath){
	// takes a string and creates either a unix path like /c/my%20folder/ if toUnixPath is set to true
	// or a windows path like c:\my folder\. Returns false if there's a problem (tbd)
	if(!toUnixPath){
		//unix -> win
		path = path.replace(/\//, "");
		path = path.replace(/\//, ":/");
		path = path.replace(/%20/g, " ");
		path = path.replace(/\//g, "\\");
	}else{
		path = "/"+path.replace(":\\", "/");
		path = path.replace(/\\/g, "/");
		path = path.replace(" ", "%20");
		//path = path.substring(0,path.lastIndexOf("/"));
	}
	return path;
}

function pad(width, string, padding) { 
  return (width <= string.length) ? string : pad(width, padding + string, padding);
}

renderAll();


create effect creator

ui

function e(s){
	$.writeln(s);
}

/*

var windowObj;
function ui(thisObj) {
	windowObj = (thisObj instanceof Panel) ? thisObj : new Window("palette", "ui_test", [100, 100, 300, 300]);
	addButton("flip",windowObj);
	return windowObj;
}*/


function addButton(buttonname,ui){
	//ui.add("button", [0, 0, 20, 20], But_01[0]);
	return ui.add("button", undefined, buttonname);
}





function ui(thisObj){
    pan = (thisObj instanceof Panel) ? thisObj : new Window("palette", "Watchfolder", [100, 100, 300, 300]);
    var securitySetting = app.preferences.getPrefAsLong("Main Pref Section", "Pref_SCRIPTING_FILE_NETWORK_SECURITY");
    if (securitySetting != 1) {
        pan.add("statictext",[15,15,300,45],"Set prefs and re-launch");
        alert("You need to check \"Allow Scripts to Write Files and Access Network\" in your preferences for this script to work");
     }else{
                var res = 
            "group { \
                        alignment: ['fill','fill'], \
                        alignChildren: ['fill','top'], \
                        orientation: 'column', \
                            setWF: Button {text: 'add btn' ,preferredSize:[-1,30]} , \
                            sendWF: Button {text: 'Send To Watchfolder' ,preferredSize:[-1,30]} , \
                    }";	
            pan.grp = pan.add(res);        
            pan.grp.setWF.onClick = function () {
            	addButton("joe",pan.grp);
            	resfreshUI(pan);
                    }
            pan.grp.sendWF.onClick = function () {
                }
            resfreshUI(pan);    
            /*
            pan.layout.layout(true);
            pan.layout.resize();
            pan.onResizing = pan.onResize = function () {this.layout.resize();}*/
            return pan;
    }
}

function resfreshUI(src){
	src.layout.layout(true);
	src.layout.resize();
	src.onResizing = pan.onResize = function () {this.layout.resize();}

}

ui(this);


fn

function e(s){
	$.writeln(s);
}

// to be done:
// 		save keys
// 		save masks
//		save text if text layer, camera zoom if camera etc
//		use FFX as custom values

function grabEffects(layers){
	
	var buffer = "";
	var chosenLayerName = "curLayer";

	for (i=0;i<layers.length;i++){

		effs = layers[i].property("ADBE Effect Parade");

		for(j=1;j<=effs.numProperties;j++){

			//create the effects, no matter if properties below have values

			buffer += "\n\tprop = "+ chosenLayerName +".Effects.addProperty(\""+ effs.property(j).matchName +"\");\n";
			buffer += "\tprop.name = \""+ effs.property(j).name +"\";\n";
			buffer += "\tprop.enabled = "+ effs.property(j).enabled +";\n";

			for(k=1;k<=effs.property(j).numProperties;k++){

				curProp = effs.property(j).property(k);
				
				//only add value if it's non-default

				if(curProp.isModified){

					curPropValue = propType(curProp);

					// if it returns -1, it's (probably) a useless 'parent' property, skip

					if( curPropValue != -1){
						
						// /!\ if it'sa  custom value type, there's little to no way of using it in a script, so we can comment it out and warn the user -- there are also false positives, ^but they should be ignored with '-1' as curpropvalue

						buffer += "\t\t// "+curProp.name+((curPropValue===false)?" /!\\ Can't use this custom data! could be a false negative, but unlikely ":"")+"\n";                                        
						buffer += "\t\t"+((curPropValue===false)?"//":"") + "prop.property(\""+curProp.matchName+"\").setValue(" + curPropValue + ");\n";
						
						// if there is an expression and it's enabled, use it

						if(curProp.expression != "" && curProp.expressionEnabled){
							buffer += "\t\t"+((curPropValue===false)?"//":"") + "prop.property(\""+curProp.matchName+"\").expression = \""+curProp.expression+"\";\n";
						}
					}
				}
			}
		}
	}

	return buffer;
}

function outputCode(){
	
	effectsLayers = app.project.activeItem.selectedLayers; //use effects from all selected layers

	buffer = "";
	if(effectsLayers.length>0){
		buffer = "var selectedLayers = app.project.activeItem.selectedLayers;\n";
		buffer += "for (i=0;i<selectedLayers.length;i++){\n";
		buffer += "\n\tcurLayer = selectedLayers[i];\n"; 
		buffer += grabEffects(effectsLayers) + "\n}";
		//e(buffer);
	}
	return buffer;
}


e(outputCode());
e("\n------------------------------------------------------");


 function propType(property){

	returnvalue = false;
	
	e("--->"+property.name+" "+property.propertyValueType+"\n"); //debug
	//e("--->"+property.name+" "+property.canVaryOverTime+"\n"); //debug		
	
	switch(property.propertyValueType){

		case PropertyValueType.ThreeD_SPATIAL:
			returnvalue = "["+property.value[0]+","+property.value[1]+","+property.value[2]+"]";
			break;
		case PropertyValueType.ThreeD:
			returnvalue = "["+property.value[0]+","+property.value[1]+","+property.value[2]+"]";
			break;

		case PropertyValueType.TwoD_SPATIAL:
			returnvalue = "["+property.value[0]+","+property.value[1]+"]";
			break;
		case PropertyValueType.TwoD:
			returnvalue = "["+property.value[0]+","+property.value[1]+"]";
			break;			

		case PropertyValueType.OneD:
			returnvalue = property.value;
			break;		

		case PropertyValueType.COLOR:
			returnvalue = "["+property.value[0]+","+property.value[1]+","+property.value[2]+","+property.value[3]+"]";
			break;

		case PropertyValueType.LAYER_INDEX:
			returnvalue = property.value;
			break;

		case PropertyValueType.MASK_INDEX:
			returnvalue = property.value;
			break;			

		//no way to store custom value but FFX, tbd
		case PropertyValueType.CUSTOM_VALUE:
			returnvalue = false;
			break;

		// if we land on default, it is _most likely_ a property 'parent' with no real use
		default:
			//e("using default: --->"+property.name+" "+property.propertyValueType+"\n")
			returnvalue = -1;
			break;
	}
	return (returnvalue);
 }

left to right

function e(s){
	//debug
    $.writeln(s);
}


function replaceLR(s){
    
    s = s.replace(/left/g, "right");
    s = s.replace(/Left/g, "Right");
    s = s.replace(/LEFT/, "RIGHT");
    return s;
}


function checkImportLeftRight(layer){

	// is it a footage layer (includes solids etc.. not Comps)
	if(layer.source instanceof FootageItem){
		
		//is it a footage item (.exr)
		if(layer.source.file != null){
			path = layer.source.mainSource.file.toString();
	
			 //check path, if it has 'left' in it, grab 'right' and import and replace footage
			if(path.toLowerCase().indexOf("left") > -1){

				rightPath = replaceLR(path);
				rightFile = new File(replaceLR(path));

				//if file exists, import right file, replace layer with it
				if(rightFile.exists){
					
					
					var io = new ImportOptions(rightFile);
					if(io.canImportAs(ImportAsType.FOOTAGE)){
					
						io.importAs = ImportAsType.FOOTAGE;
						io.sequence = true;
						src = app.project.importFile(io);
						
						return(layer.replaceSource(src,1));
						
					}else{
						return false
					}



				}else{
					alert("file not found! "+rightPath);
					return false
				}
			}
	
		}
	}
}

/*
a = app.project.activeItem;

for(i=1;i<=a.layers.length;i++){
 //e(a.layers[i].name);
 e(checkImportLeftRight(a.layers[i]));
    //if it's footage

}

for(i = 1;i<app.project.numItems;i++){
	e(i+" "+app.project.items[i].name); 
}
// 3 and 4
*/
function new3dComp(leftcomp,rightcomp){
	threedcomp = leftcomp.name.replace(/left/g,"3D");
	w = leftcomp.width;
	h = leftcomp.height;
	duration = leftcomp.duration;
	frameRate = leftcomp.frameRate;
	newComp = app.project.items.addComp(threedcomp, w , h , 1.0, duration, frameRate);


	
	newComp.layers.add(rightcomp);
	newComp.layers.add(leftcomp);
	
	threed = newComp.layers.addSolid([1,1,1],"3D Glasses",w,h,1.0);
	threed.adjustmentLayer = true;
	
	threedglasses = threed.Effects.addProperty("ADBE 3D Glasses2");
	threedglasses.property("Left View").setValue(2);
	threedglasses.property("Right View").setValue(3);
	threedglasses.property("3D View").setValue(12);

}
new3dComp(app.project.items[3],app.project.items[4]);



//e(app.project.activeItem.name+" --- ")

Output .SRT from layer markers

function pad10(n){
    return (n<10)?"0"+n:n;
}
function pad100(n){
    return (n<100)?"0"+pad10(n):n;
}

function formatTime(time){
    time =~~ (time*1000)/1000;

    var hrs = ~~(time / 3600);
    var mins = ~~((time % 3600) / 60);
    var secs =  ~~(time % 60);    
    var ms = ~~((time-Math.floor(time))*1000);
    
    time = pad10(hrs)+":"+pad10(mins)+":"+pad10(secs)+","+pad100(ms);
    return time;
}

data = "";
var ai = app.project.activeItem;
if ( ai instanceof CompItem && ai.selectedLayers.length == 1) {
    var m = ai.selectedLayers[0].marker;
    for(i=1;i<=m.numKeys;i++){
        data += i;
        data += "\n"+ formatTime(m.keyTime(i))+" --> "+ formatTime(m.keyTime(i)+m.keyValue(i).duration);
        data += "\n"+m.keyValue(i).comment;
        data += "\n";
       }
}


alert(data)

//result:
//
//1
//00:03:16,945 --> 00:03:17,364
//testing comment 1
//
//2
//01:59:47,228 --> 01:59:49,396
//second subtitle at 2 hours in
//

Shift keys

function e(str){
      $.writeln(str);
}
function getLayerFromProperty(prop){
    return prop.propertyGroup(prop.propertyDepth)
}
var c = app.project.activeItem;
if( c != null){
    var props = c.selectedProperties;

    //e(props[0].matchName);
    for(i = 0;i<props.length;i++){
        e("\n---------------------------\n"+props[i].matchName+" / "+getLayerFromProperty(props[i]).name);
        k = props[i].selectedKeys;
        for(keyVar in k){
            //k[keyVar]
            
            
           // e( ); 
           e(props[i].keyTime(k[keyVar])); 
           //e(k[keyVar]); 
        }
    //CANT FUCKING NUDGE KEYFRAMES
      //  e(props[i].selectedKeys);
    }
}



Selection tool palette

{
//tmpdir = $.getenv("tmp");
    function toolWindow(thisObj){
        function drawUI(){
            var my_palette = new Window("palette","Selection Tool");
            my_palette.bounds = [300,200,300,285];
            /*var button1 = addScriptButton(my_palette,[l_button_left,   5, l_button_right, 25], 
                    "Find and Replace Text",    demosDirectory, "Find and Replace Text.jsx");
            var button3 = addScriptButton(my_palette,[l_button_left,  30, l_button_right, 50], 
                    "Scale Composition", 		demosDirectory, "Scale Composition.jsx");
            var button4 = addScriptButton(my_palette,[l_button_left,  55, l_button_right, 75], 
                    "Scale Selected Layers", demosDirectory, "Scale Selected Layers.jsx");

            var button6 = addScriptButton(my_palette,[r_button_left,   5, r_button_right, 25], 
                    "Sort Layers by In Point",     demosDirectory, "Sort Layers by In Point.jsx");
            var button8 = addScriptButton(my_palette,[r_button_left,  30, r_button_right, 50], 
                    "Render and Email",    myDirectory,    "Render and Email.jsx");

            var button12 = addHelpButton(my_palette,[r_button_left,  55, r_button_right, 75]);*/

            my_palette.show();
        }
    drawUI();
    }
 toolWindow(this);
}

Make .bat file (WIP)

function pathToWinPath(path){
    var str = path.toString().replace(/\//, "");
    str = str.replace(/\//, ":/");
    str = str.replace(/%20/g, " ");
    str = str.replace(/\//g, "\\");
    return str;
}


function createBat(){
    d = new Date();
    m = d.getMonth()+1;
    j = d.getDate();
    if(m<10){
        m="0"+m;
    }
    if(j<10){
        j="0"+j;
    }

    var txtFile = new File("~/Desktop/ae_render"+m+"_"+j+".bat");
    alert(pathToWinPath(app.project.file));
    txtFile.open("w","TEXT","????");
    txtFile.close();
}

res =
"dialog { \
    allGroups: Panel {\
        orientation:'column',\
        alignChildren:'fill',\
        text:'Options', \
        chckOff: Checkbox {text:'Shutdown PC when finished'}, \
        chckAppend: Checkbox {text:'Append (instead of overwriting)'},\
        aePath: Group {orientation:'row',align:'fill', alignChildren:['fill','center'],\
            aeLocBtn: Button {text:' aerender.exe location : '}, \
            aeLocTst: StaticText {text:'C:\\Program fil...'}} \
        okCancel: Group {orientation:'row',align:'fill', alignChildren:'center',\
            okBtn: Button { text:'OK', properties:{name:'ok'}} , \
            cancelBtn: Button { text:'Cancel', properties:{name:'cancel'}},\
        }\
    }\
}";

win = new Window (res);
win.allGroups.chckAppend.value = true;
win.center();
win.show();

Carnet De Voyage rangement

//rangement pour carnet de voyage
app.beginUndoGroup("CDV Rangement");
boolVal = false;
sel = app.project.selection;
if(sel.length == 1){
    shot = sel[0];
    allItems = app.project.items;
    sortItems = new Array();
    for(i=1;i<=allItems.length;i++){
        if(!(allItems[i] instanceof FolderItem)){
            if(allItems[i].parentFolder.name == "Root"){
                sortItems[sortItems.length] = allItems[i];
            }
        }else{
            if(allItems[i].parentFolder.name == "Root"){
                    sortItems[sortItems.length] = allItems[i];
            }        
        }
    }
    t = app.project.items.addFolder("ELMTS");
    for(i=0;i<=sortItems.length-1;i++){
        if(sortItems[i] != shot){
        sortItems[i].parentFolder = t;
        }
    }
}
if(app.project.renderQueue.item(1).outputModules.length == 2){ //copie d'un output module à la main nécéssaire
    fileP = app.project.renderQueue.item(1).outputModules[1].file.toString();
    fileP = fileP.replace("/m/EPISODE","/b/EPISODE");
    fileP = new File(fileP);
    app.project.renderQueue.item(1).outputModules[2].file = fileP;
    app.project.renderQueue.item(1).outputModules[2].applyTemplate("PNGSeq");
    var curFile = app.project.file.name;
    curFile = curFile.substring(0,curFile.length-4);
    var pth = app.project.file.path+"/"+curFile+"_MOV+PNG.aep";
    var mySaveFile = new File(pth);        
    app.project.save(mySaveFile);
}else{
    writeLn("Duplicate output modules first");
}
app.endUndoGroup();

Chat

JSX

var myPalette = buildUI(this);

    if (myPalette != null && myPalette instanceof Window) {
        myPalette.show()
        }

    function buildUI (thisObject) {

    if (thisObject instanceof Panel) {
        var myWindow = thisObject;
        } else { 
        var myWindow = new Window ("palette", "My Window");
        }

g = myWindow.add("group");
g.orientation = "row";
g.alignChildren = "left";
//g.alignement = "top";
bt1 = g.add("button",undefined,"test");
bt1.onClick = bob;
//myWindow.myPanel.titleText = myWindow.myPanel.add("staticText");
//myWindow.myPanel.titleText.text =  "Move After Render v1.0";  

myWindow.layout.layout(true);
//myWindow.layout = new AutoLayoutManager(myWindow);
//myWindow.layout.resize();
return myWindow;
} 
h = 0;
function bob(){
//    alert();
    w = this.parent.parent;
    p = this.parent;
    h++;
    bt2 = p.add("button",undefined,"test"+h);  
      bt2.alignement = ["left","top"];
    if(h%3==0){

       
        bt2.helpTip = "TTTTT";
        }
    bt2.onClick = flup;
   //w.update();
   w.layout.layout(1); 
  // w.layout.resize();

//    w.show();
    }

function flup(){
    f = new Folder($.fileName);
    f = new Folder(f.parent+"/shelves/");
   if(!f.exists){f.create()};
    cfg = new File(f.parent+"/shelves/shelves.cfg");
    cfg.open('e');
    cfg.write(this.onClick);
    cfg.close();
    cfg.execute();
}
function pop(){
    f = new Folder($.fileName);
    fi = new File(f.parent+"/shelves/testShelf.jsx");
    fi.open('e');
    eval(fi.read());
    }
----------------
function grab(){
    var reply = "";
    c = new Socket;
    if (c.open ("berniebernie.fr:80")) {
        if(c.writeln ("GET /dump/afx/chat.php  HTTP/1.0\nHost: berniebernie.fr\n")){
            reply = decodeURIComponent(c.read(1000));
            reply = reply.split("--afx chat file log--");
            reply = reply[1];
        }else{
             return 0;
        }
        c.close();
    }else{
             return 0;
    }
    return reply;
}
function talk(str){
    var reply = "";
    c = new Socket;
    if (c.open ("berniebernie.fr:80")) {
        if(c.writeln ("GET /dump/afx/chat.php?msg="+str+"  HTTP/1.0\nHost: berniebernie.fr\n")){
            reply = decodeURIComponent(c.read(1000));
            reply = reply.split("--afx chat file log--");
            reply = reply[1];
        }else{
             return 0;
        }
        c.close();
    }else{
             return 0;
    }
    return reply;
}
//alert(grab());
alert(talk("flipflap"));

////////////////
app.preferences.getPrefAsLong("Main Pref Section","Pref_SCRIPTING_FILE_NETWORK_SECURITY"

Php

<?php
$myFile = "testFile.txt";
if(isset($_GET['msg']) && $_GET['msg'] != ""){
    $fh = fopen($myFile, 'a') or die("can't open file");
    fwrite($fh, ($_GET['msg']."\n"));
    fclose($fh);    
}else{
    //$fh = fopen($myFile, 'r') or die("can't open file");
    //include$str = $str, true);
    //header("Content-Type: plain/text"); 
    echo encodeURIComponent(file_get_contents("testFile.txt"));
    //echo nl2br(htmlentities(file_get_contents("testFile.txt")));
}

?>