"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 };