Skip to content

Commit 8a81bf7

Browse files
committed
v1.0.0-beta.15 - reduced caption preset interface complexity
1 parent 654c21f commit 8a81bf7

15 files changed

+303
-566
lines changed

examples/scripting/package-lock.json

+5-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/scripting/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"vite-plugin-dynamic-import": "^1.5.0"
1717
},
1818
"dependencies": {
19-
"@diffusionstudio/core": "^1.0.0-beta.11"
19+
"@diffusionstudio/core": "^1.0.0-beta.15"
2020
},
2121
"optionalDependencies": {
2222
"@rollup/rollup-linux-x64-gnu": "4.9.5"

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@diffusionstudio/core",
33
"private": false,
4-
"version": "1.0.0-beta.14",
4+
"version": "1.0.0-beta.15",
55
"type": "module",
66
"description": "Build bleeding edge video processing applications",
77
"files": [

src/mixins/event.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export function EventEmitterMixin<Events = {}, T extends Constructor = Construc
2929
if (!this._handlers[eventType]) {
3030
this._handlers[eventType] = { [id]: callback };
3131
} else {
32-
// @ts-ignore TODO: Figure out why this is an error
32+
// @ts-ignore
3333
this._handlers[eventType][id] = callback;
3434
}
3535

@@ -54,7 +54,7 @@ export function EventEmitterMixin<Events = {}, T extends Constructor = Construc
5454
const event = new CustomEvent<BaseEvents<Events>[T]>(eventType as string, {
5555
detail,
5656
});
57-
Object.defineProperty(event, 'target', { writable: false, value: this });
57+
Object.defineProperty(event, 'currentTarget', { writable: false, value: this });
5858

5959
for (const handler in this._handlers[eventType] ?? {}) {
6060
this._handlers[eventType]?.[handler](event);

src/tracks/caption/preset.0.spec.ts

+1-118
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { beforeEach, describe, expect, it, vi } from 'vitest';
9-
import { ComplexTextClip, Font, MediaClip, TextClip } from '../../clips';
9+
import { ComplexTextClip, MediaClip, TextClip } from '../../clips';
1010
import { Composition } from '../../composition';
1111
import { CaptionTrack } from './caption';
1212
import { Transcript, Word, WordGroup } from '../../models';
@@ -19,33 +19,6 @@ import { VerdantCaptionPreset } from './preset.verdant';
1919

2020
import type { frame, hex } from '../../types';
2121

22-
async function styleBaseClip(clip?: TextClip) {
23-
await clip?.set({
24-
fontSize: 23,
25-
fillStyle: '#0000FF',
26-
stroke: {
27-
miterLimit: 1,
28-
join: 'miter',
29-
width: 10,
30-
color: '#FF0000',
31-
},
32-
shadow: {
33-
color: '#00FF00',
34-
alpha: 0.5,
35-
angle: Math.PI / 4,
36-
blur: 32,
37-
distance: 12,
38-
},
39-
font: new Font({
40-
family: 'Komika Axis',
41-
source: 'url(komika-axis.ttf)',
42-
style: 'normal',
43-
}),
44-
});
45-
46-
await clip?.font.load();
47-
}
48-
4922
describe('(0) The Caption Presets', () => {
5023
const mockFn = vi.fn();
5124
Object.assign(document, { fonts: { add: mockFn } });
@@ -194,34 +167,10 @@ describe('(0) The Caption Presets', () => {
194167
});
195168

196169
await strategy.applyTo(track);
197-
expect(strategy.clip).toBeInstanceOf(TextClip);
198-
199-
await styleBaseClip(strategy.clip);
200170

201171
const loadedStrategy = CaptionPresetDeserializer.fromJSON(JSON.parse(JSON.stringify(strategy)));
202172
expect(loadedStrategy).toBeInstanceOf(ClassicCaptionPreset);
203-
204-
expect(loadedStrategy.clip).toBeInstanceOf(TextClip);
205-
expect(loadedStrategy.clip?.font?.loaded).toBe(false);
206173
expect((loadedStrategy as any).generatorOptions.count?.toString()).toBe('3');
207-
208-
track.clips = [];
209-
expect(track.clips.length).toBe(0);
210-
await loadedStrategy.applyTo(track);
211-
expect(loadedStrategy.clip?.font?.loaded).toBe(true);
212-
expect(track.clips.length).toBeGreaterThan(1);
213-
214-
for (const clip of track.clips) {
215-
expect(clip.font?.name).toBe('Komika Axis normal');
216-
expect(clip.font?.family).toBe('Komika Axis');
217-
expect(clip.fontSize).toBe(23);
218-
expect(clip.stroke?.miterLimit).toBe(1);
219-
expect(clip.stroke?.join).toBe('miter');
220-
expect(clip.stroke?.width).toBe(10);
221-
expect(clip.stroke?.color).toBe('#FF0000');
222-
expect(clip.shadow?.color).toBe('#00FF00');
223-
expect(clip.fillStyle).toBe('#0000FF');
224-
}
225174
});
226175

227176
it('should be able to be loaded from json, base strategy, harmozi strategy', async () => {
@@ -230,62 +179,20 @@ describe('(0) The Caption Presets', () => {
230179

231180
await strategy.applyTo(track);
232181

233-
await styleBaseClip(strategy.clip);
234-
235182
const loadedStrategy = CaptionPresetDeserializer.fromJSON(JSON.parse(JSON.stringify(strategy)));
236183
expect(loadedStrategy).toBeInstanceOf(GuineaCaptionPreset);
237184

238-
expect(loadedStrategy.clip).toBeInstanceOf(ComplexTextClip);
239-
expect(loadedStrategy.clip?.font?.loaded).toBe(false);
240185
expect((loadedStrategy as any).colors.toString()).toBe('#000000,#111111,#222222');
241-
242-
track.clips = [];
243-
await loadedStrategy.applyTo(track);
244-
expect(loadedStrategy.clip?.font?.loaded).toBe(true);
245-
expect(track.clips.length).toBeGreaterThan(1);
246-
247-
for (const clip of track.clips) {
248-
expect(clip.font?.name).toBe('Komika Axis normal');
249-
expect(clip.font?.family).toBe('Komika Axis');
250-
expect(clip.fontSize).toBe(23);
251-
expect(clip.stroke?.miterLimit).toBe(1);
252-
expect(clip.stroke?.join).toBe('miter');
253-
expect(clip.stroke?.width).toBe(10);
254-
expect(clip.stroke?.color).toBe('#FF0000');
255-
expect(clip.shadow?.color).toBe('#00FF00');
256-
}
257186
});
258187

259188
it('should be able to be loaded from json, base strategy, highlight strategy', async () => {
260189
const color = '#ABCDEF';
261190
const strategy = new SpotlightCaptionPreset({ color });
262191
await strategy.applyTo(track);
263192

264-
await styleBaseClip(strategy.clip);
265-
266193
const loadedStrategy = CaptionPresetDeserializer.fromJSON(JSON.parse(JSON.stringify(strategy)));
267194
expect(loadedStrategy).toBeInstanceOf(SpotlightCaptionPreset);
268-
269-
expect(loadedStrategy.clip).toBeInstanceOf(ComplexTextClip);
270-
expect(loadedStrategy.clip?.font?.loaded).toBe(false);
271195
expect((loadedStrategy as any).color).toBe('#ABCDEF');
272-
273-
track.clips = [];
274-
await loadedStrategy.applyTo(track);
275-
expect(loadedStrategy.clip?.font?.loaded).toBe(true);
276-
expect(track.clips.length).toBeGreaterThan(1);
277-
278-
for (const clip of track.clips) {
279-
expect(clip.font?.name).toBe('Komika Axis normal');
280-
expect(clip.font?.family).toBe('Komika Axis');
281-
expect(clip.fontSize).toBe(23);
282-
expect(clip.stroke?.miterLimit).toBe(1);
283-
expect(clip.stroke?.join).toBe('miter');
284-
expect(clip.stroke?.width).toBe(10);
285-
expect(clip.stroke?.color).toBe('#FF0000');
286-
expect(clip.shadow?.color).toBe('#00FF00');
287-
expect(clip.fillStyle).toBe('#0000FF');
288-
}
289196
});
290197

291198
it('should be able to be loaded from json, hide strategy', async () => {
@@ -295,33 +202,9 @@ describe('(0) The Caption Presets', () => {
295202
});
296203

297204
await strategy.applyTo(track);
298-
expect(strategy.clip).toBeInstanceOf(TextClip);
299-
300-
await styleBaseClip(strategy.clip);
301205

302206
const loadedStrategy = CaptionPresetDeserializer.fromJSON(JSON.parse(JSON.stringify(strategy)));
303207
expect(loadedStrategy).toBeInstanceOf(CascadeCaptionPreset);
304-
305-
expect(loadedStrategy.clip).toBeInstanceOf(TextClip);
306-
expect(loadedStrategy.clip?.font?.loaded).toBe(false);
307208
expect((loadedStrategy as any).generatorOptions.count?.toString()).toBe('9');
308-
309-
track.clips = [];
310-
expect(track.clips.length).toBe(0);
311-
await loadedStrategy.applyTo(track);
312-
expect(loadedStrategy.clip?.font?.loaded).toBe(true);
313-
expect(track.clips.length).toBeGreaterThan(1);
314-
315-
for (const clip of track.clips) {
316-
expect(clip.font?.name).toBe('Komika Axis normal');
317-
expect(clip.font?.family).toBe('Komika Axis');
318-
expect(clip.fontSize).toBe(23);
319-
expect(clip.stroke?.miterLimit).toBe(1);
320-
expect(clip.stroke?.join).toBe('miter');
321-
expect(clip.stroke?.width).toBe(10);
322-
expect(clip.stroke?.color).toBe('#FF0000');
323-
expect(clip.shadow?.color).toBe('#00FF00');
324-
expect(clip.fillStyle).toBe('#0000FF');
325-
}
326209
});
327210
});

src/tracks/caption/preset.cascade.ts

+36-55
Original file line numberDiff line numberDiff line change
@@ -10,89 +10,70 @@ import { Serializer, serializable } from '../../services';
1010
import { Font, TextClip } from '../../clips';
1111

1212
import type { GeneratorOptions } from '../../models';
13-
import type { ScreenSize, DefaultCaptionPresetConfig } from './preset.types';
13+
import type { DefaultCaptionPresetConfig } from './preset.types';
1414
import type { CaptionTrack } from './caption';
1515
import type { CaptionPresetStrategy } from './preset.interface';
1616

1717
export class CascadeCaptionPreset extends Serializer implements CaptionPresetStrategy {
18-
private _initialized = false;
19-
2018
@serializable()
2119
public generatorOptions: GeneratorOptions;
2220

2321
@serializable()
2422
public readonly type = 'CASCADE';
2523

26-
@serializable(TextClip)
27-
public clip: TextClip | undefined;
28-
2924
public constructor(config: Partial<DefaultCaptionPresetConfig> = {}) {
3025
super();
3126

3227
this.generatorOptions = config.generatorOptions ?? { duration: [1.4] };
33-
this.clip = config.clip;
34-
}
35-
36-
public async init(composition?: ScreenSize) {
37-
if (this._initialized || !composition) return;
38-
39-
if (!this.clip) {
40-
this.clip = await new TextClip({
41-
textAlign: 'left',
42-
textBaseline: 'top',
43-
fillStyle: '#FFFFFF',
44-
fontSize: 16,
45-
font: Font.fromFamily({ family: 'Geologica', weight: '400' }),
46-
maxWidth: composition.width * 0.7,
47-
stroke: {
48-
color: '#000000',
49-
width: 4,
50-
join: 'round',
51-
},
52-
shadow: {
53-
color: '#000000',
54-
blur: 8,
55-
alpha: 0.4,
56-
angle: Math.PI / 4,
57-
distance: 2,
58-
},
59-
position: {
60-
x: '12%',
61-
y: composition.height / 2 - 40,
62-
},
63-
});
64-
}
65-
66-
await this.clip.font.load();
67-
this._initialized = true;
6828
}
6929

7030
public async applyTo(track: CaptionTrack): Promise<void> {
71-
await this.init(track.composition);
72-
73-
if (!this.clip || !track.clip?.transcript) {
74-
throw new Error('Preset needs to be initialized first');
31+
if (!track.clip?.transcript || !track.composition?.width) {
32+
throw new Error('Captions need to be applied with a defined transcript and composition');
7533
}
7634

7735
const offset = track.clip?.offset ?? new Timestamp();
36+
const font = await Font.fromFamily({ family: 'Geologica', weight: '400' }).load();
7837

7938
// add captions
8039
for (const sequence of track.clip.transcript.iter(this.generatorOptions)) {
8140
for (let i = 0; i < sequence.words.length; i++) {
82-
function getText() {
83-
if (sequence.words.length == 1) {
84-
return sequence.text;
85-
}
41+
const getText = () => {
42+
if (sequence.words.length == 1) return sequence.text;
43+
8644
const words = sequence.words.map((word) => word.text);
8745
return words.slice(0, i + 1).join(' ');
8846
}
8947

90-
const clip = this.clip.copy().set({
91-
text: getText(),
92-
stop: sequence.words[i].stop.add(offset),
93-
start: sequence.words[i].start.add(offset),
94-
});
95-
await track.appendClip(clip);
48+
await track.appendClip(
49+
new TextClip({
50+
text: getText(),
51+
textAlign: 'left',
52+
textBaseline: 'top',
53+
fillStyle: '#FFFFFF',
54+
fontSize: 16,
55+
font,
56+
maxWidth: track.composition.width * 0.7,
57+
stroke: {
58+
color: '#000000',
59+
width: 4,
60+
join: 'round',
61+
},
62+
shadow: {
63+
color: '#000000',
64+
blur: 8,
65+
alpha: 0.4,
66+
angle: Math.PI / 4,
67+
distance: 2,
68+
},
69+
position: {
70+
x: '12%',
71+
y: '44%',
72+
},
73+
stop: sequence.words[i].stop.add(offset),
74+
start: sequence.words[i].start.add(offset),
75+
})
76+
);
9677
}
9778
}
9879
}

0 commit comments

Comments
 (0)