How can I send selected comps in After Effects to AME via extendscript? - extendscript

I've been trying to figure this out for the past day or two with minimal results. Essentially what I want to do is send my selected comps in After Effects to Adobe Media Encoder via script, and using information about them (substrings of their comp name, width, etc - all of which I already have known and figured out), and specify the appropriate AME preset based on the conditions met. The current two methods that I've found won't work for what I'm trying to do:
https://www.youtube.com/watch?v=K8_KWS3Gs80
https://blogs.adobe.com/creativecloud/new-changed-after-effects-cc-2014/?segment=dva
Both of these options more or less rely on the output module/render queue, (with the first option allowing sending it to AME without specifying preset) which, at least to my knowledge, won't allow h.264 file-types anymore (unless you can somehow trick render queue with a created set of settings prior to pushing queue to AME?).
Another option that I've found involves using BridgeTalk to bypass the output module/render queue and go directly to AME...BUT, that primarily involves specifying a file (rather than the currently selected comps), and requires ONLY having a single comp (to be rendered) at the root level of the project: https://community.adobe.com/t5/after-effects/app-project-renderqueue-queueiname-true/td-p/10551189?page=1
Now as far as code goes, here's the relevant, non-working portion of code:
function render_comps(){
var mySelectedItems = [];
for (var i = 1; i <= app.project.numItems; i++){
if (app.project.item(i).selected)
mySelectedItems[mySelectedItems.length] = app.project.item(i);
}
for (var i = 0; i < mySelectedItems.length; i++){
var mySelection = mySelectedItems[i];
//~ front = app.getFrontend();
//~ front.addItemToBatch(mySelection);
//~ enc = eHost.createEncoderForFormat("H.264");
//~ flag = enc.loadPreset("HD 1080i 25");
//app.getFrontend().addItemToBatch(mySelection);
var bt = new BridgeTalk();
bt.appName = "ame";
bt.target = "ame";
//var message = "alert('Hello')";
//bt.body = message;
bt.body="app.getFrontend().addCompToBatch(mySelection)";
bt.send();
}
}
Which encapsulates a number of different attempts and things that I've tried.
I've spent about 4-5 hours trying to scour the internet and various resources but so far have come up short. Thanks in advance for the help!

Related

Is it possible to store Cytoscape.js layout data directly to a file format in app/web server and re-launch the same layout to minimize re-computation?

Some of the cytoscape layout is randomize where the position is not fix every time we launch it. I understand from multiple stack overflow questions where we can save the layout data (i.e. including its position x and y) into browser local storage or session storage so that we can display the same layout using the same data.
However, the problem with local storage or session storage is good for one users. But, imagine if there are thousands of users using the same app, the server will undergo mass computation for each user to store respective data to individual browsers. Can we save the data into a file format directly into app/web server so that 1000 users will see the same layout and this reduces the computation of different data set as well.
Thank you. Would like to know the possibility to convert data into a file and store in the web/app server.
Yes, you can store position data. Actually, there are 2 options in my mind.
Use cy.json(). You can store the elements as JSON like JSON.stringify(cy.json().elements) and then save this JSON string.
cy.json().elements is something like the below image
You can restore this data easily like cy.json({elements: JSON.parse(jsonStr));
As you could see cy.json().elements is a bit big thing. Position data is just a small object like {x: 0, y: 0}. Additional to position it contains many other data. So if you only need to restore the positions, you could store them manually easily with a code like below. You can use ele.id and node.position() functions.
function storePositions() {
const nodes = cy.nodes();
const nodePositions = {};
for (let i = 0; i < nodes.length; i++) {
nodePositions[nodes[i].id()] = nodes[i].position();
}
return nodePositions;
}
You can also restore node positions easily. You can use getElementById and node.position() functions.
function restorePositions(nodePositions) {
const nodes = cy.nodes();
const nodePositions = {};
for (let k in nodePositions) {
const node = cy.getElementById(k);
if (node && node.length > 0) {
node.position(nodePositions[k]);
}
}
return nodePositions;
}

content script heavy calculation causes poor performance (chrome extension)

I have a simple chrome extension, and I'm trying to do some page analysis through the content.js. this is the code:
console.log("content.js running.."); //debug
var fromDOM = new XMLSerializer().serializeToString(document);
console.log(fromDOM)
var i = 0;
var item;
for (item in fromDOM) {
var x = fromDOM[item];
if (x == "/"){
i++;
console.log(i);
chrome.runtime.sendMessage({lala: i});
}
}
This code searches for any occurence of "/" in the page and sends a message to a background script (that currently does nothing).
This for loop alone causes any tab I load to load slower than usual.. affecting user performance.
What am I doing wrong here? I can't do heavy lifting on content.js scripts? or is there a better way I'm missing.
Assuming you want to process the current HTML of the page:
Use document.documentElement.innerHTML
Use string methods like indexOf to get the position of each / without enumerating the long HTML string character by character.
Accumulate all the positions in an array and send it in one message since sending of a message is an expensive operation that involves internal JSON.stringify+JSON.parse.
Don't use console.log when devtools is open as it does a lot of extra processing to format the messages. And generally prefer debugging interactively - there's a panel in devtools to inspect and set breakpoints in content scripts so you can debug the code, view the variables, and so on.
const html = document.documentElement.innerHTML;
const slashes = [];
let pos = -1;
do {
pos = html.indexOf('/', pos + 1);
if (pos >= 0) {
slashes.push(pos);
}
} while (pos >= 0);
chrome.runtime.sendMessage({lala: slashes});
Now your background listener will receive an array of character positions - not really useful per se, but that's just an example. You can put more info inside the array to make it more meaningful.

Converting a PGN to a list of FEN strings in nodejs (chess notations)

I'm building a chess-related application using nodejs. I've been trying to use chess.js as much as I can but I think I've hit a roadblock in terms of functionality. Before extending that functionality, I wanted to make sure that there wasn't another tool that can do what I need.
I'm looking for a way to convert a PGN string into a list of FEN moves. I was hoping to use load_pgn() in chess.js to load the moves into the object and then loop over each move and invoke the fen() function to output the current FEN. However, chess.js doesn't seem to have a way to walk through the moves in a game. Unless I'm missing something.
I'd rather not have to get into parsing strings, but will if I have to. Any suggestions?
Solution:
also see efirvida's answer below for a solution
Something like this (untested) seems to work. The function accepts a Chess object created with chess.js that already has a PGN loaded into it.
function getMovesAsFENs(chessObj) {
var moves = chessObj.history();
var newGame = new Chess();
var fens = [];
for (var i = 0; i < moves.length; i++) {
newGame.move(moves[i]);
fens.push(newGame.fen());
}
return fens;
}
Take a look to the github page .load_pgn link
var chess = new Chess();
pgn = ['[Event "Casual Game"]',
'[Site "Berlin GER"]',
'[Date "1852.??.??"]',
'[EventDate "?"]',
'[Round "?"]',
'[Result "1-0"]',
'[White "Adolf Anderssen"]',
'[Black "Jean Dufresne"]',
'[ECO "C52"]',
'[WhiteElo "?"]',
'[BlackElo "?"]',
'[PlyCount "47"]',
'',
'1.e4 e5 2.Nf3 Nc6 3.Bc4 Bc5 4.b4 Bxb4 5.c3 Ba5 6.d4 exd4 7.O-O',
'd3 8.Qb3 Qf6 9.e5 Qg6 10.Re1 Nge7 11.Ba3 b5 12.Qxb5 Rb8 13.Qa4',
'Bb6 14.Nbd2 Bb7 15.Ne4 Qf5 16.Bxd3 Qh5 17.Nf6+ gxf6 18.exf6',
'Rg8 19.Rad1 Qxf3 20.Rxe7+ Nxe7 21.Qxd7+ Kxd7 22.Bf5+ Ke8',
'23.Bd7+ Kf8 24.Bxe7# 1-0'];
chess.load_pgn(pgn.join('\n'));
// -> true
chess.fen()
// -> 1r3kr1/pbpBBp1p/1b3P2/8/8/2P2q2/P4PPP/3R2K1 b - - 0 24
something like
moves = chess.history();
var chess1 = new Chess();
for (move in moves){
chess1.move(move);
fen = chess1.fen()
}
(Not really an answer; just a comment that needs extra formatting.)
Your getMovesAsFENs function might also be written as:
function getMovesAsFENs(chessObj) {
return chessObj.history().map(function(move) {
chessObj.move(move);
return chessObj.fen();
});
}
Perhaps it doesn't matter to you, but this appeals to my sense of neatness.
Here is an end to end answer with some ES6 sugar added in:
const Chess = require('chess.js').Chess;
const chess1 = new Chess();
const chess2 = new Chess();
const startPos = chess2.fen();
const pgn = `1.e4 c5 0-1`;
chess1.load_pgn(pgn);
let fens = chess1.history().map(move => {
chess2.move(move);
return chess2.fen();
});
//the above technique will not capture the fen of the starting position. therefore:
fens = [startPos, ...fens];
//double checking everything
fens.forEach(fen => console.log(fen));
"However, chess.js doesn't seem to have a way to walk through the
moves in a game. Unless I'm missing something.".
You are right (as I have read the entire library multiple times by now). And everything that needs to see back into the history is basically undoing and then redoing the moves, without some sort of real navigation integrated (it is an interesting choice to have it solved this way, with the pros of it being lighting fast for some tasks, but with the cons of being a real pain for other seemingly easier tasks like the one you need).
Disclaimer (I wrote the following tool), I have been creating a tool (isepic-chess.js) for the past 5+ years, something similar to chess.js and I think it's slowly getting there... The library stores the moves history in an object with information like (fen, from_square, to_square, san, etc.), and also have some kind of "cursor" with the move index and some move-navigation helpers.
So with isepic-chess.js you can just call the board method board.fenHistoryExport() to get the FEN list after you parse the PGN game:
var example_pgn = `[Event "m1 London"]
[Site "?"]
[Date "1861.07.??"]
[Round "9"]
[White "Kolisch, Ignatz"]
[Black "Anderssen, Adolf"]
[Result "0-1"]
[Annotator "JvR"]
[SetUp "1"]
[FEN "5r1k/pp4pp/3r3q/8/3PpP1P/1P2NbP1/PB1Q3K/R7 b - - 0 30"]
[PlyCount "13"]
[EventDate "1861.??.??"]
30... Rxf4 $1 {Anderssen starts fireworks.} 31. Qe1 (31.gxf4 $2 Qxh4+ 32.Kg1
Rg6+) 31... Rg6 (31...Rxh4+ $1 32.gxh4 Rg6 $1) 32. Bc1 (32.Ng2 $1) 32... Rxh4+
$1 33. gxh4 Qf4+ 34. Kh3 Bg2+ $1 35. Nxg2 Qf3+ 36. Kh2 Qxg2# { Anderssen won
the match by this mate (+4, =2, -3).} 0-1`;
var board = Ic.initBoard({
pgn : example_pgn
});
console.log(board.fenHistoryExport());
There is a more complete node.js example in the README.md with the const {Ic} = require("isepic-chess"); import thingy to have it running in node.js.

Spotify developer search

I am confused about how the search function works in the Spotify API. Their example is like this:
var sp = getSpotifyApi();
var models = sp.require('$api/models');
var search = new models.Search('Rihanna');
search.localResults = models.LOCALSEARCHRESULTS.APPEND;
var searchHTML = document.getElementById('results');
search.observe(models.EVENT.CHANGE, function() {
var results = search.tracks;
var fragment = document.createDocumentFragment();
for (var i=0; i<results.length; i++){
var link = document.createElement('li');
var a = document.createElement('a');
a.href = results[i].uri;
link.appendChild(a);
a.innerHTML = results[i].name;
fragment.appendChild(link);
}
searchHTML.appendChild(fragment);
});
search.appendNext();
So, I guess that calling appendNext() initiates the search, and the inner function is called when it has results? But the results are limited to a certain number (default 50) of the total. How do you get the rest? Do you call appendNext() again recursively from inside the callback? Also, does that mean that after you do that, your list includes the original results, or are the original results replaced? Anyone know of an example that searches through all available results?
Also they mention that if the search is running, appendNext() does nothing. So how do you gracefully wait until the current search is complete before getting the next 'page'?
Their documentation is terrible, IMHO. Say you have 1000 search results total from the server. And say I want to see results 900-1000. Have I got to keep calling AppendNext over and over until I get to 900?
Thanks
Bob
There is no pagination when using the Search functionality built in the Spotify Apps API. You can increase the number of results so it returns more than 50 results (see the Search page in the documentation), although the amount is limited (it seems to be 200 tracks at the moment).
There is an alternative way, which is performing requests to the Web API instead.

What is the most efficient method using Request.UserLanguages to render a page based on the browser language??

I am making a page which pulls from the user's browser their preferred language, via the Request.UserLanguages....which returns a two letter code (ex. "en") or detailed code (ex. "en-GB") .
I basically get the string of user languages (they are in order of preference) and store them in a string array. Then I use a loop to check if the language code in the first position of the string array is any of the codes for a certain language (another string array hard coded in).
Is there a better way to do this? I'm noticing increased load time and am worried additional languages will further slow the page load...
if (!IsPostBack)
{ //Holds possible user languages preferences to check client machine against
String[] compJapaneseLang = { "ja-jp","ja","jp","jpn","euc","shift-jis" };
}
//Get client machines langugage preferences
String[] userLang = Request.UserLanguages;
//Loop through variation of preferences from possible user langugaes
for (int i = 0; i < compJapaneseLang.Length; i++)
{
//IF JAPANESE
if (userLang.GetValue(0).ToString().ToLowerInvariant().Equals(compJapaneseLang.GetValue(i).ToString().ToLowerInvariant()))
cc.JapeneseObject();
}
Thanks!
Storing them in a list turned out best, not really much else one can do....

Resources