vidpipe 1.3.5 → 1.3.6
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/cli.js +116 -60
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1440,6 +1440,50 @@ init_environment();
|
|
|
1440
1440
|
init_paths();
|
|
1441
1441
|
init_fileSystem();
|
|
1442
1442
|
init_configLogger();
|
|
1443
|
+
|
|
1444
|
+
// src/L0-pure/types/index.ts
|
|
1445
|
+
var Platform = /* @__PURE__ */ ((Platform2) => {
|
|
1446
|
+
Platform2["TikTok"] = "tiktok";
|
|
1447
|
+
Platform2["YouTube"] = "youtube";
|
|
1448
|
+
Platform2["Instagram"] = "instagram";
|
|
1449
|
+
Platform2["LinkedIn"] = "linkedin";
|
|
1450
|
+
Platform2["X"] = "x";
|
|
1451
|
+
return Platform2;
|
|
1452
|
+
})(Platform || {});
|
|
1453
|
+
var PLATFORM_CHAR_LIMITS = {
|
|
1454
|
+
tiktok: 2200,
|
|
1455
|
+
youtube: 5e3,
|
|
1456
|
+
instagram: 2200,
|
|
1457
|
+
linkedin: 3e3,
|
|
1458
|
+
twitter: 280
|
|
1459
|
+
};
|
|
1460
|
+
function toLatePlatform(platform) {
|
|
1461
|
+
return platform === "x" /* X */ ? "twitter" : platform;
|
|
1462
|
+
}
|
|
1463
|
+
function fromLatePlatform(latePlatform) {
|
|
1464
|
+
const normalized = normalizePlatformString(latePlatform);
|
|
1465
|
+
if (normalized === "twitter") {
|
|
1466
|
+
return "x" /* X */;
|
|
1467
|
+
}
|
|
1468
|
+
const platformValues = Object.values(Platform);
|
|
1469
|
+
if (platformValues.includes(normalized)) {
|
|
1470
|
+
return normalized;
|
|
1471
|
+
}
|
|
1472
|
+
throw new Error(`Unsupported platform from Late API: ${latePlatform}`);
|
|
1473
|
+
}
|
|
1474
|
+
function normalizePlatformString(raw) {
|
|
1475
|
+
const lower = raw.toLowerCase().trim();
|
|
1476
|
+
if (lower === "x" || lower === "x (twitter)" || lower === "x/twitter") {
|
|
1477
|
+
return "twitter";
|
|
1478
|
+
}
|
|
1479
|
+
return lower;
|
|
1480
|
+
}
|
|
1481
|
+
var SUPPORTED_VIDEO_EXTENSIONS = [".mp4", ".webm"];
|
|
1482
|
+
function isSupportedVideoExtension(ext) {
|
|
1483
|
+
return SUPPORTED_VIDEO_EXTENSIONS.includes(ext.toLowerCase());
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
// src/L7-app/fileWatcher.ts
|
|
1443
1487
|
var FileWatcher = class _FileWatcher extends EventEmitter {
|
|
1444
1488
|
watchFolder;
|
|
1445
1489
|
watcher = null;
|
|
@@ -1469,8 +1513,8 @@ var FileWatcher = class _FileWatcher extends EventEmitter {
|
|
|
1469
1513
|
}
|
|
1470
1514
|
}
|
|
1471
1515
|
async handleDetectedFile(filePath) {
|
|
1472
|
-
if (extname(filePath).toLowerCase()
|
|
1473
|
-
logger_default.debug(`[watcher] Ignoring
|
|
1516
|
+
if (!isSupportedVideoExtension(extname(filePath).toLowerCase())) {
|
|
1517
|
+
logger_default.debug(`[watcher] Ignoring unsupported file: ${filePath}`);
|
|
1474
1518
|
return;
|
|
1475
1519
|
}
|
|
1476
1520
|
let fileSize;
|
|
@@ -1505,7 +1549,7 @@ var FileWatcher = class _FileWatcher extends EventEmitter {
|
|
|
1505
1549
|
throw err;
|
|
1506
1550
|
}
|
|
1507
1551
|
for (const file of files) {
|
|
1508
|
-
if (extname(file).toLowerCase()
|
|
1552
|
+
if (isSupportedVideoExtension(extname(file).toLowerCase())) {
|
|
1509
1553
|
const filePath = join(this.watchFolder, file);
|
|
1510
1554
|
this.handleDetectedFile(filePath).catch(
|
|
1511
1555
|
(err) => logger_default.error(`Error processing ${filePath}: ${err instanceof Error ? err.message : String(err)}`)
|
|
@@ -1535,7 +1579,7 @@ var FileWatcher = class _FileWatcher extends EventEmitter {
|
|
|
1535
1579
|
});
|
|
1536
1580
|
this.watcher.on("change", (filePath) => {
|
|
1537
1581
|
logger_default.debug(`[watcher] 'change' event: ${filePath}`);
|
|
1538
|
-
if (extname(filePath).toLowerCase()
|
|
1582
|
+
if (!isSupportedVideoExtension(extname(filePath).toLowerCase())) return;
|
|
1539
1583
|
logger_default.info(`Change detected on video file: ${filePath}`);
|
|
1540
1584
|
this.handleDetectedFile(filePath).catch(
|
|
1541
1585
|
(err) => logger_default.error(`Error processing ${filePath}: ${err instanceof Error ? err.message : String(err)}`)
|
|
@@ -1556,7 +1600,7 @@ var FileWatcher = class _FileWatcher extends EventEmitter {
|
|
|
1556
1600
|
this.scanExistingFiles();
|
|
1557
1601
|
}
|
|
1558
1602
|
});
|
|
1559
|
-
logger_default.info(`Watching for new
|
|
1603
|
+
logger_default.info(`Watching for new video files in: ${this.watchFolder}`);
|
|
1560
1604
|
}
|
|
1561
1605
|
stop() {
|
|
1562
1606
|
if (this.watcher) {
|
|
@@ -2880,6 +2924,41 @@ async function compositeOverlays(videoPath, overlays, outputPath, videoWidth, vi
|
|
|
2880
2924
|
});
|
|
2881
2925
|
}
|
|
2882
2926
|
|
|
2927
|
+
// src/L2-clients/ffmpeg/transcoding.ts
|
|
2928
|
+
init_fileSystem();
|
|
2929
|
+
init_paths();
|
|
2930
|
+
init_configLogger();
|
|
2931
|
+
function transcodeToMp4(inputPath, outputPath) {
|
|
2932
|
+
const outputDir = dirname(outputPath);
|
|
2933
|
+
return new Promise((resolve3, reject) => {
|
|
2934
|
+
ensureDirectory(outputDir).then(() => {
|
|
2935
|
+
logger_default.info(`Transcoding to MP4: ${inputPath} \u2192 ${outputPath}`);
|
|
2936
|
+
createFFmpeg(inputPath).outputOptions([
|
|
2937
|
+
"-c:v",
|
|
2938
|
+
"libx264",
|
|
2939
|
+
"-preset",
|
|
2940
|
+
"ultrafast",
|
|
2941
|
+
"-crf",
|
|
2942
|
+
"23",
|
|
2943
|
+
"-threads",
|
|
2944
|
+
"4",
|
|
2945
|
+
"-c:a",
|
|
2946
|
+
"aac",
|
|
2947
|
+
"-b:a",
|
|
2948
|
+
"128k",
|
|
2949
|
+
"-movflags",
|
|
2950
|
+
"+faststart"
|
|
2951
|
+
]).output(outputPath).on("end", () => {
|
|
2952
|
+
logger_default.info(`Transcoding complete: ${outputPath}`);
|
|
2953
|
+
resolve3(outputPath);
|
|
2954
|
+
}).on("error", (err) => {
|
|
2955
|
+
logger_default.error(`Transcoding failed: ${err.message}`);
|
|
2956
|
+
reject(new Error(`Transcoding to MP4 failed: ${err.message}`));
|
|
2957
|
+
}).run();
|
|
2958
|
+
}).catch(reject);
|
|
2959
|
+
});
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2883
2962
|
// src/L3-services/videoOperations/videoOperations.ts
|
|
2884
2963
|
function ffprobe2(...args) {
|
|
2885
2964
|
return ffprobe(...args);
|
|
@@ -2917,6 +2996,9 @@ function getVideoResolution2(...args) {
|
|
|
2917
2996
|
function compositeOverlays2(...args) {
|
|
2918
2997
|
return compositeOverlays(...args);
|
|
2919
2998
|
}
|
|
2999
|
+
function transcodeToMp42(...args) {
|
|
3000
|
+
return transcodeToMp4(...args);
|
|
3001
|
+
}
|
|
2920
3002
|
|
|
2921
3003
|
// src/L0-pure/captions/captionGenerator.ts
|
|
2922
3004
|
function pad(n, width) {
|
|
@@ -4367,46 +4449,6 @@ var SocialPostAsset = class extends TextAsset {
|
|
|
4367
4449
|
// src/L5-assets/ShortVideoAsset.ts
|
|
4368
4450
|
init_paths();
|
|
4369
4451
|
init_fileSystem();
|
|
4370
|
-
|
|
4371
|
-
// src/L0-pure/types/index.ts
|
|
4372
|
-
var Platform = /* @__PURE__ */ ((Platform2) => {
|
|
4373
|
-
Platform2["TikTok"] = "tiktok";
|
|
4374
|
-
Platform2["YouTube"] = "youtube";
|
|
4375
|
-
Platform2["Instagram"] = "instagram";
|
|
4376
|
-
Platform2["LinkedIn"] = "linkedin";
|
|
4377
|
-
Platform2["X"] = "x";
|
|
4378
|
-
return Platform2;
|
|
4379
|
-
})(Platform || {});
|
|
4380
|
-
var PLATFORM_CHAR_LIMITS = {
|
|
4381
|
-
tiktok: 2200,
|
|
4382
|
-
youtube: 5e3,
|
|
4383
|
-
instagram: 2200,
|
|
4384
|
-
linkedin: 3e3,
|
|
4385
|
-
twitter: 280
|
|
4386
|
-
};
|
|
4387
|
-
function toLatePlatform(platform) {
|
|
4388
|
-
return platform === "x" /* X */ ? "twitter" : platform;
|
|
4389
|
-
}
|
|
4390
|
-
function fromLatePlatform(latePlatform) {
|
|
4391
|
-
const normalized = normalizePlatformString(latePlatform);
|
|
4392
|
-
if (normalized === "twitter") {
|
|
4393
|
-
return "x" /* X */;
|
|
4394
|
-
}
|
|
4395
|
-
const platformValues = Object.values(Platform);
|
|
4396
|
-
if (platformValues.includes(normalized)) {
|
|
4397
|
-
return normalized;
|
|
4398
|
-
}
|
|
4399
|
-
throw new Error(`Unsupported platform from Late API: ${latePlatform}`);
|
|
4400
|
-
}
|
|
4401
|
-
function normalizePlatformString(raw) {
|
|
4402
|
-
const lower = raw.toLowerCase().trim();
|
|
4403
|
-
if (lower === "x" || lower === "x (twitter)" || lower === "x/twitter") {
|
|
4404
|
-
return "twitter";
|
|
4405
|
-
}
|
|
4406
|
-
return lower;
|
|
4407
|
-
}
|
|
4408
|
-
|
|
4409
|
-
// src/L5-assets/ShortVideoAsset.ts
|
|
4410
4452
|
var ShortVideoAsset = class extends VideoAsset {
|
|
4411
4453
|
/** Reference to the source video this short was extracted from */
|
|
4412
4454
|
parent;
|
|
@@ -8231,26 +8273,40 @@ var MainVideoAsset = class _MainVideoAsset extends VideoAsset {
|
|
|
8231
8273
|
await ensureDirectory(socialPostsDir);
|
|
8232
8274
|
const destFilename = `${slug}.mp4`;
|
|
8233
8275
|
const destPath = join(videoDir, destFilename);
|
|
8234
|
-
|
|
8276
|
+
const sourceExt = extname(sourcePath).toLowerCase();
|
|
8277
|
+
const needsTranscode = sourceExt !== ".mp4";
|
|
8278
|
+
let needsIngest = true;
|
|
8235
8279
|
try {
|
|
8236
8280
|
const destStats = await getFileStats(destPath);
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8281
|
+
if (needsTranscode) {
|
|
8282
|
+
if (destStats.size > 1024) {
|
|
8283
|
+
logger_default.info(`Transcoded MP4 already exists (${(destStats.size / 1024 / 1024).toFixed(1)} MB), skipping transcode`);
|
|
8284
|
+
needsIngest = false;
|
|
8285
|
+
}
|
|
8286
|
+
} else {
|
|
8287
|
+
const srcStats = await getFileStats(sourcePath);
|
|
8288
|
+
if (destStats.size === srcStats.size) {
|
|
8289
|
+
logger_default.info(`Video already copied (same size), skipping copy`);
|
|
8290
|
+
needsIngest = false;
|
|
8291
|
+
}
|
|
8241
8292
|
}
|
|
8242
8293
|
} catch {
|
|
8243
8294
|
}
|
|
8244
|
-
if (
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8295
|
+
if (needsIngest) {
|
|
8296
|
+
if (needsTranscode) {
|
|
8297
|
+
await transcodeToMp42(sourcePath, destPath);
|
|
8298
|
+
logger_default.info(`Transcoded video to ${destPath}`);
|
|
8299
|
+
} else {
|
|
8300
|
+
await new Promise((resolve3, reject) => {
|
|
8301
|
+
const readStream = openReadStream(sourcePath);
|
|
8302
|
+
const writeStream = openWriteStream(destPath);
|
|
8303
|
+
readStream.on("error", reject);
|
|
8304
|
+
writeStream.on("error", reject);
|
|
8305
|
+
writeStream.on("finish", resolve3);
|
|
8306
|
+
readStream.pipe(writeStream);
|
|
8307
|
+
});
|
|
8308
|
+
logger_default.info(`Copied video to ${destPath}`);
|
|
8309
|
+
}
|
|
8254
8310
|
}
|
|
8255
8311
|
const asset = new _MainVideoAsset(sourcePath, videoDir, slug);
|
|
8256
8312
|
try {
|