feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto - Configurado MCP server para Premiere Pro - Adicionado documentação e skills - Configurado Gitignore para o projeto
This commit is contained in:
Executable
+489
@@ -0,0 +1,489 @@
|
||||
import { buildToolScript, escapeForExtendScript } from "../bridge/script-builder.js";
|
||||
import { sendCommand, BridgeOptions } from "../bridge/file-bridge.js";
|
||||
|
||||
export function getMediaTools(bridgeOptions: BridgeOptions) {
|
||||
return {
|
||||
import_media: {
|
||||
description: "Import media files into the project",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
file_paths: {
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
description: "Array of file paths to import",
|
||||
},
|
||||
target_bin: {
|
||||
type: "string",
|
||||
description: "Optional bin name or node ID to import into. Imports to root if omitted.",
|
||||
},
|
||||
suppress_ui: {
|
||||
type: "boolean",
|
||||
description: "Suppress import dialogs (default: true)",
|
||||
},
|
||||
},
|
||||
required: ["file_paths"],
|
||||
},
|
||||
handler: async (args: { file_paths: string[]; target_bin?: string; suppress_ui?: boolean }) => {
|
||||
const paths = args.file_paths.map((p) => `"${escapeForExtendScript(p)}"`).join(", ");
|
||||
const suppress = args.suppress_ui !== false ? "true" : "false";
|
||||
const binLookup = args.target_bin
|
||||
? `var targetBin = __findProjectItem("${escapeForExtendScript(args.target_bin)}");
|
||||
if (!targetBin) return __error("Bin not found: ${escapeForExtendScript(args.target_bin)}");`
|
||||
: `var targetBin = app.project.rootItem;`;
|
||||
|
||||
const script = buildToolScript(`
|
||||
${binLookup}
|
||||
var filePaths = [${paths}];
|
||||
var importSuccess = app.project.importFiles(filePaths, ${suppress}, targetBin, false);
|
||||
if (!importSuccess) return __error("Import failed");
|
||||
return __result({ imported: filePaths.length, files: filePaths });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
import_folder: {
|
||||
description: "Import an entire folder of media into the project",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
folder_path: {
|
||||
type: "string",
|
||||
description: "Path to the folder to import",
|
||||
},
|
||||
},
|
||||
required: ["folder_path"],
|
||||
},
|
||||
handler: async (args: { folder_path: string }) => {
|
||||
const script = buildToolScript(`
|
||||
var folder = new Folder("${escapeForExtendScript(args.folder_path)}");
|
||||
if (!folder.exists) return __error("Folder not found: ${escapeForExtendScript(args.folder_path)}");
|
||||
|
||||
var files = folder.getFiles();
|
||||
var filePaths = [];
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
if (files[i] instanceof File) {
|
||||
filePaths.push(files[i].fsName);
|
||||
}
|
||||
}
|
||||
|
||||
if (filePaths.length === 0) return __error("No files found in folder");
|
||||
|
||||
var importSuccess = app.project.importFiles(filePaths, true, app.project.rootItem, false);
|
||||
if (!importSuccess) return __error("Import failed");
|
||||
return __result({ imported: filePaths.length, folder: "${escapeForExtendScript(args.folder_path)}" });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
create_bin: {
|
||||
description: "Create a new bin (folder) in the project panel",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
name: {
|
||||
type: "string",
|
||||
description: "Name of the new bin",
|
||||
},
|
||||
parent_bin: {
|
||||
type: "string",
|
||||
description: "Optional parent bin name or node ID. Creates in root if omitted.",
|
||||
},
|
||||
},
|
||||
required: ["name"],
|
||||
},
|
||||
handler: async (args: { name: string; parent_bin?: string }) => {
|
||||
const parentLookup = args.parent_bin
|
||||
? `var parent = __findProjectItem("${escapeForExtendScript(args.parent_bin)}");
|
||||
if (!parent) return __error("Parent bin not found");`
|
||||
: `var parent = app.project.rootItem;`;
|
||||
|
||||
const script = buildToolScript(`
|
||||
${parentLookup}
|
||||
var newBin = parent.createBin("${escapeForExtendScript(args.name)}");
|
||||
return __result({ created: true, name: "${escapeForExtendScript(args.name)}", nodeId: newBin.nodeId });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
move_item_to_bin: {
|
||||
description: "Move a project item to a different bin",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the item to move",
|
||||
},
|
||||
target_bin: {
|
||||
type: "string",
|
||||
description: "Name or node ID of the target bin",
|
||||
},
|
||||
},
|
||||
required: ["item_id", "target_bin"],
|
||||
},
|
||||
handler: async (args: { item_id: string; target_bin: string }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found: ${escapeForExtendScript(args.item_id)}");
|
||||
|
||||
var targetBin = __findProjectItem("${escapeForExtendScript(args.target_bin)}");
|
||||
if (!targetBin) return __error("Target bin not found: ${escapeForExtendScript(args.target_bin)}");
|
||||
|
||||
item.moveBin(targetBin);
|
||||
return __result({ moved: true, item: item.name, toBin: targetBin.name });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
relink_media: {
|
||||
description: "Relink an offline media item to a new file path",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the item to relink",
|
||||
},
|
||||
new_path: {
|
||||
type: "string",
|
||||
description: "New file path for the media",
|
||||
},
|
||||
},
|
||||
required: ["item_id", "new_path"],
|
||||
},
|
||||
handler: async (args: { item_id: string; new_path: string }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found: ${escapeForExtendScript(args.item_id)}");
|
||||
|
||||
var success = item.changeMediaPath("${escapeForExtendScript(args.new_path)}", true);
|
||||
return __result({ relinked: success, item: item.name, newPath: "${escapeForExtendScript(args.new_path)}" });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
refresh_media: {
|
||||
description: "Refresh a project item to pick up changes to the source file",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the item to refresh",
|
||||
},
|
||||
},
|
||||
required: ["item_id"],
|
||||
},
|
||||
handler: async (args: { item_id: string }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found: ${escapeForExtendScript(args.item_id)}");
|
||||
item.refreshMedia();
|
||||
return __result({ refreshed: true, item: item.name });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
check_offline_media: {
|
||||
description: "Check for offline (missing) media in the project",
|
||||
parameters: {},
|
||||
handler: async () => {
|
||||
const script = buildToolScript(`
|
||||
var offlineItems = [];
|
||||
|
||||
function checkItem(item) {
|
||||
if (item.type === 1) {
|
||||
try {
|
||||
if (item.isOffline && item.isOffline()) {
|
||||
offlineItems.push({
|
||||
nodeId: item.nodeId,
|
||||
name: item.name,
|
||||
mediaPath: item.getMediaPath ? item.getMediaPath() : ""
|
||||
});
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
if (item.type === 2 && item.children) {
|
||||
for (var i = 0; i < item.children.numItems; i++) {
|
||||
checkItem(item.children[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var root = app.project.rootItem;
|
||||
for (var i = 0; i < root.children.numItems; i++) {
|
||||
checkItem(root.children[i]);
|
||||
}
|
||||
|
||||
return __result({ offlineCount: offlineItems.length, items: offlineItems });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
set_offline: {
|
||||
description: "Set a project item offline, or ask Premiere to refresh it back online when offline is false.",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the project item",
|
||||
},
|
||||
offline: {
|
||||
type: "boolean",
|
||||
description: "true to take media offline (default); false to refresh an existing offline item",
|
||||
},
|
||||
},
|
||||
required: ["item_id"],
|
||||
},
|
||||
handler: async (args: { item_id: string; offline?: boolean }) => {
|
||||
const offline = args.offline !== false;
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found: ${escapeForExtendScript(args.item_id)}");
|
||||
${offline
|
||||
? `item.setOffline();`
|
||||
: `item.refreshMedia();`
|
||||
}
|
||||
var observedOffline = !!item.isOffline();
|
||||
if (observedOffline !== ${offline}) {
|
||||
return __error(${offline
|
||||
? `"Premiere did not take the project item offline."`
|
||||
: `"Premiere could not refresh this item online. Use relink_media with the known media path if the source has moved."`
|
||||
});
|
||||
}
|
||||
return __result({ offline: observedOffline, item: item.name, verified: true });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
has_proxy: {
|
||||
description: "Check if a project item has a proxy attached",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the project item",
|
||||
},
|
||||
},
|
||||
required: ["item_id"],
|
||||
},
|
||||
handler: async (args: { item_id: string }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found");
|
||||
|
||||
var info = { item: item.name };
|
||||
try { info.hasProxy = item.hasProxy(); } catch(e) { info.hasProxy = false; }
|
||||
try { info.canProxy = item.canProxy(); } catch(e) { info.canProxy = false; }
|
||||
try { info.proxyPath = item.getProxyPath(); } catch(e) {}
|
||||
|
||||
return __result(info);
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
detach_proxy: {
|
||||
description: "Detach/remove the proxy from a project item",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the project item",
|
||||
},
|
||||
},
|
||||
required: ["item_id"],
|
||||
},
|
||||
handler: async (args: { item_id: string }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found");
|
||||
item.detachProxy();
|
||||
return __result({ detached: true, item: item.name });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
set_override_frame_rate: {
|
||||
description: "Override the frame rate of a project item (useful for image sequences or misinterpreted media)",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the project item",
|
||||
},
|
||||
frame_rate: {
|
||||
type: "number",
|
||||
description: "Frame rate to set (e.g., 23.976, 24, 29.97, 30, 60)",
|
||||
},
|
||||
},
|
||||
required: ["item_id", "frame_rate"],
|
||||
},
|
||||
handler: async (args: { item_id: string; frame_rate: number }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found");
|
||||
item.setOverrideFrameRate(${args.frame_rate});
|
||||
return __result({ set: true, item: item.name, frameRate: ${args.frame_rate} });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
set_override_pixel_aspect_ratio: {
|
||||
description: "Override the pixel aspect ratio of a project item",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the project item",
|
||||
},
|
||||
numerator: {
|
||||
type: "number",
|
||||
description: "PAR numerator (e.g., 1 for square pixels)",
|
||||
},
|
||||
denominator: {
|
||||
type: "number",
|
||||
description: "PAR denominator (e.g., 1 for square pixels)",
|
||||
},
|
||||
},
|
||||
required: ["item_id", "numerator", "denominator"],
|
||||
},
|
||||
handler: async (args: { item_id: string; numerator: number; denominator: number }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found");
|
||||
item.setOverridePixelAspectRatio(${args.numerator}, ${args.denominator});
|
||||
return __result({ set: true, item: item.name, par: "${args.numerator}:${args.denominator}" });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
set_scale_to_frame_size: {
|
||||
description: "Enable 'Scale to Frame Size' on a project item so it fills the sequence frame",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the project item",
|
||||
},
|
||||
},
|
||||
required: ["item_id"],
|
||||
},
|
||||
handler: async (args: { item_id: string }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found");
|
||||
item.setScaleToFrameSize();
|
||||
return __result({ set: true, item: item.name });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
get_item_info: {
|
||||
description: "Get detailed type info about a project item (is it a sequence, multicam, merged clip, etc.)",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the project item",
|
||||
},
|
||||
},
|
||||
required: ["item_id"],
|
||||
},
|
||||
handler: async (args: { item_id: string }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found");
|
||||
|
||||
var info = {
|
||||
name: item.name,
|
||||
nodeId: item.nodeId,
|
||||
type: item.type === 1 ? "clip" : item.type === 2 ? "bin" : item.type === 3 ? "sequence" : "unknown",
|
||||
treePath: item.treePath
|
||||
};
|
||||
try { info.isSequence = item.isSequence(); } catch(e) {}
|
||||
try { info.isMulticamClip = item.isMulticamClip(); } catch(e) {}
|
||||
try { info.isMergedClip = item.isMergedClip(); } catch(e) {}
|
||||
try { info.isOffline = item.isOffline(); } catch(e) {}
|
||||
try { info.mediaPath = item.getMediaPath(); } catch(e) {}
|
||||
try { info.hasProxy = item.hasProxy(); } catch(e) {}
|
||||
try { info.canProxy = item.canProxy(); } catch(e) {}
|
||||
|
||||
return __result(info);
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
select_item: {
|
||||
description: "Select a project item in the Project panel",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the project item to select",
|
||||
},
|
||||
},
|
||||
required: ["item_id"],
|
||||
},
|
||||
handler: async (args: { item_id: string }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found");
|
||||
item.select();
|
||||
return __result({ selected: true, item: item.name });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
|
||||
set_start_time: {
|
||||
description: "Set the start time (timecode offset) for a project item",
|
||||
parameters: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
item_id: {
|
||||
type: "string",
|
||||
description: "Node ID or name of the project item",
|
||||
},
|
||||
start_seconds: {
|
||||
type: "number",
|
||||
description: "Start time in seconds",
|
||||
},
|
||||
},
|
||||
required: ["item_id", "start_seconds"],
|
||||
},
|
||||
handler: async (args: { item_id: string; start_seconds: number }) => {
|
||||
const script = buildToolScript(`
|
||||
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
||||
if (!item) return __error("Item not found");
|
||||
|
||||
var ticks = __secondsToTicks(${args.start_seconds}).toString();
|
||||
item.setStartTime(ticks);
|
||||
return __result({ set: true, item: item.name, startSeconds: ${args.start_seconds} });
|
||||
`);
|
||||
return sendCommand(script, bridgeOptions);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user