refactor: 全面重构代码并加白话注释,移动全局并行,去掉去向/重复记录
- 重构后端与前端,全程大白话注释(不懂程序也能看懂) - 移动阶段改为全局并行(MoveAll,工人数=CPU核心数) - 去掉记录每个文件搬去哪了(删除去向回填,解决写库卡顿) - 去掉重复文件标记与统计:重复判定改为 MD5+路径都相同才算,重复则原地忽略不移动;MD5 相同但路径不同仍照常搬 - 媒体库去掉归类目录列,看板去掉重复/归类分布统计
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user