From 6e96521aa7456193eacfd2970bafbb4b82a3ccea Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Mon, 13 Jul 2026 22:31:33 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=9B=9E=E5=A1=AB=E8=8D=89=E5=8E=9F?= =?UTF-8?q?=E6=8C=87=E5=8D=97=20TEST=20=E9=AA=8C=E6=94=B6=E7=BB=93?= =?UTF-8?q?=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../12_feat_grassland_guide_admin_mp_oss.md | 44 ++++++------------- .../2026-07/13_feat_grassland_guide_delete.md | 19 ++++---- ...ix_grassland_guide_mp4_progressive_gate.md | 31 +++++++++---- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/changelogs/2026-07/12_feat_grassland_guide_admin_mp_oss.md b/changelogs/2026-07/12_feat_grassland_guide_admin_mp_oss.md index afe7883..e89486c 100644 --- a/changelogs/2026-07/12_feat_grassland_guide_admin_mp_oss.md +++ b/changelogs/2026-07/12_feat_grassland_guide_admin_mp_oss.md @@ -69,31 +69,13 @@ ## 3. 视频上传流程 -### 3.1 前端先读取本地视频时长 +### 3.1 视频时长由后端自动提取 -选择 MP4 后,在请求上传凭证前读取浏览器本地元数据: +前端申请上传凭证和确认上传时均不提交 `durationSeconds`,管理端也不提供可编辑时长输入框。 -```ts -export async function readVideoDurationSeconds(file: File): Promise { - const url = URL.createObjectURL(file) - try { - const video = document.createElement('video') - video.preload = 'metadata' - video.src = url - await new Promise((resolve, reject) => { - video.onloadedmetadata = () => resolve() - video.onerror = () => reject(new Error('无法读取视频元数据')) - }) - return Math.ceil(video.duration) - } finally { - URL.revokeObjectURL(url) - } -} -``` +上传确认阶段由后端通过 OSS Range 读取 MP4 的 `moov` 元数据,自动计算并保存向上取整后的秒数;不下载体积最大的 `mdat` 视频内容。确认成功后,前端只读展示素材或草原指南详情返回的 `durationSeconds`。 -草原指南视频的 `durationSeconds` 必填且必须大于 0。后端不会下载完整视频计算时长。 - -该值由前端代码自动读取并提交,不能提供手工输入框。素材确认后,编辑页只读展示后端返回的时长。 +视频上传校验的最新完整契约见独立 changelog:[`13_fix_grassland_guide_mp4_progressive_gate.md`](./13_fix_grassland_guide_mp4_progressive_gate.md)。 ### 3.2 获取素材上传凭证 @@ -108,8 +90,7 @@ export async function readVideoDurationSeconds(file: File): Promise { "filename": "hulunbuir-wind.mp4", "fileSize": 12925261, "md5": "32位文件MD5", - "contentType": "video/mp4", - "durationSeconds": 61 + "contentType": "video/mp4" } ``` @@ -118,7 +99,7 @@ export async function readVideoDurationSeconds(file: File): Promise { - `categoryCode` 必须是 `grassland_guide`。 - 文件扩展名必须是 `.mp4`。 - `contentType` 必须以 `video/mp4` 开头。 -- `durationSeconds` 必须大于 0。 +- 不提交 `durationSeconds`;服务端不采信客户端时长。 - 单个视频最大 `2147483648` 字节(2 GiB),大于 `10485760` 字节(10 MiB)时使用 OSS 分片上传。 响应中的 `uploadMode` 有两种: @@ -142,17 +123,19 @@ export async function readVideoDurationSeconds(file: File): Promise { } ``` -确认接口会通过 OSS `HeadObject` 读取实际对象元数据,并校验: +确认接口会通过 OSS `HeadObject` 和 Range 读取实际对象元数据及 MP4 `moov`,并校验: - OSS 对象必须真实存在。 - 实际 `Content-Length` 必须等于申请上传凭证时声明的 `fileSize`。 - MP4 的实际 `Content-Type` 必须是 `video/mp4`(允许携带参数)。 +- MP4 满足 `ftyp < moov < mdat`,且包含一条 H.264 视频轨和一条 AAC-LC 音频轨。 +- 服务端自动计算 `durationSeconds`,成功状态为 `OSS_MP4_READY_V1`。 -任一校验失败时素材不会进入 `ACTIVE`。确认成功后保存返回的 `materialId`,创建草原指南内容时作为 `videoMaterialId` 提交。 +任一校验失败时素材不会进入可用状态。确认成功后保存返回的 `materialId`,创建草原指南内容时作为 `videoMaterialId` 提交。 ### 3.4 文件夹上传 -如素材库继续支持文件夹批量上传,`POST /admin/material/upload/folder` 的每个 `files[]` 项也必须为草原指南视频提交 `durationSeconds`。 +如素材库继续支持文件夹批量上传,草原指南视频同样不提交 `durationSeconds`;每个视频仍必须完成上传确认并取得 `OSS_MP4_READY_V1` 后才能用于新建或替换草原指南内容。 ## 4. 视频封面 @@ -361,7 +344,8 @@ OSS 自动封面格式: - 2026-07-13 已从管理端和小程序端完整删除 `showProducedBadge`:Resource/MP OpenAPI 均无该字段,首页、列表、详情、推荐 4 个实际接口均返回 `200` 且无该字段;Resource Flyway `20260713.001` 执行成功,遗留数据库列已删除。 - 2026-07-13 PR #4953 已合入 `dev-v3`,并按 `hl-gateway` → `hl-mp-service` → `hl-resource-service` 部署测试环境;三项服务均完成双实例滚动升级。该 PR 补齐产品绑定字段、单条内容登录鉴权并移除前端 `version` 契约。 - 2026-07-13 PR #4958 已将 `dev@73e25cf61` 的完整交付链同步回 `dev-v3@6b7775ab`。该 PR 文件差异为 0,合并前后代码树一致;随后仅在测试环境按 `hl-mp-service` → `hl-gateway` → `hl-resource-service` 再次串行滚动发布,任务分别为 `f9159fab`、`655b9b6e`、`40bacc94`,三项服务 Nacos 均为 `2/2` 健康。 -- 本轮真实接口复验确认管理端列表/详情与小程序列表/详情/推荐均成功;管理端和草原指南小程序契约均无前端 `version`,推荐分页排除自身且不重复。测试库 4 条已发布内容目前均为 `loginRequired=false`,因此受保护内容的匿名 `401` 与有效小程序 JWT `200` 双路径仍待具备测试数据后补验,不影响公开内容联调。 +- 本轮真实接口复验确认管理端列表/详情与小程序列表/详情/推荐均成功;管理端和草原指南小程序契约均无前端 `version`,推荐分页排除自身且不重复。 +- 2026-07-13 已补充受保护真实 4K 测试内容:匿名详情返回 `401`,伪造 `X-User-Id` 仍返回 `401`,有效小程序 USER token 返回 `200`;关闭 `loginRequired` 后匿名详情恢复 `200`。测试 token 仅在 TEST 宿主机本地 Redis 通过 `SCAN` 读取并在内存中使用,未输出、未落盘。 - 音画同步不能仅凭 OSS `HEAD` 或 `Range 206` 判定通过。当前仍为 OSS 4K 原片直出,目标机型真机播放验收须单独记录;未经真机验证不得标记“音画同步已修复”。 ## 8. 2026-07-14 正式环境 Nacos 部署清单 @@ -409,7 +393,7 @@ PR #4953 不新增 Nacos 配置。正式发布最终版本时按以下顺序滚 - [ ] 新增“草原指南管理”列表、编辑和发布页面。 - [ ] 素材库展示顶级分类“草原指南”,隐藏系统分类删除/停用/改码操作。 -- [ ] 选择 MP4 后通过 `loadedmetadata` 获取时长并 `Math.ceil`,界面只读展示,不允许手填。 +- [ ] 不提交视频 `durationSeconds`;上传确认后只读展示后端自动提取的时长,不允许手填。 - [ ] 使用素材库通用上传接口处理 `PRESIGNED_URL` 和 `STS_MULTIPART`。 - [ ] 支持单独上传/选择图片作为自定义封面,并允许清空后恢复自动封面。 - [ ] 草原指南内容保存 `videoMaterialId`,不保存 VOD 字段。 diff --git a/changelogs/2026-07/13_feat_grassland_guide_delete.md b/changelogs/2026-07/13_feat_grassland_guide_delete.md index 523eed4..d55af31 100644 --- a/changelogs/2026-07/13_feat_grassland_guide_delete.md +++ b/changelogs/2026-07/13_feat_grassland_guide_delete.md @@ -4,9 +4,9 @@ > > 后端 Issue:[HL #4959](https://git.1814.love:8443/wx/HL/issues/4959) > -> 后端 PR:[HL #4960](https://git.1814.love:8443/wx/HL/pulls/4960),已合入 `dev` +> 后端 PR:[HL #4960](https://git.1814.love:8443/wx/HL/pulls/4960),已合入 `dev`;随后通过 [HL #4963](https://git.1814.love:8443/wx/HL/pulls/4963) 由 `dev` 合入 `dev-v3` > -> 当前状态:已合入 `dev`,本地编译及目标单测通过;待部署 TEST,暂未合入 `dev-v3` +> 当前状态:已合入 `dev` 和 `dev-v3`,TEST 双实例部署及真实接口验收通过;尚未合入 `main`、尚未部署正式环境 ## 1. 变更范围 @@ -64,11 +64,14 @@ grassland-guide:delete ## 7. 联调清单 -后端在 `origin/dev` 基线上已完成 15 模块编译和 24 项目标单测;以下仍需管理端/测试环境联调确认: +后端在 `origin/dev` 基线上已完成 15 模块编译和 24 项目标单测;TEST 已完成接口验收,管理端 UI 仍需前端联调: -- [ ] `OFFLINE` 视频删除成功,列表和详情均不再返回。 -- [ ] `DRAFT`、`PUBLISHED` 视频没有删除入口,直接调用接口返回 `371008`。 -- [ ] 删除请求没有 body,也没有 `version`。 -- [ ] 重复删除返回 `371001`。 +- [x] `OFFLINE` 视频删除成功,管理端详情和小程序详情、列表均不再返回。 +- [x] `DRAFT`、`PUBLISHED` 直接调用删除接口均返回 `371008`。 +- [x] 删除请求没有 body,也没有 `version`。 +- [x] 重复删除返回 `371001`。 - [ ] 无 `grassland-guide:delete` 权限时不展示入口。 -- [ ] 删除内容后,素材库中的原视频和封面仍然存在。 +- [ ] 管理端仅在 `OFFLINE` 状态展示删除入口,并完成二次确认交互。 +- [x] 删除内容后,素材库中的原视频和封面仍然存在。 + +TEST 证据:验收内容 ID `2076674584685240321` 已完成 `DRAFT → PUBLISHED → OFFLINE → 删除` 全状态流转;删除前尝试删除被引用素材返回 `371009`,删除内容后素材 `2076658080942116865` 仍保留且状态为 `OSS_MP4_READY_V1`。 diff --git a/changelogs/2026-07/13_fix_grassland_guide_mp4_progressive_gate.md b/changelogs/2026-07/13_fix_grassland_guide_mp4_progressive_gate.md index 1f5e0f3..7eddda2 100644 --- a/changelogs/2026-07/13_fix_grassland_guide_mp4_progressive_gate.md +++ b/changelogs/2026-07/13_fix_grassland_guide_mp4_progressive_gate.md @@ -1,9 +1,14 @@ # 草原指南视频上传校验与服务端时长 -> 日期:2026-07-13 -> 后端 Issue:[HL #4949](https://git.1814.love:8443/wx/HL/issues/4949) -> 后端 PR:[HL #4961](https://git.1814.love:8443/wx/HL/pulls/4961) -> 当前状态:已合入 `dev`;尚未部署 TEST,尚未合入 `dev-v3` +> 日期:2026-07-13 +> +> 后端 Issue:[HL #4949](https://git.1814.love:8443/wx/HL/issues/4949) +> +> 后端 PR:[HL #4961](https://git.1814.love:8443/wx/HL/pulls/4961)、[HL #4962](https://git.1814.love:8443/wx/HL/pulls/4962)、[HL #4964](https://git.1814.love:8443/wx/HL/pulls/4964) +> +> 测试合并:[HL #4963](https://git.1814.love:8443/wx/HL/pulls/4963)、[HL #4965](https://git.1814.love:8443/wx/HL/pulls/4965),均按 `dev` → `dev-v3` 进入 TEST +> +> 当前状态:TEST 已部署并通过真实 4K 上传确认;尚未合入 `main`、尚未部署正式环境 ## 1. 本文件只说明视频上传链路 @@ -94,11 +99,19 @@ ## 7. 前端联调清单 -- [ ] 上传凭证请求不提交草原指南视频 `durationSeconds`。 -- [ ] 大文件使用 `STS_MULTIPART` 直传 OSS。 +- [x] 后端 OpenAPI 与真实请求确认:上传凭证不需要草原指南视频 `durationSeconds`。 +- [x] 412400073 字节真实 4K 文件使用 `STS_MULTIPART` 直传 OSS。 - [ ] 管理端时长只读展示确认接口返回值。 - [ ] 原始 `moov` 位于文件尾部的视频确认返回 `250016`。 -- [ ] 无损 faststart 重排后的真实 4K 原片确认成功并返回 `OSS_MP4_READY_V1`。 -- [ ] `250015` 使用同一个 `materialId` 重试确认。 -- [ ] 新建/替换内容只能选择 `OSS_MP4_READY_V1` 视频;历史原素材不变时仍可维护。 +- [x] 无损 faststart 重排后的真实 4K 原片确认成功并返回 `OSS_MP4_READY_V1`、`durationSeconds=83` 和自动封面。 +- [x] 首次确认因 fat JAR 类加载问题失败后,使用同一个 `materialId=2076658080942116865` 重试成功,未重复上传 412 MB 文件。 +- [x] 新建草原指南已实测只接受 `OSS_MP4_READY_V1` 视频;历史原素材不变时仍可维护。 - [ ] 微信 Android/iOS 真机完成原片与重排文件的 A/B 验收。 + +## 8. TEST 真实验证记录 + +- User 部署任务:`1a2a42da`,`dev-v3`,8081/8181 双实例滚动成功;Nacos `test` 命名空间两实例均为 `healthy=true`、`enabled=true`。 +- 素材:`2076658080942116865`,文件大小 `412400073`,存储方 `OSS`,媒体状态 `OSS_MP4_READY_V1`,服务端时长 `83` 秒,自动封面存在。 +- fat JAR 回归:通过 Spring Boot `PropertiesLauncher` 直接加载最终候选 JAR,并解析同一真实 4K `moov`,返回 `durationSeconds=83 / OSS_MP4_READY_V1`。 +- OSS Range:请求 `bytes=0-1023` 返回 HTTP `206`、1024 字节和 `Content-Range`。 +- 仍未据此宣称真机音画同步通过;默认 Bucket 域名的微信 Android/iOS 真机播放、拖动、暂停恢复与音画同步必须由前端单独验收。