Compare commits
3 Commits
13cd51fa28
...
51383ca07f
Author | SHA1 | Date | |
---|---|---|---|
|
51383ca07f | ||
|
7d063ad8fd | ||
|
84cd5014dc |
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "kdenlive",
|
"name": "kdenlive",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "kdenlive",
|
"name": "kdenlive",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"zx": "^4.2.0"
|
"zx": "^4.2.0"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "kdenlive",
|
"name": "kdenlive-ts",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"description": "Create kdenlive projects from within JS",
|
"description": "Create kdenlive projects from within JS",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -9,7 +9,8 @@
|
|||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
"test-reports": "npm run build && rm -fr .xunit coverage && npm run test -- --cover --test-report"
|
"test-reports": "npm run build && rm -fr .xunit coverage && npm run test -- --cover --test-report"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "Kuba Orlik",
|
||||||
|
"repository": "https://git.internet-czas-dzialac.pl/icd/kdenlive-ts",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mocha": "^9.0.0",
|
"@types/mocha": "^9.0.0",
|
||||||
|
33
src/entry.ts
Normal file
33
src/entry.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Producer } from "./producer";
|
||||||
|
|
||||||
|
export abstract class Entry {
|
||||||
|
abstract toXML(): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MediaEntry extends Entry {
|
||||||
|
constructor(
|
||||||
|
public producer: Producer,
|
||||||
|
public in_point: string,
|
||||||
|
public out_point: string
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
toXML(): string {
|
||||||
|
return /* HTML */ `<entry
|
||||||
|
producer="${this.producer.id}"
|
||||||
|
in="${this.in_point}"
|
||||||
|
out="${this.out_point}"
|
||||||
|
></entry>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BlankEntry extends Entry {
|
||||||
|
constructor(public length: string) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
toXML(): string {
|
||||||
|
return `<blank length="${this.length}"/>`;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import { $ } from "zx";
|
import { $ } from "zx";
|
||||||
|
import { BlankEntry, MediaEntry } from "./entry";
|
||||||
import Project from "./kdenlive";
|
import Project from "./kdenlive";
|
||||||
|
|
||||||
describe("Kdenlive", () => {
|
describe("Kdenlive", () => {
|
||||||
@ -58,4 +59,79 @@ describe("Kdenlive", () => {
|
|||||||
await $`echo ${await project.toXML()} > 20a20v-tracks.kdenlive`;
|
await $`echo ${await project.toXML()} > 20a20v-tracks.kdenlive`;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("clips", () => {
|
||||||
|
it("should generate a 1a1v project with one clip", async () => {
|
||||||
|
const project = new Project(30);
|
||||||
|
const producer = project.addProducer("/home/kuba/Videos/5min.mp4");
|
||||||
|
const video_track = project.addVideoTractor();
|
||||||
|
const audio_track = project.addAudioTractor();
|
||||||
|
const entry = new MediaEntry(
|
||||||
|
producer,
|
||||||
|
"00:00:00.000",
|
||||||
|
"00:00:01.000"
|
||||||
|
);
|
||||||
|
video_track.addEntry(entry);
|
||||||
|
audio_track.addEntry(entry);
|
||||||
|
await $`echo ${await project.toXML()} > 1s-clip.kdenlive`;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should generate a 1a1v project with two contingent clips", async () => {
|
||||||
|
const project = new Project(30);
|
||||||
|
const producer = project.addProducer("/home/kuba/Videos/5min.mp4");
|
||||||
|
const video_track = project.addVideoTractor();
|
||||||
|
const audio_track = project.addAudioTractor();
|
||||||
|
const entry = new MediaEntry(
|
||||||
|
producer,
|
||||||
|
"00:00:00.000",
|
||||||
|
"00:00:01.000"
|
||||||
|
);
|
||||||
|
video_track.addEntry(entry);
|
||||||
|
audio_track.addEntry(entry);
|
||||||
|
const entry2 = new MediaEntry(
|
||||||
|
producer,
|
||||||
|
"00:00:01.000",
|
||||||
|
"00:00:02.000"
|
||||||
|
);
|
||||||
|
video_track.addEntry(entry2);
|
||||||
|
audio_track.addEntry(entry2);
|
||||||
|
await $`echo ${await project.toXML()} > 2x1s-clip.kdenlive`;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should generate a 1a1v project with 20 contingent clips", async () => {
|
||||||
|
const project = new Project(30);
|
||||||
|
const producer = project.addProducer("/home/kuba/Videos/5min.mp4");
|
||||||
|
const video_track = project.addVideoTractor();
|
||||||
|
const audio_track = project.addAudioTractor();
|
||||||
|
for (let i = 0; i <= 20; i++) {
|
||||||
|
let entry = new MediaEntry(
|
||||||
|
producer,
|
||||||
|
`00:00:${i.toString().padStart(2, "0")}.000`,
|
||||||
|
`00:00:${(i + 1).toString().padStart(2, "0")}.000`
|
||||||
|
);
|
||||||
|
video_track.addEntry(entry);
|
||||||
|
audio_track.addEntry(entry);
|
||||||
|
}
|
||||||
|
await $`echo ${await project.toXML()} > 20x1s-clip.kdenlive`;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should generate a 1a1v project with 10 clips with 1s pauses", async () => {
|
||||||
|
const project = new Project(30);
|
||||||
|
const producer = project.addProducer("/home/kuba/Videos/5min.mp4");
|
||||||
|
const video_track = project.addVideoTractor();
|
||||||
|
const audio_track = project.addAudioTractor();
|
||||||
|
for (let i = 0; i <= 20; i++) {
|
||||||
|
let entry = new MediaEntry(
|
||||||
|
producer,
|
||||||
|
`00:00:${i.toString().padStart(2, "0")}.000`,
|
||||||
|
`00:00:${(i + 1).toString().padStart(2, "0")}.000`
|
||||||
|
);
|
||||||
|
video_track.addEntry(entry);
|
||||||
|
audio_track.addEntry(entry);
|
||||||
|
video_track.addEntry(new BlankEntry("00:00:01.000"));
|
||||||
|
audio_track.addEntry(new BlankEntry("00:00:01.000"));
|
||||||
|
}
|
||||||
|
await $`echo ${await project.toXML()} > 10x1s-clip-with-breaks.kdenlive`;
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,23 +1,36 @@
|
|||||||
|
import { Entry } from "./entry";
|
||||||
import { makeIDGen } from "./util";
|
import { makeIDGen } from "./util";
|
||||||
|
|
||||||
const playlistIndexGen = makeIDGen(0);
|
const playlistIndexGen = makeIDGen(0);
|
||||||
|
|
||||||
export abstract class Playlist {
|
export abstract class Playlist {
|
||||||
|
public entries: Entry[] = [];
|
||||||
constructor(public index = playlistIndexGen.next().value) {}
|
constructor(public index = playlistIndexGen.next().value) {}
|
||||||
|
|
||||||
abstract toXML(): string;
|
abstract toXML(): string;
|
||||||
|
|
||||||
|
addEntry(entry: Entry) {
|
||||||
|
this.entries.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEntries() {
|
||||||
|
return this.entries.map((e) => e.toXML()).join("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AudioPlaylist extends Playlist {
|
export class AudioPlaylist extends Playlist {
|
||||||
toXML() {
|
toXML() {
|
||||||
return /* HTML */ ` <playlist id="playlist${this.index}">
|
return /* HTML */ `<playlist id="playlist${this.index}">
|
||||||
<property name="kdenlive:audio_track">1</property>
|
<property name="kdenlive:audio_track">1</property>
|
||||||
|
${this.renderEntries()}
|
||||||
</playlist>`;
|
</playlist>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class VideoPlaylist extends Playlist {
|
export class VideoPlaylist extends Playlist {
|
||||||
toXML() {
|
toXML() {
|
||||||
return /* HTML */ ` <playlist id="playlist${this.index}"></playlist>`;
|
return /* HTML */ ` <playlist id="playlist${this.index}">
|
||||||
|
${this.renderEntries()}
|
||||||
|
</playlist>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,18 +9,22 @@ export abstract class Producer {
|
|||||||
this.index = producerIndexGen.next().value;
|
this.index = producerIndexGen.next().value;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getNativeMltXml(fps: number) {
|
async getNativeMltXml(fps: number): Promise<string> {
|
||||||
const xml = (
|
const xml = (
|
||||||
await $`melt ${
|
await $`melt ${
|
||||||
this.path
|
this.path
|
||||||
} -consumer xml ${`frame_rate_num=${fps}`} | htmlq producer`
|
} -consumer xml ${`frame_rate_num=${fps}`} | htmlq producer`
|
||||||
).stdout;
|
).stdout;
|
||||||
return xml.replace("producer0", `producer${this.index}`);
|
return xml.replace("producer0", this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async toXML(fps: number) {
|
async toXML(fps: number): Promise<string> {
|
||||||
return await this.getNativeMltXml(fps);
|
return await this.getNativeMltXml(fps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return "producer" + this.index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ConcreteProducer extends Producer {
|
export class ConcreteProducer extends Producer {
|
||||||
@ -87,4 +91,8 @@ export class BlackTrack extends Producer {
|
|||||||
<property name="set.test_audio">0</property>
|
<property name="set.test_audio">0</property>
|
||||||
</producer>`;
|
</producer>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return "black_track";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Entry } from "./entry";
|
||||||
import { AudioPlaylist, Playlist, VideoPlaylist } from "./playlist";
|
import { AudioPlaylist, Playlist, VideoPlaylist } from "./playlist";
|
||||||
import { makeIDGen } from "./util";
|
import { makeIDGen } from "./util";
|
||||||
|
|
||||||
@ -9,6 +10,11 @@ export abstract class Tractor {
|
|||||||
public index = trackIndexGen.next().value;
|
public index = trackIndexGen.next().value;
|
||||||
|
|
||||||
abstract toXML(): string;
|
abstract toXML(): string;
|
||||||
|
|
||||||
|
addEntry(entry: Entry): this {
|
||||||
|
this.main_playlist.addEntry(entry);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AudioTractor extends Tractor {
|
export class AudioTractor extends Tractor {
|
||||||
|
Loading…
Reference in New Issue
Block a user