diff --git a/README_zh_CN.md b/README_zh_CN.md index 7d712fb37..c20fcdc74 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -42,6 +42,7 @@ * [安装包](#安装包) * [Docker 部署](#docker-部署) * [Unraid 部署](#unraid-部署) + * [宝塔面板 部署](#宝塔面板部署) * [内部预览版](#内部预览版) * [🏘️ 社区](#️-社区) * [🛠️ 开发指南](#️-开发指南) @@ -300,6 +301,38 @@ Publish parameters: --accessAuthCode=******(访问授权码) +### 宝塔面板部署 + +
+宝塔面板 部署文档 + +#### 前提 + +* 仅适用于宝塔面板9.2.0及以上版本 +* 安装宝塔面板,前往[宝塔面板](https://www.bt.cn/new/download.html)官网,选择正式版的脚本下载安装 + +#### 部署 + +1. 登录宝塔面板,在左侧菜单栏中点击 `Docker` +2. 首次会提示安装 `Docker` 和 `Docker Compose` 服务,点击立即安装,若已安装请忽略 +3. 安装完成后在 `Docker-应用商店-实用工具` 中找到 `思源笔记`,点击`安装`,也可以在搜索框直接搜索 +4. 设置域名等基本信息,点击 `确定` + * 名称:应用名称,默认 `siyuan_随机字符` + * 版本选择:默认 `latest` + * 域名:如你需要通过域名访问,请在此处填写你的域名 + * 允许外部访问:如你需通过 `IP+Port` 直接访问,请勾选,如你已经设置了域名,请不要勾选此处 + * 端口:默认 `6806`,可自行修改 + * 访问授权码:默认随机生成 + * 内存限制:0为不限制,根据实际需要设置 +5. 提交后面板会自动进行应用初始化,大概需要`1-3`分钟,初始化完成后即可访问 + +#### 访问思源笔记 + +* 如果你填写了域名,请在浏览器输入域名访问 +* 如你选择了 `IP+端口`,请在浏览器地输入 `http://<宝塔面板IP>:6806` 访问 + +
+ ### 内部预览版 我们会在有重大更新前发布内部预览版,请访问 [https://github.com/siyuan-note/insider](https://github.com/siyuan-note/insider)。 diff --git a/app/src/block/popover.ts b/app/src/block/popover.ts index 37c9abb89..ba917e5e3 100644 --- a/app/src/block/popover.ts +++ b/app/src/block/popover.ts @@ -37,6 +37,7 @@ export const initBlockPopover = (app: App) => { if (aElement.firstElementChild?.getAttribute("data-type") === "url") { if (aElement.firstElementChild.textContent.indexOf("...") > -1) { tip = Lute.EscapeHTMLStr(aElement.firstElementChild.getAttribute("data-href")); + tooltipClass = "href"; } } if (!tip && aElement.dataset.wrap !== "true" && event.target.dataset.type !== "block-more" && !hasClosestByClassName(event.target, "block__icon")) { @@ -49,6 +50,7 @@ export const initBlockPopover = (app: App) => { } } else if (aElement.classList.contains("av__celltext--url")) { tip = tip ? `${tip.substring(0, Constants.SIZE_TITLE)}
${aElement.getAttribute("data-name")}` : aElement.getAttribute("data-name"); + tooltipClass = "href"; } else if (aElement.classList.contains("av__calc--ashow") && aElement.clientWidth + 2 < aElement.scrollWidth) { tip = aElement.lastChild.textContent + " " + aElement.firstElementChild.textContent; } @@ -76,7 +78,7 @@ export const initBlockPopover = (app: App) => { } else { assetTip += ` ${response.data.hSize}${title ? '
' + title : ""}
${window.siyuan.languages.modifiedAt} ${response.data.hUpdated}
${window.siyuan.languages.createdAt} ${response.data.hCreated}`; } - showTooltip(assetTip, aElement); + showTooltip(assetTip, aElement, tooltipClass); }); tip = ""; } else if (title) { diff --git a/kernel/filesys/tree.go b/kernel/filesys/tree.go index 24aa96953..ccc3d7371 100644 --- a/kernel/filesys/tree.go +++ b/kernel/filesys/tree.go @@ -150,29 +150,22 @@ func LoadTreeByData(data []byte, boxID, p string, luteEngine *lute.Lute) (ret *p parentAbsPath += ".sy" parentPath := parentAbsPath parentAbsPath = filepath.Join(util.DataDir, boxID, parentAbsPath) - parentData, readErr := filelock.ReadFile(parentAbsPath) - if nil != readErr { - if os.IsNotExist(readErr) { - // 子文档缺失父文档时自动补全 https://github.com/siyuan-note/siyuan/issues/7376 - parentTree := treenode.NewTree(boxID, parentPath, hPathBuilder.String()+"Untitled", "Untitled") - if _, writeErr := WriteTree(parentTree); nil != writeErr { - logging.LogErrorf("rebuild parent tree [%s] failed: %s", parentAbsPath, writeErr) - } else { - logging.LogInfof("rebuilt parent tree [%s]", parentAbsPath) - treenode.UpsertBlockTree(parentTree) - } + + parentDocIAL := DocIAL(parentAbsPath) + if 1 > len(parentDocIAL) { + // 子文档缺失父文档时自动补全 https://github.com/siyuan-note/siyuan/issues/7376 + parentTree := treenode.NewTree(boxID, parentPath, hPathBuilder.String()+"Untitled", "Untitled") + if _, writeErr := WriteTree(parentTree); nil != writeErr { + logging.LogErrorf("rebuild parent tree [%s] failed: %s", parentAbsPath, writeErr) } else { - logging.LogWarnf("read parent tree data [%s] failed: %s", parentAbsPath, readErr) + logging.LogInfof("rebuilt parent tree [%s]", parentAbsPath) + treenode.UpsertBlockTree(parentTree) } hPathBuilder.WriteString("Untitled/") continue } - ial := ReadDocIAL(parentData) - if 1 > len(ial) { - logging.LogWarnf("tree [%s] is corrupted", filepath.Join(boxID, p)) - } - title := ial["title"] + title := parentDocIAL["title"] if "" == title { title = "Untitled" } @@ -185,6 +178,29 @@ func LoadTreeByData(data []byte, boxID, p string, luteEngine *lute.Lute) (ret *p return } +func DocIAL(absPath string) (ret map[string]string) { + filelock.Lock(absPath) + file, err := os.Open(absPath) + if err != nil { + logging.LogErrorf("open file [%s] failed: %s", absPath, err) + filelock.Unlock(absPath) + return nil + } + + iter := jsoniter.Parse(jsoniter.ConfigCompatibleWithStandardLibrary, file, 512) + for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { + if field == "Properties" { + iter.ReadVal(&ret) + break + } else { + iter.Skip() + } + } + file.Close() + filelock.Unlock(absPath) + return +} + func WriteTree(tree *parse.Tree) (size uint64, err error) { data, filePath, err := prepareWriteTree(tree) if err != nil { diff --git a/kernel/model/file.go b/kernel/model/file.go index d0be5ba06..b65909b71 100644 --- a/kernel/model/file.go +++ b/kernel/model/file.go @@ -37,7 +37,6 @@ import ( "github.com/88250/lute/html" "github.com/88250/lute/parse" util2 "github.com/88250/lute/util" - jsoniter "github.com/json-iterator/go" "github.com/siyuan-note/filelock" "github.com/siyuan-note/logging" "github.com/siyuan-note/riff" @@ -116,29 +115,9 @@ func (box *Box) docIAL(p string) (ret map[string]string) { } filePath := filepath.Join(util.DataDir, box.ID, p) - - filelock.Lock(filePath) - file, err := os.Open(filePath) - if err != nil { - logging.LogErrorf("open file [%s] failed: %s", p, err) - filelock.Unlock(filePath) - return nil - } - - iter := jsoniter.Parse(jsoniter.ConfigCompatibleWithStandardLibrary, file, 512) - for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { - if field == "Properties" { - iter.ReadVal(&ret) - break - } else { - iter.Skip() - } - } - file.Close() - filelock.Unlock(filePath) - + ret = filesys.DocIAL(filePath) if 1 > len(ret) { - logging.LogWarnf("properties not found in file [%s]", p) + logging.LogWarnf("properties not found in file [%s]", filePath) box.moveCorruptedData(filePath) return nil } diff --git a/kernel/model/outline.go b/kernel/model/outline.go index 5e45b1f34..4e819d511 100644 --- a/kernel/model/outline.go +++ b/kernel/model/outline.go @@ -17,10 +17,8 @@ package model import ( - "github.com/88250/lute/html" - "time" - "github.com/88250/lute/ast" + "github.com/88250/lute/html" "github.com/88250/lute/parse" "github.com/emirpasic/gods/stacks/linkedliststack" "github.com/siyuan-note/siyuan/kernel/treenode" @@ -209,7 +207,6 @@ func (tx *Transaction) doMoveOutlineHeading(operation *Operation) (ret *TxErr) { } func Outline(rootID string, preview bool) (ret []*Path, err error) { - time.Sleep(util.FrontendQueueInterval) FlushTxQueue() ret = []*Path{} diff --git a/kernel/util/ocr.go b/kernel/util/ocr.go index f7d2db15d..8dadbf402 100644 --- a/kernel/util/ocr.go +++ b/kernel/util/ocr.go @@ -228,10 +228,11 @@ func Tesseract(imgAbsPath string) (ret []map[string]interface{}) { } tsv := string(output) - logging.LogInfof("tesseract [path=%s, size=%d] success", imgAbsPath, info.Size()) + //logging.LogInfof("tesseract [path=%s] success [%s]", imgAbsPath, tsv) // 按行分割 TSV 数据 - lines := strings.Split(tsv, "\r\n") + tsv = strings.ReplaceAll(tsv, "\r", "") + lines := strings.Split(tsv, "\n") // 解析 TSV 数据 跳过标题行,从第二行开始处理 for _, line := range lines[1:] { @@ -262,7 +263,7 @@ func GetOcrJsonText(jsonData []map[string]interface{}) (ret string) { if text, ok := dataMap["text"]; ok { // 确保 text 是字符串类型 if textStr, ok := text.(string); ok { - ret += " " + textStr + ret += " " + strings.ReplaceAll(textStr, "\r", "") } } } diff --git a/kernel/util/runtime.go b/kernel/util/runtime.go index 30adbea1e..4182d7042 100644 --- a/kernel/util/runtime.go +++ b/kernel/util/runtime.go @@ -132,9 +132,6 @@ func SetNetworkProxy(proxyURL string) { } const ( - // FrontendQueueInterval 为前端请求队列轮询间隔。 - FrontendQueueInterval = 512 * time.Millisecond - // SQLFlushInterval 为数据库事务队列写入间隔。 SQLFlushInterval = 3000 * time.Millisecond )