• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

How to detect if project has unsaved changes?

Explorer ,
Jun 01, 2020 Jun 01, 2020

Copy link to clipboard

Copied

I need to test if there are unsaved changes to the project in the After Effects application. Is there any way to do that? I get really close with this hacky solution -- save the project to a temp location and compare it to the current project:

 

function projectHasUnsavedChanges() {
  if (!app.project || !app.project.file) {
    return false;
  }
  var currentFile = app.project.file;
  // create_uuid pulled from https://stackoverflow.com/questions/105034/how-to-create-guid-uuid
  var tempProjectFile = new File(Folder.temp.fsName + '/' + create_uuid() + '.tmp.aep');
  app.project.save(tempProjectFile);
  var filesIdentical = byte_compare_files(tempProjectFile, currentFile);
  tempProjectFile.remove();
  return !filesIdentical;
}

 

This solution has a huge side-effect making it unacceptable. Basically whenever .save() is called, it changes the After Effects active project file to the saved location. Furthermore it adds the saved file to the recent history. Given I am just trying to do a test for unsaved changes, this doesn't work.

Are there any other options out there?

Thanks!

TOPICS
FAQ , How to , Scripting

Views

1.5K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 01, 2020 Jun 01, 2020

Copy link to clipboard

Copied

AEGP_ProjectIsDirty ?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jun 01, 2020 Jun 01, 2020

Copy link to clipboard

Copied

Thank you for the reference. But how do I leverage this from ExtendScript, i.e. via ExternalObject or something?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 01, 2020 Jun 01, 2020

Copy link to clipboard

Copied

either an ExternalObject or if you already have an AEGP running you could have it check the flag in idle hook and write it's status to a javascript global.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jun 01, 2020 Jun 01, 2020

Copy link to clipboard

Copied

I do not have an AEGP running. My project is just an extension with Script UI, so I would be trying to invoke AEGP_ProjectIsDirty from ExtendScript. But how to do that? For example, I don't know what to put in ExternalObject:

// Completely non-working and invalid code...
var projectSuite6 = new ExternalObject('lib:?AEGP_ProjSuite6?');
var project = projectSuite6.AEGP_GetProjectProjectByIndex(0);
var isDirty = project.AEGP_ProjectIsDirty();

Thanks

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 01, 2020 Jun 01, 2020

Copy link to clipboard

Copied

you'll need to compile an external object handling dll, which would put you in the C realm anyways...

AEGP calls are accessible only via the C API, so unless you're willing to travel that road i guess that's not a valid solution for you.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 01, 2020 Jun 01, 2020

Copy link to clipboard

Copied

here's a hacky thought:
through javascript, do a system call like this:
tasklist /v /fo list /fi "imagename eq afterfx*"| find /i "window title:"

it will retreive the name text of the title of AE's window. if the name ends with an asterix then the project has unsaved changed.

(the command i showed here is very slow. perhaps there's a faster way to find AE's process)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jun 01, 2020 Jun 01, 2020

Copy link to clipboard

Copied

Thanks so much for the information. I am open to using a hack but the problem is it must work on a Mac as well -- which is why I am resistant to jumping into C as well. Bummer. 😞

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 01, 2020 Jun 01, 2020

Copy link to clipboard

Copied

that wasn't a C solution. it was purely javascript.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jun 01, 2020 Jun 01, 2020

Copy link to clipboard

Copied

The tasklist solution was javascript, yes. But it still won't work on Mac.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jun 02, 2020 Jun 02, 2020

Copy link to clipboard

Copied

I figured out a way, sort of, to do this. I am hoping to get feedback on it's viability and maybe a way to improve the idea. It takes advantage of three facts:

 

  1. app.project.file is falsy when a project is not loaded, and truthy when a project is loaded.
  2. app.project.revision is updated every time a change is made.
  3. XMP's 'ModifyDate' is updated every time the project file is saved.

 

Armed with this information, I can keep track of what revision the project has when the project is saved:

 

 

var projectState = (function () {
  var xmpLib = new ExternalObject('lib:AdobeXMPScript');
  var currentModifyDate;
  var revisionWhenReadModifyDate;
  var currentState;

  function getState() {
    return currentState;
  }

  function update() {
    var actualModifyDate = readModifyDateFromXmp();
    var actualRevision = (app.project && app.project.revision) || undefined;
    if (actualModifyDate !== currentModifyDate) {
      currentModifyDate = actualModifyDate;
      revisionWhenReadModifyDate = actualRevision;
    }
    // 0 = project not loaded, 1 = project loaded with no changes, 2 = project loaded with changes
    currentState = !currentModifyDate ? 0 : ((revisionWhenReadModifyDate === actualRevision) ? 1 : 2);
  }

  function readModifyDateFromXmp() {
    if (!app.project || !app.project.file || !app.project.xmpPacket) {
      return undefined;
    }
    var xmpMeta = new XMPMeta(app.project.xmpPacket);
    return xmpMeta.getProperty(XMPConst.NS_XMP, 'ModifyDate').toString();
  }

  return {
    getState: getState,
    update: update
  };
})();

 

 

The major drawback here is I need read the project revision immediately when the project is saved or opened. I cannot find events for either of these, so in order to keep the state up to date I need to poll projectState.update() every second or so. If I had events for project saving and opening that would solve the problem, I think. But if I do that, then I projectState.getState() gives me an accurate reading of 'dirty' state. There is of course a race condition that if the user saves the file and makes a quick modification before projectState.update() is called, the state will be incorrect. Events for project save or opened would solve that as well...

 

Oh also, if the extension is started while the project state is dirty, the result will be inaccurate also. So this doesn't totally work, but it gets close.

 

Thoughts?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Oct 23, 2023 Oct 23, 2023

Copy link to clipboard

Copied

Sorry to revive such an old post, but do you have any suggestions regarding building an externalobject with AEGP functionality?

Everything I seem to be trying isn't working, and I think its related to establishing that initial connection with AE.

For a test I'm simply trying to run AEGP_executeScript, but the code fails without exception when I try to set my SuiteHandler like I would in an actual AEGP. 
```

    sP = pica_basicP;
   AEGP_SuiteHandler suites(sP); <---- Doesn't get past here
```

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Oct 24, 2023 Oct 24, 2023

Copy link to clipboard

Copied

LATEST

can you elborate on that snippet in some wider context? it's impossible to tell by these two lines...

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines