diff --git a/app/src/history/diff.ts b/app/src/history/diff.ts index 797b3498a..c105520a4 100644 --- a/app/src/history/diff.ts +++ b/app/src/history/diff.ts @@ -75,7 +75,7 @@ const renderCompare = (app: App, element: HTMLElement) => { textElement.previousElementSibling.classList.remove("fn__none"); textElement.classList.add("fn__none"); leftElement.lastElementChild.classList.add("fn__none"); - } else if (response.data.isLargeDoc) { + } else if (response.data.isProtyleDoc) { textElement.value = response.data.content; textElement.classList.remove("fn__none"); leftElement.lastElementChild.classList.add("fn__none"); @@ -103,7 +103,7 @@ const renderCompare = (app: App, element: HTMLElement) => { textElement.previousElementSibling.classList.remove("fn__none"); textElement.classList.add("fn__none"); rightElement.lastElementChild.classList.add("fn__none"); - } else if (response.data.isLargeDoc) { + } else if (response.data.isProtyleDoc) { textElement.value = response.data.content; textElement.classList.remove("fn__none"); rightElement.lastElementChild.classList.add("fn__none"); diff --git a/kernel/api/repo.go b/kernel/api/repo.go index 7ec3fbd9f..0b82f82e7 100644 --- a/kernel/api/repo.go +++ b/kernel/api/repo.go @@ -36,7 +36,7 @@ func openRepoSnapshotDoc(c *gin.Context) { } id := arg["id"].(string) - id, rootID, content, isLargeDoc, updated, err := model.OpenRepoSnapshotDoc(id) + content, isProtyleDoc, updated, err := model.OpenRepoSnapshotDoc(id) if nil != err { ret.Code = -1 ret.Msg = err.Error() @@ -44,11 +44,9 @@ func openRepoSnapshotDoc(c *gin.Context) { } ret.Data = map[string]interface{}{ - "id": id, - "rootID": rootID, - "content": content, - "isLargeDoc": isLargeDoc, - "updated": updated, + "content": content, + "isProtyleDoc": isProtyleDoc, + "updated": updated, } } diff --git a/kernel/model/repository.go b/kernel/model/repository.go index a44b82df7..45474dd5a 100644 --- a/kernel/model/repository.go +++ b/kernel/model/repository.go @@ -71,7 +71,7 @@ type TypeCount struct { Count int `json:"count"` } -func OpenRepoSnapshotDoc(fileID string) (id, rootID, content string, isLargeDoc bool, updated int64, err error) { +func OpenRepoSnapshotDoc(fileID string) (content string, isProtyleDoc bool, updated int64, err error) { if 1 > len(Conf.Repo.Key) { err = errors.New(Conf.Language(26)) return @@ -97,15 +97,13 @@ func OpenRepoSnapshotDoc(fileID string) (id, rootID, content string, isLargeDoc if strings.HasSuffix(file.Path, ".sy") { luteEngine := NewLute() var snapshotTree *parse.Tree - isLargeDoc, snapshotTree, err = parseTreeInSnapshot(data, luteEngine) + isProtyleDoc, snapshotTree, err = parseTreeInSnapshot(data, luteEngine) if nil != err { logging.LogErrorf("parse tree from snapshot file [%s] failed", fileID) return } - id = snapshotTree.Root.ID - rootID = snapshotTree.Root.ID - if !isLargeDoc { + if !isProtyleDoc { renderTree := &parse.Tree{Root: &ast.Node{Type: ast.NodeDocument}} var unlinks []*ast.Node @@ -135,7 +133,7 @@ func OpenRepoSnapshotDoc(fileID string) (id, rootID, content string, isLargeDoc } luteEngine.RenderOptions.ProtyleContenteditable = false - if isLargeDoc { + if isProtyleDoc { util.PushMsg(Conf.Language(36), 5000) formatRenderer := render.NewFormatRenderer(snapshotTree, luteEngine.RenderOptions) content = gulu.Str.FromBytes(formatRenderer.Render()) @@ -143,11 +141,27 @@ func OpenRepoSnapshotDoc(fileID string) (id, rootID, content string, isLargeDoc content = luteEngine.Tree2BlockDOM(snapshotTree, luteEngine.RenderOptions) } } else { - isLargeDoc = true + isProtyleDoc = true if strings.HasSuffix(file.Path, ".json") { content = gulu.Str.FromBytes(data) } else { - content = file.Path + if strings.Contains(file.Path, "assets/") { // 剔除笔记本级或者文档级资源文件路径前缀 + file.Path = file.Path[strings.Index(file.Path, "assets/"):] + if util.IsDisplayableAsset(file.Path) { + dir, f := filepath.Split(file.Path) + tempRepoDiffDir := filepath.Join(util.TempDir, "repo", "diff", dir) + if mkErr := os.MkdirAll(tempRepoDiffDir, 0755); nil != mkErr { + logging.LogErrorf("mkdir [%s] failed: %v", tempRepoDiffDir, mkErr) + } else { + if wrErr := os.WriteFile(filepath.Join(tempRepoDiffDir, f), data, 0644); nil != wrErr { + logging.LogErrorf("write file [%s] failed: %v", filepath.Join(tempRepoDiffDir, file.Path), wrErr) + } + } + content = path.Join("repo", "diff", file.Path) + } + } else { + content = file.Path + } } } return @@ -304,8 +318,8 @@ func parseTitleInSnapshot(fileID string, repo *dejavu.Repo, luteEngine *lute.Lut return } -func parseTreeInSnapshot(data []byte, luteEngine *lute.Lute) (isLargeDoc bool, tree *parse.Tree, err error) { - isLargeDoc = 1024*1024*1 <= len(data) +func parseTreeInSnapshot(data []byte, luteEngine *lute.Lute) (isProtyleDoc bool, tree *parse.Tree, err error) { + isProtyleDoc = 1024*1024*1 <= len(data) tree, err = filesys.ParseJSONWithoutFix(data, luteEngine.ParseOptions) if nil != err { return diff --git a/kernel/server/serve.go b/kernel/server/serve.go index dc1e3d09a..312cd7488 100644 --- a/kernel/server/serve.go +++ b/kernel/server/serve.go @@ -75,6 +75,7 @@ func Serve(fastMode bool) { servePlugins(ginServer) serveEmojis(ginServer) serveTemplates(ginServer) + serveRepoDiff(ginServer) api.ServeAPI(ginServer) var host string @@ -349,6 +350,15 @@ func serveAssets(ginServer *gin.Engine) { }) } +func serveRepoDiff(ginServer *gin.Engine) { + ginServer.GET("/repo/diff/*path", model.CheckAuth, func(context *gin.Context) { + requestPath := context.Param("path") + p := filepath.Join(util.TempDir, "repo", "diff", requestPath) + http.ServeFile(context.Writer, context.Request, p) + return + }) +} + func serveDebug(ginServer *gin.Engine) { ginServer.GET("/debug/pprof/", gin.WrapF(pprof.Index)) ginServer.GET("/debug/pprof/allocs", gin.WrapF(pprof.Index)) diff --git a/kernel/util/path.go b/kernel/util/path.go index 106afd793..f6dd83e1e 100644 --- a/kernel/util/path.go +++ b/kernel/util/path.go @@ -193,3 +193,26 @@ func FilterSelfChildDocs(paths []string) (ret []string) { func IsAssetLinkDest(dest []byte) bool { return bytes.HasPrefix(dest, []byte("assets/")) } + +var ( + SiYuanAssetsImage = []string{".apng", ".ico", ".cur", ".jpg", ".jpe", ".jpeg", ".jfif", ".pjp", ".pjpeg", ".png", ".gif", ".webp", ".bmp", ".svg", ".avif"} + SiYuanAssetsAudio = []string{".mp3", ".wav", ".ogg", ".m4a"} + SiYuanAssetsVideo = []string{".mov", ".weba", ".mkv", ".mp4", ".webm"} +) + +func IsDisplayableAsset(p string) bool { + ext := strings.ToLower(filepath.Ext(p)) + if "" == ext { + return false + } + if gulu.Str.Contains(ext, SiYuanAssetsImage) { + return true + } + if gulu.Str.Contains(ext, SiYuanAssetsAudio) { + return true + } + if gulu.Str.Contains(ext, SiYuanAssetsVideo) { + return true + } + return false +}