refactor: 全面重构代码并加白话注释,移动全局并行,去掉去向/重复记录

- 重构后端与前端,全程大白话注释(不懂程序也能看懂)
- 移动阶段改为全局并行(MoveAll,工人数=CPU核心数)
- 去掉记录每个文件搬去哪了(删除去向回填,解决写库卡顿)
- 去掉重复文件标记与统计:重复判定改为 MD5+路径都相同才算,重复则原地忽略不移动;MD5 相同但路径不同仍照常搬
- 媒体库去掉归类目录列,看板去掉重复/归类分布统计
This commit is contained in:
2025-05-11 21:05:35 +08:00
parent f915a9b1ac
commit 8979c744a8
26 changed files with 1044 additions and 683 deletions
+19 -12
View File
@@ -1,3 +1,6 @@
// 媒体库的两个接口:查列表、查统计。
// 「媒体库」页面查列表(带筛选和分页),「统计看板」页面查统计。
// 这两个接口只读数据库,不干别的活。
package api
import (
@@ -11,17 +14,17 @@ import (
"kenaito-media-picker/internal/store"
)
// MediaController 媒体库接口
// MediaController 媒体库相关接口的"窗口"。
type MediaController struct {
store *store.Store
store *store.Store // 数据库(只读)
}
// NewMediaController 创建媒体控制器,注入数据访问层
// NewMediaController 创建媒体库控制器,注入数据库。
func NewMediaController(st *store.Store) *MediaController {
return &MediaController{store: st}
}
// mediaListReq 列表查询请求
// mediaListReq 媒体库列表的查询条件(前端「媒体库」页面传过来的)。
type mediaListReq struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
@@ -35,16 +38,17 @@ type mediaListReq struct {
SortOrder string `json:"sortOrder"`
}
// mediaView 列表展示视图:补充方向/分辨率/可读大小等派生字段
// mediaView 列表里展示的一条记录:在数据库记录的基础上,
// 再补几个"现算"的字段(方向、分辨率档位、人类可读的体积和时长),方便页面直接显示。
type mediaView struct {
store.MediaInfo
Orientation string `json:"orientation"` // 横屏/竖屏/等比
Resolution string `json:"resolution"` // 分辨率档位
SizeText string `json:"sizeText"` // 人类可读体积
DurationText string `json:"durationText"` // 人类可读时长
Resolution string `json:"resolution"` // 分辨率档位(如 1080P)
SizeText string `json:"sizeText"` // 人类可读体积(如 1.5 MB)
DurationText string `json:"durationText"` // 人类可读时长(如 05:30)
}
// List POST /api/media/list 分页查询媒体库
// List 处理 POST /api/media/list:按条件分页查媒体库列表。
func (c *MediaController) List(ctx *gin.Context) {
var req mediaListReq
if err := ctx.ShouldBindJSON(&req); err != nil {
@@ -67,6 +71,7 @@ func (c *MediaController) List(ctx *gin.Context) {
SortOrder: req.SortOrder,
}
// 查这一页的数据,同时查总条数(分页条要用)
list, err := c.store.ListMedia(q)
if err != nil {
Error(ctx, http.StatusInternalServerError, "查询媒体列表失败:"+err.Error())
@@ -78,6 +83,7 @@ func (c *MediaController) List(ctx *gin.Context) {
return
}
// 每条记录补上"现算"的展示字段再返回
views := make([]interface{}, 0, len(list))
for _, m := range list {
views = append(views, toMediaView(m))
@@ -85,7 +91,7 @@ func (c *MediaController) List(ctx *gin.Context) {
Success(ctx, map[string]interface{}{"list": views, "total": total})
}
// Stats POST /api/media/stats 媒体库统计看板
// Stats 处理 POST /api/media/stats:统计看板要用的全部数据。
func (c *MediaController) Stats(ctx *gin.Context) {
st, err := c.store.Stats()
if err != nil {
@@ -95,9 +101,10 @@ func (c *MediaController) Stats(ctx *gin.Context) {
Success(ctx, st)
}
// toMediaView 补充派生字段
// toMediaView 给一条数据库记录补上展示用的派生字段。
func toMediaView(m store.MediaInfo) mediaView {
v := mediaView{MediaInfo: m}
// 宽高有效才算方向和分辨率档位
if m.Width > 0 && m.Height > 0 {
v.Orientation = classify.OrientationOf(m.Width, m.Height).String()
v.Resolution = classify.ResLabel(m.Width, m.Height)
@@ -111,7 +118,7 @@ func toMediaView(m store.MediaInfo) mediaView {
return v
}
// formatDuration 秒 → 时:分:秒
// formatDuration 把秒数转成人类可读的时:分:秒。
func formatDuration(sec float64) string {
s := int(sec)
h := s / 3600