Advertisement
Guest User

Select Keyframes Script

a guest
Mar 5th, 2025
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.11 KB | None | 0 0
  1. (function selectSpecifiedKeyframes() {
  2. // Ensure an active composition and at least one selected layer.
  3. var comp = app.project.activeItem;
  4. if (!(comp && comp instanceof CompItem)) {
  5. alert("Please select a composition.");
  6. return;
  7. }
  8. var layers = comp.selectedLayers;
  9. if (layers.length === 0) {
  10. alert("Please select at least one layer.");
  11. return;
  12. }
  13.  
  14. // Helper function: recursively gather properties that have keyframes.
  15. function gatherKeyframedProperties(propGroup, propSet) {
  16. for (var i = 1; i <= propGroup.numProperties; i++) {
  17. var prop = propGroup.property(i);
  18. if (prop.canSetExpression && prop.numKeys && prop.numKeys > 0) {
  19. propSet[prop.name] = true;
  20. }
  21. if (prop.propertyType === PropertyType.NAMED_GROUP || prop.propertyType === PropertyType.INDEXED_GROUP) {
  22. gatherKeyframedProperties(prop, propSet);
  23. }
  24. }
  25. }
  26.  
  27. // Build a list of property names (from selected layers) that have keyframes.
  28. var keyframedProps = {};
  29. for (var l = 0; l < layers.length; l++) {
  30. gatherKeyframedProperties(layers[l], keyframedProps);
  31. }
  32. var propNames = [];
  33. for (var name in keyframedProps) {
  34. propNames.push(name);
  35. }
  36. if (propNames.length === 0) {
  37. alert("No keyframed properties found in the selected layers.");
  38. return;
  39. }
  40.  
  41. // Create the dialog for property and keyframe option selection.
  42. var dlg = new Window("dialog", "Select Property and Keyframe");
  43. dlg.orientation = "column";
  44. dlg.alignChildren = "left";
  45.  
  46. dlg.add("statictext", undefined, "Select a property:");
  47. var propDropdown = dlg.add("dropdownlist", undefined, propNames);
  48. propDropdown.selection = 0;
  49.  
  50. dlg.add("statictext", undefined, "Select keyframe option:");
  51. var keyframeDropdown = dlg.add("dropdownlist", undefined, ["First", "Last", "Middle", "Range"]);
  52. keyframeDropdown.selection = 0;
  53.  
  54. // Range input group – only visible when "Range" is selected.
  55. var rangeGroup = dlg.add("group", undefined, "Range Inputs");
  56. rangeGroup.orientation = "row";
  57. rangeGroup.alignChildren = "center";
  58. rangeGroup.add("statictext", undefined, "From:");
  59. var rangeFrom = rangeGroup.add("edittext", undefined, "1");
  60. rangeFrom.characters = 3;
  61. rangeGroup.add("statictext", undefined, "To:");
  62. var rangeTo = rangeGroup.add("edittext", undefined, "1");
  63. rangeTo.characters = 3;
  64. rangeGroup.visible = false;
  65.  
  66. keyframeDropdown.onChange = function() {
  67. rangeGroup.visible = (keyframeDropdown.selection.text === "Range");
  68. };
  69.  
  70. var continueBtn = dlg.add("button", undefined, "Continue", {name:"ok"});
  71. continueBtn.onClick = function() {
  72. dlg.close();
  73. };
  74. dlg.show();
  75.  
  76. // Get user selections.
  77. var selectedPropertyName = propDropdown.selection.text;
  78. var keyframeOption = keyframeDropdown.selection.text;
  79.  
  80. var rangeStart, rangeEnd;
  81. if (keyframeOption === "Range") {
  82. rangeStart = parseInt(rangeFrom.text, 10);
  83. rangeEnd = parseInt(rangeTo.text, 10);
  84. if (isNaN(rangeStart) || isNaN(rangeEnd) || rangeStart < 1 || rangeEnd < rangeStart) {
  85. showMessage("Invalid range input!");
  86. return;
  87. }
  88. }
  89.  
  90. // Helper function: check if a keyframe is a hold keyframe.
  91. function isHoldKeyframe(prop, index) {
  92. try {
  93. return (prop.keyInInterpolationType(index) === KeyframeInterpolationType.HOLD ||
  94. prop.keyOutInterpolationType(index) === KeyframeInterpolationType.HOLD);
  95. } catch (e) {
  96. return false;
  97. }
  98. }
  99.  
  100. app.beginUndoGroup("Select Specified Keyframes");
  101.  
  102. var anyValid = false;
  103. var someMissing = false;
  104.  
  105. // Process each selected layer.
  106. for (var i = 0; i < layers.length; i++) {
  107. var foundProp = findPropertyByName(layers[i], selectedPropertyName);
  108. if (foundProp) {
  109. var numKeys = foundProp.numKeys;
  110. // Deselect all keyframes.
  111. for (var k = 1; k <= numKeys; k++) {
  112. foundProp.setSelectedAtKey(k, false);
  113. }
  114. var indicesToSelect = [];
  115. if (keyframeOption === "First") {
  116. if (numKeys >= 1) { indicesToSelect.push(1); }
  117. else { someMissing = true; }
  118. } else if (keyframeOption === "Last") {
  119. if (numKeys >= 1) { indicesToSelect.push(numKeys); }
  120. else { someMissing = true; }
  121. } else if (keyframeOption === "Middle") {
  122. if (numKeys > 2) {
  123. for (var j = 2; j < numKeys; j++) { indicesToSelect.push(j); }
  124. } else { someMissing = true; }
  125. } else if (keyframeOption === "Range") {
  126. if (numKeys >= rangeEnd) {
  127. for (var r = rangeStart; r <= rangeEnd; r++) { indicesToSelect.push(r); }
  128. } else { someMissing = true; }
  129. }
  130. if (indicesToSelect.length > 0) {
  131. // For each index to select, if it's a hold keyframe, temporarily convert it to linear.
  132. var holdData = {}; // Store original interpolation data.
  133. for (var idx = 0; idx < indicesToSelect.length; idx++) {
  134. var kIndex = indicesToSelect[idx];
  135. if (isHoldKeyframe(foundProp, kIndex)) {
  136. var origIn = foundProp.keyInInterpolationType(kIndex);
  137. var origOut = foundProp.keyOutInterpolationType(kIndex);
  138. holdData[kIndex] = { origIn: origIn, origOut: origOut };
  139. foundProp.setInterpolationTypeAtKey(kIndex, KeyframeInterpolationType.LINEAR, KeyframeInterpolationType.LINEAR);
  140. }
  141. foundProp.setSelectedAtKey(kIndex, true);
  142. }
  143. // Now revert any hold keyframes back to their original interpolation.
  144. for (var idx in holdData) {
  145. var indexNum = parseInt(idx, 10);
  146. var data = holdData[idx];
  147. foundProp.setInterpolationTypeAtKey(indexNum, data.origIn, data.origOut);
  148. }
  149. anyValid = true;
  150. }
  151. } else {
  152. someMissing = true;
  153. }
  154. }
  155.  
  156. app.endUndoGroup();
  157.  
  158. var totalSelected = 0;
  159. for (var i = 0; i < layers.length; i++) {
  160. var prop = findPropertyByName(layers[i], selectedPropertyName);
  161. if (prop) {
  162. totalSelected += prop.selectedKeys.length;
  163. }
  164. }
  165. if (totalSelected === 0) {
  166. throw new Error("No keyframes ended up being selected even though keyframes exist.");
  167. }
  168.  
  169. // Provide feedback.
  170. if (!anyValid) {
  171. showMessage("No Keyframes Found!");
  172. } else if (someMissing) {
  173. showMessage("Some layers are missing keyframes!");
  174. } else {
  175. showMessage("Task Complete!");
  176. }
  177.  
  178.  
  179.  
  180. // Recursive function to find a property by name (case-insensitive).
  181. function findPropertyByName(propGroup, nameToFind) {
  182. for (var j = 1; j <= propGroup.numProperties; j++) {
  183. var prop = propGroup.property(j);
  184. if (prop.name.toLowerCase() === nameToFind.toLowerCase()) {
  185. return prop;
  186. }
  187. if (prop.propertyType === PropertyType.NAMED_GROUP || prop.propertyType === PropertyType.INDEXED_GROUP) {
  188. var found = findPropertyByName(prop, nameToFind);
  189. if (found) { return found; }
  190. }
  191. }
  192. return null;
  193. }
  194.  
  195. // Function to display a dialog with a "Continue" button.
  196. function showMessage(msg) {
  197. var win = new Window("dialog", "Notification");
  198. win.orientation = "column";
  199. win.alignChildren = "center";
  200. win.add("statictext", undefined, msg);
  201. var btn = win.add("button", undefined, "Continue");
  202. btn.onClick = function() { win.close(); };
  203. win.show();
  204. }
  205. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement