From 558f1cdabc705fce03cc40775b5acd8297f297db Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 4 Jun 2023 10:30:19 +0800 Subject: [PATCH] :art: Support for listing missing files in Settings - Assets https://github.com/siyuan-note/siyuan/issues/8383 --- kernel/api/asset.go | 10 +++++++ kernel/api/router.go | 1 + kernel/conf/search.go | 2 ++ kernel/model/assets.go | 66 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) diff --git a/kernel/api/asset.go b/kernel/api/asset.go index 9e1d94220..8de72d5a3 100644 --- a/kernel/api/asset.go +++ b/kernel/api/asset.go @@ -210,6 +210,16 @@ func getUnusedAssets(c *gin.Context) { } } +func getMissingAssets(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + missingAssets := model.MissingAssets() + ret.Data = map[string]interface{}{ + "missingAssets": missingAssets, + } +} + func resolveAssetPath(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) diff --git a/kernel/api/router.go b/kernel/api/router.go index f41165aa4..93143da0e 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -224,6 +224,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/asset/setFileAnnotation", model.CheckAuth, model.CheckReadonly, setFileAnnotation) ginServer.Handle("POST", "/api/asset/getFileAnnotation", model.CheckAuth, getFileAnnotation) ginServer.Handle("POST", "/api/asset/getUnusedAssets", model.CheckAuth, getUnusedAssets) + ginServer.Handle("POST", "/api/asset/getMissingAssets", model.CheckAuth, getMissingAssets) ginServer.Handle("POST", "/api/asset/removeUnusedAsset", model.CheckAuth, model.CheckReadonly, removeUnusedAsset) ginServer.Handle("POST", "/api/asset/removeUnusedAssets", model.CheckAuth, model.CheckReadonly, removeUnusedAssets) ginServer.Handle("POST", "/api/asset/getDocImageAssets", model.CheckAuth, model.CheckReadonly, getDocImageAssets) diff --git a/kernel/conf/search.go b/kernel/conf/search.go index 985f2dbbe..a4672724c 100644 --- a/kernel/conf/search.go +++ b/kernel/conf/search.go @@ -83,6 +83,8 @@ func NewSearch() *Search { Memo: true, IAL: false, + IndexAssetPath: true, + BacklinkMentionName: true, BacklinkMentionAlias: false, BacklinkMentionAnchor: true, diff --git a/kernel/model/assets.go b/kernel/model/assets.go index d0626564b..b7d406287 100644 --- a/kernel/model/assets.go +++ b/kernel/model/assets.go @@ -680,6 +680,72 @@ func UnusedAssets() (ret []string) { return } +func MissingAssets() (ret []string) { + defer logging.Recover() + ret = []string{} + + assetsPathMap, err := allAssetAbsPaths() + if nil != err { + return + } + notebooks, err := ListNotebooks() + if nil != err { + return + } + luteEngine := util.NewLute() + for _, notebook := range notebooks { + dests := map[string]bool{} + + pages := pagedPaths(filepath.Join(util.DataDir, notebook.ID), 32) + for _, paths := range pages { + var trees []*parse.Tree + for _, localPath := range paths { + tree, loadTreeErr := loadTree(localPath, luteEngine) + if nil != loadTreeErr { + continue + } + trees = append(trees, tree) + } + for _, tree := range trees { + for _, d := range assetsLinkDestsInTree(tree) { + dests[d] = true + } + + if titleImgPath := treenode.GetDocTitleImgPath(tree.Root); "" != titleImgPath { + // 题头图计入 + if !util.IsAssetLinkDest([]byte(titleImgPath)) { + continue + } + dests[titleImgPath] = true + } + } + } + + for dest, _ := range dests { + if !strings.HasPrefix(dest, "assets/") { + continue + } + + if idx := strings.Index(dest, "?"); 0 < idx { + dest = dest[:idx] + } + + if strings.HasSuffix(dest, "/") { + continue + } + + if "" == assetsPathMap[dest] { + ret = append(ret, dest) + continue + } + + } + } + + sort.Strings(ret) + return +} + func emojisInTree(tree *parse.Tree) (ret []string) { ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus { if !entering {