From 84cd5014dc8c8e1e06a1b6e397f9e2e7bdc2f0d9 Mon Sep 17 00:00:00 2001 From: Kuba Orlik Date: Mon, 25 Oct 2021 21:26:23 +0200 Subject: [PATCH] Entries and playlists --- src/entry.ts | 17 +++++++++++++++++ src/example.test.ts | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/playlist.ts | 17 +++++++++++++++-- src/producer.ts | 14 +++++++++++--- src/tractor.ts | 6 ++++++ 5 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 src/entry.ts diff --git a/src/entry.ts b/src/entry.ts new file mode 100644 index 0000000..4f977b3 --- /dev/null +++ b/src/entry.ts @@ -0,0 +1,17 @@ +import { Producer } from "./producer"; + +export class Entry { + constructor( + public producer: Producer, + public in_point: string, + public out_point: string + ) {} + + toXML(): string { + return /* HTML */ ``; + } +} diff --git a/src/example.test.ts b/src/example.test.ts index ca417fe..995032d 100644 --- a/src/example.test.ts +++ b/src/example.test.ts @@ -1,4 +1,5 @@ import { $ } from "zx"; +import { Entry } from "./entry"; import Project from "./kdenlive"; describe("Kdenlive", () => { @@ -58,4 +59,48 @@ describe("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 Entry(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 Entry(producer, "00:00:00.000", "00:00:01.000"); + video_track.addEntry(entry); + audio_track.addEntry(entry); + const entry2 = new Entry(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 Entry( + 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`; + }); + }); }); diff --git a/src/playlist.ts b/src/playlist.ts index b861949..12f9c90 100644 --- a/src/playlist.ts +++ b/src/playlist.ts @@ -1,23 +1,36 @@ +import { Entry } from "./entry"; import { makeIDGen } from "./util"; const playlistIndexGen = makeIDGen(0); export abstract class Playlist { + public entries: Entry[] = []; constructor(public index = playlistIndexGen.next().value) {} 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 { toXML() { - return /* HTML */ ` + return /* HTML */ ` 1 + ${this.renderEntries()} `; } } export class VideoPlaylist extends Playlist { toXML() { - return /* HTML */ ` `; + return /* HTML */ ` + ${this.renderEntries()} + `; } } diff --git a/src/producer.ts b/src/producer.ts index c7a520c..1209187 100644 --- a/src/producer.ts +++ b/src/producer.ts @@ -9,18 +9,22 @@ export abstract class Producer { this.index = producerIndexGen.next().value; } - async getNativeMltXml(fps: number) { + async getNativeMltXml(fps: number): Promise { const xml = ( await $`melt ${ this.path } -consumer xml ${`frame_rate_num=${fps}`} | htmlq producer` ).stdout; - return xml.replace("producer0", `producer${this.index}`); + return xml.replace("producer0", this.id); } - async toXML(fps: number) { + async toXML(fps: number): Promise { return await this.getNativeMltXml(fps); } + + get id() { + return "producer" + this.index; + } } export class ConcreteProducer extends Producer { @@ -87,4 +91,8 @@ export class BlackTrack extends Producer { 0 `; } + + get id() { + return "black_track"; + } } diff --git a/src/tractor.ts b/src/tractor.ts index 59e9f6b..64c50da 100644 --- a/src/tractor.ts +++ b/src/tractor.ts @@ -1,3 +1,4 @@ +import { Entry } from "./entry"; import { AudioPlaylist, Playlist, VideoPlaylist } from "./playlist"; import { makeIDGen } from "./util"; @@ -9,6 +10,11 @@ export abstract class Tractor { public index = trackIndexGen.next().value; abstract toXML(): string; + + addEntry(entry: Entry): this { + this.main_playlist.addEntry(entry); + return this; + } } export class AudioTractor extends Tractor {