feat: 媒体库 blob 去重存储与品牌/注册等前端调整
新增: - blob_store 二进制去重存储 + blob_dedup 测试 其它: - 后端 settings/auth/media_library/upload/operations 服务与 handler 调整 - 前端品牌(BrandLockup/BrandCropModal/BrandSeoPanel)、注册、媒体库、分析详情页、Header/SiteChrome 等更新
This commit is contained in:
@@ -64,6 +64,7 @@ type MediaLibraryItem struct {
|
||||
Height int `json:"height"`
|
||||
Uploader string `json:"uploader,omitempty"` // 上传者昵称(取自附件记录,无记录为空)
|
||||
UploadedAt *time.Time `json:"uploaded_at,omitempty"`
|
||||
RefCount int `json:"ref_count,omitempty"` // 引用计数(>1 表示内容相同的重复上传共享此文件)
|
||||
SourceURL string `json:"source_url,omitempty"` // 来源回链(帖子/评论锚点/用户主页)
|
||||
SourceLabel string `json:"source_label,omitempty"` // 来源描述(如:帖子《…》下的评论)
|
||||
}
|
||||
@@ -91,13 +92,29 @@ func (s *UploadService) AdminMediaLibrary() ([]MediaLibraryItem, map[string]int,
|
||||
Scan(&rows).Error; err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
metaByURL := make(map[string]attMeta, len(rows))
|
||||
// 远程存储对象(/api/media/)不在磁盘上,直接作为条目加入
|
||||
items := make([]MediaLibraryItem, 0, len(rows))
|
||||
// 同 URL 多条记录(内容寻址去重后,重复上传共享同一文件):
|
||||
// 上传者/时间取最早一条,计数即该文件的引用次数
|
||||
type urlMeta struct {
|
||||
meta attMeta
|
||||
count int
|
||||
}
|
||||
agg := make(map[string]*urlMeta, len(rows))
|
||||
for _, r := range rows {
|
||||
metaByURL[r.URL] = r // 本地文件在磁盘扫描时按 URL 合并元数据
|
||||
if !strings.HasPrefix(r.URL, "/api/media/") {
|
||||
continue
|
||||
if a, ok := agg[r.URL]; ok {
|
||||
a.count++
|
||||
if r.CreatedAt.Before(a.meta.CreatedAt) {
|
||||
a.meta = r
|
||||
}
|
||||
} else {
|
||||
agg[r.URL] = &urlMeta{meta: r, count: 1}
|
||||
}
|
||||
}
|
||||
// 远程存储对象(/api/media/)不在磁盘上,按 URL 去重后直接作为条目加入
|
||||
items := make([]MediaLibraryItem, 0, len(agg))
|
||||
for url, a := range agg {
|
||||
r := a.meta
|
||||
if !strings.HasPrefix(url, "/api/media/") {
|
||||
continue // 本地文件在磁盘扫描时按 URL 合并元数据
|
||||
}
|
||||
if r.Kind != model.AttachmentKindImage && r.Kind != model.AttachmentKindAvatar {
|
||||
continue // 未知 kind 不进媒体库
|
||||
@@ -109,10 +126,10 @@ func (s *UploadService) AdminMediaLibrary() ([]MediaLibraryItem, map[string]int,
|
||||
catKey, catName := mediaCategoryForAttachment(r.Kind, r.Source)
|
||||
ca := r.CreatedAt
|
||||
items = append(items, MediaLibraryItem{
|
||||
URL: r.URL, Category: catKey, CategoryName: catName,
|
||||
Name: strings.TrimPrefix(r.URL, "/api/media/"), MIME: r.MIME,
|
||||
URL: url, Category: catKey, CategoryName: catName,
|
||||
Name: strings.TrimPrefix(url, "/api/media/"), MIME: r.MIME,
|
||||
Size: int64(r.Size), Width: r.Width, Height: r.Height,
|
||||
Uploader: uploader, UploadedAt: &ca,
|
||||
Uploader: uploader, UploadedAt: &ca, RefCount: a.count,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -152,8 +169,9 @@ func (s *UploadService) AdminMediaLibrary() ([]MediaLibraryItem, map[string]int,
|
||||
mt := info.ModTime()
|
||||
item.UploadedAt = &mt
|
||||
}
|
||||
if m, ok := metaByURL[url]; ok {
|
||||
if a, ok := agg[url]; ok {
|
||||
// 附件记录有上传者与准确创建时间,覆盖磁盘信息
|
||||
m := a.meta
|
||||
uploader := m.Nickname
|
||||
if uploader == "" {
|
||||
uploader = m.Username
|
||||
@@ -161,6 +179,7 @@ func (s *UploadService) AdminMediaLibrary() ([]MediaLibraryItem, map[string]int,
|
||||
ca := m.CreatedAt
|
||||
item.Uploader = uploader
|
||||
item.UploadedAt = &ca
|
||||
item.RefCount = a.count
|
||||
if m.Size > 0 {
|
||||
item.Size = int64(m.Size)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user