65 lines
1.7 KiB
JavaScript
65 lines
1.7 KiB
JavaScript
"use strict";
|
||
|
||
/**
|
||
* 发布前封面适配(对齐 Electron CoverAdapter / PLATFORM_REQUIREMENTS.douyin)
|
||
*/
|
||
const fs = require("fs");
|
||
const path = require("path");
|
||
const os = require("os");
|
||
const { spawnSync } = require("child_process");
|
||
const pipelineNative = require("./pipeline_native.js");
|
||
|
||
const PLATFORM_COVER = {
|
||
douyin: { width: 1080, height: 1920, format: "jpg" },
|
||
};
|
||
|
||
function ensurePublishCoverDir() {
|
||
const dir = path.join(os.tmpdir(), "aiclient-publish-cover");
|
||
fs.mkdirSync(dir, { recursive: true });
|
||
return dir;
|
||
}
|
||
|
||
/**
|
||
* @param {string} coverPath
|
||
* @param {'douyin'|'kuaishou'|'shipin'|'xiaohongshu'} [platform]
|
||
* @returns {string}
|
||
*/
|
||
function adaptCoverForPublish(coverPath, platform = "douyin") {
|
||
const req = PLATFORM_COVER[platform];
|
||
if (!req) return coverPath;
|
||
if (!fs.existsSync(coverPath)) {
|
||
throw new Error(`封面文件不存在: ${coverPath}`);
|
||
}
|
||
|
||
const ffmpeg = pipelineNative.locateFfmpeg();
|
||
if (!ffmpeg) {
|
||
console.warn("[publish_cover_adapt] 未找到 ffmpeg,使用原始封面");
|
||
return coverPath;
|
||
}
|
||
|
||
const outPath = path.join(
|
||
ensurePublishCoverDir(),
|
||
`${platform}_${Date.now()}.jpg`,
|
||
);
|
||
const { width, height } = req;
|
||
const vf = `scale=${width}:${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2:black`;
|
||
|
||
const r = spawnSync(
|
||
ffmpeg,
|
||
["-y", "-i", coverPath, "-vf", vf, "-q:v", "2", outPath],
|
||
{ encoding: "utf8", windowsHide: true },
|
||
);
|
||
|
||
if (r.status !== 0 || !fs.existsSync(outPath)) {
|
||
console.warn(
|
||
"[publish_cover_adapt] ffmpeg 适配失败,使用原始封面:",
|
||
(r.stderr || "").slice(0, 200),
|
||
);
|
||
return coverPath;
|
||
}
|
||
|
||
return outPath;
|
||
}
|
||
|
||
module.exports = { adaptCoverForPublish, PLATFORM_COVER };
|