Skip to content

Commit

Permalink
feat: export to pr project
Browse files Browse the repository at this point in the history
  • Loading branch information
zcf0508 committed Nov 20, 2022
1 parent 7095fc9 commit 273971b
Show file tree
Hide file tree
Showing 12 changed files with 524 additions and 23 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ dist-ssr
release
.vscode/.debug.env
dist-electron

# ignore adobe esdebugger core file
**/adobe-lib/**
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
- [x] 选择视频文件并生成字幕页面
- [x] 字幕剪辑页面
- [x] 导出视频
- [ ] 编辑结果导入到 Pr 中
- [x] 编辑结果导入到 Pr 中
- [ ] 剪辑视频预览
- [ ] 字幕编辑修改
- [ ] Mac 系统支持
- [ ] i18n
Expand Down
5 changes: 5 additions & 0 deletions electron-builder.json5
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
"directories": {
"output": "release/${version}"
},
extraResources: {
from: './public/resources',
to: './'
},
"files": [
"adobe-lib",
"dist-electron",
"dist"
],
Expand Down
259 changes: 259 additions & 0 deletions electron/adobe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
import path from "path"
import * as fs from "fs"

const prod = import.meta.env.PROD

type EXTENSION_SPEC_NAME = "vscesd";
type CoreLib = {
/**
* 初始化, 返回值为 0 时表示成功
*/
esdInitialize: (name: EXTENSION_SPEC_NAME, processId: number) => {status: number};
/**
* 获取已安装应用的 spec
*/
esdGetInstalledApplicationSpecifiers: () => {status: number, specifiers: Array<string>};
/**
* 通过 spec 获取应用名称
*/
esdGetDisplayNameForApplication: (spec: string) => {status:number, name: string};
/**
* 检查指定程序是否正在运行
*/
esdGetApplicationRunning:(spen: string) => {status:number, isRunning: string};
/**
* 转换文件地址格式
*/
esdPathToUri:(path: string)=> {status:number, uri: string};
/**
* 发送调试信息,运行 jsx
*/
esdSendDebugMessage: (
appSpecifier: string,
body: string,
bringToFront: boolean,
timeout: number
) => {status: number, serialNumber: number};
/**
* 清理
*/
esdCleanup: () => {status: number};
}

let coreLib = undefined as CoreLib

function GetCoreLib() {
if (coreLib === undefined) {
const platform = process.platform;
let core = undefined;
if (platform === "darwin") {
core = require("../../adobe-lib/esdebugger-core/mac/esdcorelibinterface.node");
}
else if (platform === "win32") {
const arch = process.arch;
if (arch === "x64" || arch === "arm64") {
core = require("../../adobe-lib/esdebugger-core/win/x64/esdcorelibinterface.node");
}
else {
core = require("../../adobe-lib/esdebugger-core/win/win32/esdcorelibinterface.node");
}
}
if (core === undefined) {
throw new Error("Could not initialize Core Library! Is this running on a supported platform?");
}

coreLib = core
}
return coreLib;
}

// 初始化 core
function initCore(){
return new Promise<CoreLib>((resolve, reject) => {
const core = GetCoreLib();
console.log(core.esdCleanup().status)
const result = core.esdInitialize("vscesd", process.pid);
console.log("init result " + result.status)
if (result.status === 0 || result.status === 11) {
resolve(core)
} else {
reject()
}
})
}


function createPrProject(targetDir: string, videoPath: string){
const videoName = path.basename(videoPath).slice(
0,
path.basename(videoPath).indexOf(".") || path.basename(videoPath).length,
)
const tempFile = path.join(
prod ? process.resourcesPath : path.join(__dirname, "../../public/resources"),
"temp.prproj",
)
try{
!fs.existsSync(targetDir) && fs.mkdirSync(targetDir)
// 复制到目标文件夹中
fs.copyFileSync(tempFile, path.join(targetDir, videoName + ".prproj"))
fs.copyFileSync(videoPath, path.join(targetDir, path.basename(videoPath)))
return {
proj: path.join(targetDir, videoName + ".prproj"),
video: path.join(targetDir, path.basename(videoPath)),
}
}catch(e){
console.error(e)
return ""
}
}


// 生成 jsx 文件
function createJsxFile(
targetDir: string, proj: string, videoFile: string, srtFile: string, clipPoints: Array<string>,
) {
let jsxTemplate = fs.readFileSync(
path.join(prod ? process.resourcesPath : path.join(__dirname, "../../public/resources"), "./autocut.jsx.template"),
"utf-8",
)

jsxTemplate = jsxTemplate.replace("{{projPath}}", proj.replaceAll("\\","\\\\"))
jsxTemplate = jsxTemplate.replace("{{videoPath}}", videoFile.replaceAll("\\","\\\\"))
jsxTemplate = jsxTemplate.replace("{{srtPath}}", srtFile.replaceAll("\\","\\\\"))
jsxTemplate = jsxTemplate.replace("{{clipPoints}}", clipPoints.join(","))

fs.writeFileSync(path.join(targetDir, "autocut.jsx"), jsxTemplate)

return path.join(targetDir, "autocut.jsx")
}


export async function exportToPr(
targetDir: string,
videoFile: string,
srtFile: string,
clipPoints: Array<string>,
spec:string,
cb:(status: string, msg: string) => any,
) {
const { proj, video } = createPrProject(targetDir, videoFile)
if(!proj){
cb("error", "项目创建失败")
return
}
const jsx = createJsxFile(targetDir, proj, video, srtFile, clipPoints)
if(!jsx){
cb("error", "脚本创建失败")
return
}

const core = await initCore()
// eslint-disable-next-line max-len
const body = `<eval engine="main" file="${core.esdPathToUri(jsx).uri}" debug="0"><source><![CDATA[${fs.readFileSync(jsx)}]]></source></eval>`
const result = core.esdSendDebugMessage(spec, body, true, 0)
core.esdCleanup()
if(result.status!==0) {
cb("error", "脚本运行失败")
return
}
cb("success", "")
}

const prVersions = [
{
specifier: "premierepro-23.0",
name: "Adobe Premiere Pro CC 2023",
},
{
specifier: "premierepro-22.0",
name: "Adobe Premiere Pro CC 2022",
},
{
specifier: "premierepro-15.0",
name: "Adobe Premiere Pro CC 2021",
},
{
specifier: "premierepro-14.3",
name: "Adobe Premiere Pro CC 2020",
},
{
specifier: "premierepro-14.0",
name: "Adobe Premiere Pro CC 2020",
},
{
specifier: "premierepro-13.1.5",
name: "Adobe Premiere Pro CC 2019",
},
{
specifier: "premierepro-13.1.4",
name: "Adobe Premiere Pro CC 2019",
},
{
specifier: "premierepro-13.1.3",
name: "Adobe Premiere Pro CC 2019",
},
{
specifier: "premierepro-13.1.2",
name: "Adobe Premiere Pro CC 2019",
},
{
specifier: "premierepro-13.1.1",
name: "Adobe Premiere Pro CC 2019",
},
{
specifier: "premierepro-13.1",
name: "Adobe Premiere Pro CC 2019",
},
{
specifier: "premierepro-13.0",
name: "Adobe Premiere Pro CC 2019",
},
{
specifier: "premierepro-12.0",
name: "Adobe Premiere Pro CC 2019",
},
{
specifier: "premierepro-11.0",
name: "Adobe Premiere Pro CC 2017",
},
]

export async function getSpec() {
let appDefs = [] as Array<{
specifier: string,
name:string
}>
const core = await initCore()
const res = core.esdGetInstalledApplicationSpecifiers()

if(res.status === 0) {
let specifiers = res.specifiers
if(specifiers.length === 0){
const installedProDir = path.join(process.env.APPDATA, "/Adobe/Premiere Pro")
fs.readdirSync(installedProDir).forEach((dir) => {
if(!isNaN(Number(dir.replaceAll(".", "")))){
specifiers.push(`premierepro-${dir}`)
}
})
}
specifiers.map((spec) => {
const result = core.esdGetDisplayNameForApplication(spec);
if (result.status === 0) {
if(result.name.indexOf("Adobe Premiere Pro") >= 0){
appDefs.push({
specifier: spec,
name: result.name,
})
} else {
prVersions.map(item=>{
if(item.specifier === spec){
appDefs.push(item)
}
})
}
}
})
}
core.esdCleanup()
return appDefs
}
27 changes: 27 additions & 0 deletions electron/main/autocut.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BrowserWindow, ipcMain, dialog } from "electron"
import { exportToPr, getSpec } from "../adobe"
import { cutVideo, generateSubtitle } from "../autocut"
import { autocutCheck, ffmpegCheck } from "../autocut/check"
import { downloadAutoCut } from "../autocut/download"
Expand Down Expand Up @@ -87,4 +88,30 @@ export function registerAutoCut(win: BrowserWindow){
})
})
})

ipcMain.on("check-pr-versions", async (e,...args) => {
const version = await getSpec()
e.reply("report-pr-versions", version)
})

ipcMain.handle("select-prproj-save-directory", async (e, ...args) => {
const res = await dialog.showOpenDialog(win, {
title: "请选择 Pr 工程路径",
properties: ["openDirectory", "createDirectory"],

})
return res
})

ipcMain.on("export-to-pr", (e,...args) => {
const targetDir = args[0] as string
const videoFile = args[1] as string
const srtFile = args[2] as string
const clipPoints = args[3] as Array<string>
const spec = args[4] as string

exportToPr(targetDir, videoFile, srtFile, clipPoints, spec, (status, msg)=>{
console.log(status)
})
})
}
41 changes: 41 additions & 0 deletions public/resources/autocut.jsx.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
var projPath = "{{projPath}}";
var videoPath = "{{videoPath}}";
var srtPath = "{{srtPath}}";
var clipPoints = "{{clipPoints}}".split(",");


app.enableQE();

app.openDocument(projPath);
var root = app.project.rootItem;
app.project.createNewSequence("序列 01", "seq01");

app.project.importFiles([videoPath]);
var video = root.children[1];
var seq = app.project.activeSequence;
var time = seq.zeroPoint;
seq.videoTracks[0].insertClip(video, time);
// 获取视频轨道
var videoTrack = qe.project.getActiveSequence().getVideoTrackAt(0);
for (var i = 0; i < clipPoints.length; i++) {
var point = new Time()
point.seconds = Number(clipPoints[i])
videoTrack.razor(
point.getFormatted(seq.getSettings().videoFrameRate, seq.getSettings().videoDisplayFormat),
true,
true
);
}

app.project.importFiles([srtPath]);
var srt = root.children[2];
var seq = app.project.activeSequence;
var time = seq.zeroPoint;
seq.videoTracks[1].insertClip(srt, time);
// 获取字幕轨道
var srtTrack = qe.project.getActiveSequence().getVideoTrackAt(1);
for (var i = 0; i < clipPoints.length; i++) {
var point = new Time()
point.seconds = Number(clipPoints[i])
srtTrack.razor(point.getFormatted(seq.getSettings().videoFrameRate, seq.getSettings().videoDisplayFormat), true, true);
}
Binary file added public/resources/temp.prproj
Binary file not shown.
1 change: 1 addition & 0 deletions src/auto-import.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ declare global {
const usePermission: typeof import('@vueuse/core')['usePermission']
const usePointer: typeof import('@vueuse/core')['usePointer']
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
const usePrVersions: typeof import('./hooks/usePrVersions')['usePrVersions']
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
Expand Down
Loading

0 comments on commit 273971b

Please sign in to comment.