From 6b2a60de3240b7b3e054ee4cc6987d9637c099ed Mon Sep 17 00:00:00 2001 From: MaDaLei Date: Sun, 19 Apr 2026 15:44:49 +0800 Subject: [PATCH] deploy 04191544 --- .../petstore/controller/ReportController.java | 11 ++++++ src/main/java/com/petstore/entity/Report.java | 7 ++++ .../service/ReportHighlightVideoService.java | 34 +++++++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/petstore/controller/ReportController.java b/src/main/java/com/petstore/controller/ReportController.java index 497f792..e0cf044 100644 --- a/src/main/java/com/petstore/controller/ReportController.java +++ b/src/main/java/com/petstore/controller/ReportController.java @@ -62,8 +62,19 @@ public class ReportController { return "photo"; } + /** + * 报告 JSON 中与「服务回顾短片」相关的字段(与小程序 / H5 共用契约)。 + * + */ private void putHighlightFields(Map target, Report r) { target.put("highlightVideoUrl", r.getHighlightVideoUrl() != null ? fullUrl(r.getHighlightVideoUrl()) : null); + target.put("highlightShareCoverUrl", r.getHighlightShareCoverUrl() != null ? fullUrl(r.getHighlightShareCoverUrl()) : null); + target.put("highlightPosterUrl", null); target.put("highlightVideoStatus", r.getHighlightVideoStatus()); target.put("highlightVideoError", r.getHighlightVideoError()); target.put("highlightDurationSec", r.getHighlightDurationSec()); diff --git a/src/main/java/com/petstore/entity/Report.java b/src/main/java/com/petstore/entity/Report.java index bae7511..97469c3 100644 --- a/src/main/java/com/petstore/entity/Report.java +++ b/src/main/java/com/petstore/entity/Report.java @@ -75,4 +75,11 @@ public class Report { /** 失败原因归类:material | service | network | unknown(对宠主展示,无技术细节) */ @Column(name = "highlight_fail_reason", length = 16) private String highlightFailReason; + + /** + * 成片首帧截图(竖屏内一帧),用于分享卡片封面等;相对路径如 {@code /api/upload/image/年/月/日/xxx_cover.jpg}。 + * 与成片 MP4 同目录;仅当 highlight 状态为 done 且截帧成功时有值。 + */ + @Column(name = "highlight_share_cover_url", length = 500) + private String highlightShareCoverUrl; } diff --git a/src/main/java/com/petstore/service/ReportHighlightVideoService.java b/src/main/java/com/petstore/service/ReportHighlightVideoService.java index f468062..142ea5a 100644 --- a/src/main/java/com/petstore/service/ReportHighlightVideoService.java +++ b/src/main/java/com/petstore/service/ReportHighlightVideoService.java @@ -143,6 +143,7 @@ public class ReportHighlightVideoService { report.setHighlightVideoStatus("processing"); report.setHighlightVideoError(null); report.setHighlightFailReason(null); + report.setHighlightShareCoverUrl(null); report.setHighlightComposeMode(mode); report.setUpdateTime(LocalDateTime.now()); reportMapper.save(report); @@ -356,13 +357,20 @@ public class ReportHighlightVideoService { Path finalPath = outDir.resolve(filename); Files.copy(afterBgm, finalPath, StandardCopyOption.REPLACE_EXISTING); - String publicBase = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl; - String url = publicBase + "/api/upload/image/" + datePath + "/" + filename; + String videoRel = "/api/upload/image/" + datePath + "/" + filename; + String coverFilename = filename.endsWith(".mp4") + ? filename.substring(0, filename.length() - 4) + "_cover.jpg" + : filename + "_cover.jpg"; + Path coverPath = outDir.resolve(coverFilename); + String coverRel = extractVideoCoverFrame(finalPath, coverPath) + ? "/api/upload/image/" + datePath + "/" + coverFilename + : null; int durationRoundedSec = (int) Math.ceil(totalDurationSec); synchronized (lockFor(reportId)) { reportMapper.findByIdAndDeletedFalse(reportId).ifPresent(r -> { - r.setHighlightVideoUrl(url); + r.setHighlightVideoUrl(videoRel); + r.setHighlightShareCoverUrl(coverRel); r.setHighlightVideoStatus("done"); r.setHighlightVideoError(null); r.setHighlightFailReason(null); @@ -451,6 +459,26 @@ public class ReportHighlightVideoService { /** * 服务前第一张 | 服务后第一张 左右拼接为 1080×1920 竖屏对比图(左前右后)。 */ + /** + * 从成片 MP4 截取首帧为 JPEG,供分享卡片等使用。 + * + * @return 是否写出有效文件 + */ + private boolean extractVideoCoverFrame(Path mp4, Path outJpg) { + try { + int code = runFfmpeg(List.of( + ffmpegBinary, "-y", + "-i", mp4.toString(), + "-map", "0:v:0", + "-frames:v", "1", + "-q:v", "2", + outJpg.toString())); + return code == 0 && Files.isRegularFile(outJpg); + } catch (Exception e) { + return false; + } + } + private boolean buildComparisonCover(Path beforeFile, Path afterFile, Path outJpg) throws Exception { String fc = "[0:v]scale=540:1920:force_original_aspect_ratio=decrease,pad=540:1920:(ow-iw)/2:(oh-ih)/2,setsar=1[va];" + "[1:v]scale=540:1920:force_original_aspect_ratio=decrease,pad=540:1920:(ow-iw)/2:(oh-ih)/2,setsar=1[vb];"