@gannochenko/staticstripes 0.0.21 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-builder.d.ts +18 -0
- package/dist/app-builder.d.ts.map +1 -0
- package/dist/app-builder.js +94 -0
- package/dist/app-builder.js.map +1 -0
- package/dist/cli/commands/filters.d.ts +3 -0
- package/dist/cli/commands/filters.d.ts.map +1 -0
- package/dist/cli/commands/filters.js +21 -0
- package/dist/cli/commands/filters.js.map +1 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +6 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/instagram/instagram-upload-strategy.d.ts +5 -0
- package/dist/cli/instagram/instagram-upload-strategy.d.ts.map +1 -1
- package/dist/cli/instagram/instagram-upload-strategy.js +46 -3
- package/dist/cli/instagram/instagram-upload-strategy.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/html-project-parser.d.ts +20 -1
- package/dist/html-project-parser.d.ts.map +1 -1
- package/dist/html-project-parser.js +128 -15
- package/dist/html-project-parser.js.map +1 -1
- package/dist/project.d.ts +4 -1
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +50 -1
- package/dist/project.js.map +1 -1
- package/dist/sample-sequences.d.ts.map +1 -1
- package/dist/sample-sequences.js +7 -0
- package/dist/sample-sequences.js.map +1 -1
- package/dist/sequence.d.ts +4 -1
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +43 -19
- package/dist/sequence.js.map +1 -1
- package/dist/type.d.ts +18 -1
- package/dist/type.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/app-builder.ts +113 -0
- package/src/cli/commands/filters.ts +21 -0
- package/src/cli/commands/generate.ts +10 -1
- package/src/cli/instagram/instagram-upload-strategy.ts +61 -1
- package/src/cli.ts +2 -0
- package/src/html-project-parser.ts +172 -26
- package/src/project.ts +62 -0
- package/src/sample-sequences.ts +7 -0
- package/src/sequence.ts +50 -20
- package/src/type.ts +20 -1
package/src/sequence.ts
CHANGED
|
@@ -16,13 +16,14 @@ import {
|
|
|
16
16
|
Stream,
|
|
17
17
|
VisualFilter,
|
|
18
18
|
} from './stream';
|
|
19
|
-
import { Output, SequenceDefinition } from './type';
|
|
19
|
+
import { Output, SequenceDefinition, FragmentDebugInfo } from './type';
|
|
20
20
|
|
|
21
21
|
export class Sequence {
|
|
22
22
|
private time: number = 0; // time is absolute
|
|
23
23
|
|
|
24
24
|
private videoStream!: Stream;
|
|
25
25
|
private audioStream!: Stream;
|
|
26
|
+
private debugInfo: FragmentDebugInfo[] = []; // Collect debug info during build
|
|
26
27
|
|
|
27
28
|
constructor(
|
|
28
29
|
private buf: FilterBuffer,
|
|
@@ -44,6 +45,11 @@ export class Sequence {
|
|
|
44
45
|
this.expressionContext,
|
|
45
46
|
);
|
|
46
47
|
|
|
48
|
+
const calculatedDuration = calculateFinalValue(
|
|
49
|
+
fragment.duration,
|
|
50
|
+
this.expressionContext,
|
|
51
|
+
);
|
|
52
|
+
|
|
47
53
|
if (fragment.id === 'outro_message') {
|
|
48
54
|
debugger;
|
|
49
55
|
}
|
|
@@ -51,7 +57,7 @@ export class Sequence {
|
|
|
51
57
|
const timeContext: TimeData = {
|
|
52
58
|
start: 0,
|
|
53
59
|
end: 0,
|
|
54
|
-
duration:
|
|
60
|
+
duration: calculatedDuration,
|
|
55
61
|
};
|
|
56
62
|
|
|
57
63
|
const asset = this.assetManager.getAssetByName(fragment.assetName);
|
|
@@ -69,7 +75,7 @@ export class Sequence {
|
|
|
69
75
|
} else {
|
|
70
76
|
// Create blank transparent video stream for audio-only assets
|
|
71
77
|
currentVideoStream = makeBlankStream(
|
|
72
|
-
|
|
78
|
+
calculatedDuration,
|
|
73
79
|
this.output.resolution.width,
|
|
74
80
|
this.output.resolution.height,
|
|
75
81
|
this.output.fps,
|
|
@@ -78,36 +84,40 @@ export class Sequence {
|
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
// Create audio stream: use actual audio if available, otherwise create silent stream
|
|
87
|
+
// If fragment has -sound: off, always use silence
|
|
81
88
|
let currentAudioStream: Stream;
|
|
82
|
-
if (
|
|
89
|
+
if (fragment.sound === 'off') {
|
|
90
|
+
// Force silent audio when -sound: off
|
|
91
|
+
currentAudioStream = makeSilentStream(calculatedDuration, this.buf);
|
|
92
|
+
} else if (asset.hasAudio) {
|
|
83
93
|
currentAudioStream = makeStream(
|
|
84
94
|
this.assetManager.getAudioInputLabelByAssetName(fragment.assetName),
|
|
85
95
|
this.buf,
|
|
86
96
|
);
|
|
87
97
|
} else {
|
|
88
98
|
// Create silent audio stream matching the video duration
|
|
89
|
-
currentAudioStream = makeSilentStream(
|
|
99
|
+
currentAudioStream = makeSilentStream(calculatedDuration, this.buf);
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
// duration and clipping adjustment
|
|
93
|
-
if (fragment.trimLeft != 0 ||
|
|
103
|
+
if (fragment.trimLeft != 0 || calculatedDuration < asset.duration) {
|
|
94
104
|
// console.log('fragment.trimLeft=' + fragment.trimLeft);
|
|
95
|
-
// console.log('fragment.duration=' +
|
|
105
|
+
// console.log('fragment.duration=' + calculatedDuration);
|
|
96
106
|
// console.log('asset.duration=' + asset.duration);
|
|
97
107
|
|
|
98
108
|
// Only trim video if it came from an actual source
|
|
99
109
|
if (asset.hasVideo) {
|
|
100
110
|
currentVideoStream.trim(
|
|
101
111
|
fragment.trimLeft,
|
|
102
|
-
fragment.trimLeft +
|
|
112
|
+
fragment.trimLeft + calculatedDuration,
|
|
103
113
|
);
|
|
104
114
|
}
|
|
105
115
|
|
|
106
|
-
// Only trim audio if it came from an actual source
|
|
107
|
-
if (asset.hasAudio) {
|
|
116
|
+
// Only trim audio if it came from an actual source AND sound is not off
|
|
117
|
+
if (asset.hasAudio && fragment.sound !== 'off') {
|
|
108
118
|
currentAudioStream.trim(
|
|
109
119
|
fragment.trimLeft,
|
|
110
|
-
fragment.trimLeft +
|
|
120
|
+
fragment.trimLeft + calculatedDuration,
|
|
111
121
|
);
|
|
112
122
|
}
|
|
113
123
|
}
|
|
@@ -124,12 +134,12 @@ export class Sequence {
|
|
|
124
134
|
|
|
125
135
|
if (
|
|
126
136
|
asset.duration === 0 &&
|
|
127
|
-
|
|
137
|
+
calculatedDuration > 0 &&
|
|
128
138
|
asset.type === 'image'
|
|
129
139
|
) {
|
|
130
140
|
// special case for images - extend static image to desired duration
|
|
131
141
|
currentVideoStream.tPad({
|
|
132
|
-
start:
|
|
142
|
+
start: calculatedDuration,
|
|
133
143
|
startMode: 'clone',
|
|
134
144
|
});
|
|
135
145
|
}
|
|
@@ -202,7 +212,7 @@ export class Sequence {
|
|
|
202
212
|
fades: [
|
|
203
213
|
{
|
|
204
214
|
type: 'out',
|
|
205
|
-
startTime:
|
|
215
|
+
startTime: calculatedDuration - fragment.transitionOutDuration,
|
|
206
216
|
duration: fragment.transitionOutDuration,
|
|
207
217
|
},
|
|
208
218
|
],
|
|
@@ -211,7 +221,7 @@ export class Sequence {
|
|
|
211
221
|
fades: [
|
|
212
222
|
{
|
|
213
223
|
type: 'out',
|
|
214
|
-
startTime:
|
|
224
|
+
startTime: calculatedDuration - fragment.transitionOutDuration,
|
|
215
225
|
duration: fragment.transitionOutDuration,
|
|
216
226
|
},
|
|
217
227
|
],
|
|
@@ -239,7 +249,7 @@ export class Sequence {
|
|
|
239
249
|
|
|
240
250
|
// console.log('this.time=' + this.time);
|
|
241
251
|
// console.log('streamDuration=' + this.time);
|
|
242
|
-
// console.log('otherStreamDuration=' +
|
|
252
|
+
// console.log('otherStreamDuration=' + calculatedDuration);
|
|
243
253
|
// console.log('otherStreamOffsetLeft=' + otherStreamOffsetLeft);
|
|
244
254
|
|
|
245
255
|
// use overlay
|
|
@@ -247,14 +257,14 @@ export class Sequence {
|
|
|
247
257
|
flipLayers: fragment.overlayZIndex < 0,
|
|
248
258
|
offset: {
|
|
249
259
|
streamDuration: this.time,
|
|
250
|
-
otherStreamDuration:
|
|
260
|
+
otherStreamDuration: calculatedDuration,
|
|
251
261
|
otherStreamOffsetLeft: otherStreamOffsetLeft,
|
|
252
262
|
},
|
|
253
263
|
});
|
|
254
264
|
this.audioStream.overlayStream(currentAudioStream, {
|
|
255
265
|
offset: {
|
|
256
266
|
streamDuration: this.time,
|
|
257
|
-
otherStreamDuration:
|
|
267
|
+
otherStreamDuration: calculatedDuration,
|
|
258
268
|
otherStreamOffsetLeft: otherStreamOffsetLeft,
|
|
259
269
|
},
|
|
260
270
|
});
|
|
@@ -291,13 +301,25 @@ export class Sequence {
|
|
|
291
301
|
}
|
|
292
302
|
|
|
293
303
|
timeContext.start = this.time + calculatedOverlayLeft;
|
|
294
|
-
timeContext.end = this.time +
|
|
295
|
-
this.time +=
|
|
304
|
+
timeContext.end = this.time + calculatedDuration + calculatedOverlayLeft;
|
|
305
|
+
this.time += calculatedDuration + calculatedOverlayLeft;
|
|
296
306
|
|
|
297
307
|
this.expressionContext.fragments.set(fragment.id, {
|
|
298
308
|
time: timeContext,
|
|
299
309
|
});
|
|
300
310
|
|
|
311
|
+
// Collect debug info
|
|
312
|
+
this.debugInfo.push({
|
|
313
|
+
id: fragment.id,
|
|
314
|
+
assetName: fragment.assetName,
|
|
315
|
+
startTime: timeContext.start,
|
|
316
|
+
endTime: timeContext.end,
|
|
317
|
+
duration: calculatedDuration,
|
|
318
|
+
trimLeft: fragment.trimLeft,
|
|
319
|
+
overlayLeft: calculatedOverlayLeft,
|
|
320
|
+
enabled: fragment.enabled,
|
|
321
|
+
});
|
|
322
|
+
|
|
301
323
|
// console.log('new time=' + this.time);
|
|
302
324
|
|
|
303
325
|
firstOne = false;
|
|
@@ -327,4 +349,12 @@ export class Sequence {
|
|
|
327
349
|
public getAudioStream(): Stream {
|
|
328
350
|
return this.audioStream;
|
|
329
351
|
}
|
|
352
|
+
|
|
353
|
+
public getDebugInfo(): FragmentDebugInfo[] {
|
|
354
|
+
return this.debugInfo;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
public getTotalDuration(): number {
|
|
358
|
+
return this.time;
|
|
359
|
+
}
|
|
330
360
|
}
|
package/src/type.ts
CHANGED
|
@@ -47,7 +47,7 @@ export type Fragment = {
|
|
|
47
47
|
id: string;
|
|
48
48
|
enabled: boolean;
|
|
49
49
|
assetName: string;
|
|
50
|
-
duration: number; // calculated, in seconds (can come from CSS or from the asset's duration)
|
|
50
|
+
duration: number | CompiledExpression; // calculated, in seconds (can come from CSS or from the asset's duration, or be a calc() expression)
|
|
51
51
|
trimLeft: number; // in seconds (skip first N seconds of asset via -trim-start)
|
|
52
52
|
overlayLeft: number | CompiledExpression; // amount of seconds to overlay with the previous fragment (normalized from margin-left + prev margin-right)
|
|
53
53
|
overlayZIndex: number;
|
|
@@ -66,6 +66,7 @@ export type Fragment = {
|
|
|
66
66
|
chromakeySimilarity: number;
|
|
67
67
|
chromakeyColor: string;
|
|
68
68
|
visualFilter?: string; // Optional visual filter (e.g., 'instagram-nashville')
|
|
69
|
+
sound: 'on' | 'off'; // Whether to use asset audio or replace with silence (default: 'on')
|
|
69
70
|
container?: Container; // Optional container attached to this fragment
|
|
70
71
|
app?: App; // Optional app attached to this fragment
|
|
71
72
|
timecodeLabel?: string; // Optional label for timecode (from data-timecode attribute)
|
|
@@ -75,6 +76,23 @@ export type SequenceDefinition = {
|
|
|
75
76
|
fragments: Fragment[];
|
|
76
77
|
};
|
|
77
78
|
|
|
79
|
+
export type FragmentDebugInfo = {
|
|
80
|
+
id: string;
|
|
81
|
+
assetName: string;
|
|
82
|
+
startTime: number; // absolute start time in seconds
|
|
83
|
+
endTime: number; // absolute end time in seconds
|
|
84
|
+
duration: number; // fragment duration in seconds
|
|
85
|
+
trimLeft: number; // trim from asset start in seconds
|
|
86
|
+
overlayLeft: number; // overlay with previous fragment in seconds
|
|
87
|
+
enabled: boolean;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export type SequenceDebugInfo = {
|
|
91
|
+
sequenceIndex: number;
|
|
92
|
+
totalDuration: number; // total duration of the sequence in seconds
|
|
93
|
+
fragments: FragmentDebugInfo[];
|
|
94
|
+
};
|
|
95
|
+
|
|
78
96
|
export type Output = {
|
|
79
97
|
name: string; // e.g. "youtube"
|
|
80
98
|
path: string; // e.g. "./output/video.mp4"
|
|
@@ -118,6 +136,7 @@ export type Upload = {
|
|
|
118
136
|
thumbOffset?: number; // Thumbnail frame location in milliseconds
|
|
119
137
|
coverUrl?: string; // Optional cover image URL
|
|
120
138
|
videoUrl?: string; // Public URL to video (if not auto-generated from S3)
|
|
139
|
+
locationId?: string; // Facebook Page location ID for geotagging
|
|
121
140
|
};
|
|
122
141
|
};
|
|
123
142
|
|