🎨 Improve detection of duplicate insertion of assets https://github.com/siyuan-note/siyuan/issues/16220

Signed-off-by: Daniel <845765@qq.com>
This commit is contained in:
Daniel 2025-10-28 11:01:12 +08:00
parent 920f7e4623
commit 2567526672
No known key found for this signature in database
GPG key ID: 86211BA83DF03017
3 changed files with 75 additions and 9 deletions

50
kernel/cache/asset.go vendored
View file

@ -28,14 +28,60 @@ import (
"github.com/siyuan-note/siyuan/kernel/util" "github.com/siyuan-note/siyuan/kernel/util"
) )
type AssetHash struct {
Hash string `json:"hash"`
Path string `json:"path"`
}
var (
assetHashCache = map[string]*AssetHash{}
assetHashLock = sync.Mutex{}
)
func RemoveAssetHash(hash string) {
assetHashLock.Lock()
defer assetHashLock.Unlock()
delete(assetHashCache, hash)
}
func SetAssetHash(hash, path string) {
assetHashLock.Lock()
defer assetHashLock.Unlock()
assetHashCache[hash] = &AssetHash{
Hash: hash,
Path: path,
}
}
func GetAssetHash(hash string) *AssetHash {
assetHashLock.Lock()
defer assetHashLock.Unlock()
for _, a := range assetHashCache {
if a.Hash == hash {
if filelock.IsExist(filepath.Join(util.DataDir, a.Path)) {
return a
}
delete(assetHashCache, hash)
return nil
}
}
return nil
}
type Asset struct { type Asset struct {
HName string `json:"hName"` HName string `json:"hName"`
Path string `json:"path"` Path string `json:"path"`
Updated int64 `json:"updated"` Updated int64 `json:"updated"`
} }
var assetsCache = map[string]*Asset{} var (
var assetsLock = sync.Mutex{} assetsCache = map[string]*Asset{}
assetsLock = sync.Mutex{}
)
func GetAssets() (ret map[string]*Asset) { func GetAssets() (ret map[string]*Asset) {
assetsLock.Lock() assetsLock.Lock()

View file

@ -51,6 +51,19 @@ import (
"github.com/siyuan-note/siyuan/kernel/util" "github.com/siyuan-note/siyuan/kernel/util"
) )
func GetAssetPathByHash(hash string) string {
assetHash := cache.GetAssetHash(hash)
if nil == assetHash {
sqlAsset := sql.QueryAssetByHash(hash)
if nil == sqlAsset {
return ""
}
cache.SetAssetHash(sqlAsset.Hash, sqlAsset.Path)
return sqlAsset.Path
}
return assetHash.Path
}
func HandleAssetsRemoveEvent(assetAbsPath string) { func HandleAssetsRemoveEvent(assetAbsPath string) {
removeIndexAssetContent(assetAbsPath) removeIndexAssetContent(assetAbsPath)
removeAssetThumbnail(assetAbsPath) removeAssetThumbnail(assetAbsPath)
@ -648,6 +661,7 @@ func RemoveUnusedAssets() (ret []string) {
hash, _ := util.GetEtag(p) hash, _ := util.GetEtag(p)
hashes = append(hashes, hash) hashes = append(hashes, hash)
cache.RemoveAssetHash(hash)
} }
} }
@ -703,6 +717,7 @@ func RemoveUnusedAsset(p string) (ret string) {
hash, _ := util.GetEtag(absPath) hash, _ := util.GetEtag(absPath)
sql.BatchRemoveAssetsQueue([]string{hash}) sql.BatchRemoveAssetsQueue([]string{hash})
cache.RemoveAssetHash(hash)
} }
if err = filelock.Remove(absPath); err != nil { if err = filelock.Remove(absPath); err != nil {

View file

@ -29,7 +29,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/siyuan-note/filelock" "github.com/siyuan-note/filelock"
"github.com/siyuan-note/logging" "github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/sql" "github.com/siyuan-note/siyuan/kernel/cache"
"github.com/siyuan-note/siyuan/kernel/treenode" "github.com/siyuan-note/siyuan/kernel/treenode"
"github.com/siyuan-note/siyuan/kernel/util" "github.com/siyuan-note/siyuan/kernel/util"
) )
@ -90,9 +90,9 @@ func InsertLocalAssets(id string, assetAbsPaths []string, isUpload bool) (succMa
return return
} }
if existAsset := sql.QueryAssetByHash(hash); nil != existAsset { if existAssetPath := GetAssetPathByHash(hash); "" != existAssetPath {
// 已经存在同样数据的资源文件的话不重复保存 // 已经存在同样数据的资源文件的话不重复保存
succMap[baseName] = existAsset.Path succMap[baseName] = existAssetPath
} else { } else {
fName = util.AssetName(fName, ast.NewNodeID()) fName = util.AssetName(fName, ast.NewNodeID())
writePath := filepath.Join(assetsDirPath, fName) writePath := filepath.Join(assetsDirPath, fName)
@ -105,7 +105,10 @@ func InsertLocalAssets(id string, assetAbsPaths []string, isUpload bool) (succMa
return return
} }
f.Close() f.Close()
succMap[baseName] = "assets/" + fName
p := "assets/" + fName
succMap[baseName] = p
cache.SetAssetHash(hash, p)
} }
} }
IncSync() IncSync()
@ -197,9 +200,9 @@ func Upload(c *gin.Context) {
break break
} }
if existAsset := sql.QueryAssetByHash(hash); nil != existAsset { if existAssetPath := GetAssetPathByHash(hash); "" != existAssetPath {
// 已经存在同样数据的资源文件的话不重复保存 // 已经存在同样数据的资源文件的话不重复保存
succMap[baseName] = existAsset.Path succMap[baseName] = existAssetPath
} else { } else {
if skipIfDuplicated { if skipIfDuplicated {
// 复制 PDF 矩形注解时不再重复插入图片 No longer upload image repeatedly when copying PDF rectangle annotation https://github.com/siyuan-note/siyuan/issues/10666 // 复制 PDF 矩形注解时不再重复插入图片 No longer upload image repeatedly when copying PDF rectangle annotation https://github.com/siyuan-note/siyuan/issues/10666
@ -310,7 +313,9 @@ func Upload(c *gin.Context) {
os.RemoveAll(tmpDir2) os.RemoveAll(tmpDir2)
} }
succMap[baseName] = strings.TrimPrefix(path.Join(relAssetsDirPath, fName), "/") p := strings.TrimPrefix(path.Join(relAssetsDirPath, fName), "/")
succMap[baseName] = p
cache.SetAssetHash(hash, p)
} }
} }