Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Vanessa 2022-09-01 20:24:20 +08:00
commit 7034ab30c1
15 changed files with 261 additions and 100 deletions

File diff suppressed because one or more lines are too long

View file

@ -21,6 +21,7 @@ import (
"github.com/88250/gulu"
"github.com/gin-gonic/gin"
"github.com/siyuan-note/siyuan/kernel/bazaar"
"github.com/siyuan-note/siyuan/kernel/model"
"github.com/siyuan-note/siyuan/kernel/util"
)
@ -164,6 +165,15 @@ func getBazaarTemplate(c *gin.Context) {
}
}
func getInstalledTemplate(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
ret.Data = map[string]interface{}{
"packages": bazaar.InstalledTemplates(),
}
}
func installBazaarTemplate(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
@ -221,6 +231,15 @@ func getBazaarTheme(c *gin.Context) {
}
}
func getInstalledTheme(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
ret.Data = map[string]interface{}{
"packages": bazaar.InstalledThemes(),
}
}
func installBazaarTheme(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)

View file

@ -240,9 +240,11 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/bazaar/installBazaarIcon", model.CheckAuth, installBazaarIcon)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarIcon", model.CheckAuth, uninstallBazaarIcon)
ginServer.Handle("POST", "/api/bazaar/getBazaarTemplate", model.CheckAuth, getBazaarTemplate)
ginServer.Handle("POST", "/api/bazaar/getInstalledTemplate", model.CheckAuth, getInstalledTemplate)
ginServer.Handle("POST", "/api/bazaar/installBazaarTemplate", model.CheckAuth, installBazaarTemplate)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarTemplate", model.CheckAuth, uninstallBazaarTemplate)
ginServer.Handle("POST", "/api/bazaar/getBazaarTheme", model.CheckAuth, getBazaarTheme)
ginServer.Handle("POST", "/api/bazaar/getInstalledTheme", model.CheckAuth, getInstalledTheme)
ginServer.Handle("POST", "/api/bazaar/installBazaarTheme", model.CheckAuth, installBazaarTheme)
ginServer.Handle("POST", "/api/bazaar/uninstallBazaarTheme", model.CheckAuth, uninstallBazaarTheme)
ginServer.Handle("POST", "/api/bazaar/getBazaarPackageREAME", model.CheckAuth, getBazaarPackageREAME)

View file

@ -57,26 +57,13 @@ type Icon struct {
func Icons() (icons []*Icon) {
icons = []*Icon{}
result, err := util.GetRhyResult(false)
if nil != err {
return
}
bazaarIndex := getBazaarIndex()
bazaarHash := result["bazaar"].(string)
result = map[string]interface{}{}
request := httpclient.NewBrowserRequest()
u := util.BazaarOSSServer + "/bazaar@" + bazaarHash + "/stage/icons.json"
resp, err := request.SetResult(&result).Get(u)
pkgIndex, err := getPkgIndex("icons")
if nil != err {
logging.LogErrorf("get community stage index [%s] failed: %s", u, err)
return
}
if 200 != resp.StatusCode {
logging.LogErrorf("get community stage index [%s] failed: %d", u, resp.StatusCode)
return
}
repos := result["repos"].([]interface{})
bazaarIndex := getBazaarIndex()
repos := pkgIndex["repos"].([]interface{})
waitGroup := &sync.WaitGroup{}
lock := &sync.Mutex{}
p, _ := ants.NewPoolWithFunc(2, func(arg interface{}) {

View file

@ -37,6 +37,90 @@ import (
"golang.org/x/text/transform"
)
func TemplateJSON(templateDirName string) (ret map[string]interface{}, err error) {
p := filepath.Join(util.ThemesPath, templateDirName, "template.json")
if !gulu.File.IsExist(p) {
err = os.ErrNotExist
return
}
data, err := os.ReadFile(p)
if nil != err {
logging.LogErrorf("read template.json [%s] failed: %s", p, err)
return
}
if err = gulu.JSON.UnmarshalJSON(data, &ret); nil != err {
logging.LogErrorf("parse template.json [%s] failed: %s", p, err)
return
}
if 4 > len(ret) {
logging.LogWarnf("invalid template.json [%s]", p)
return nil, errors.New("invalid template.json")
}
return
}
func ThemeJSON(themeDirName string) (ret map[string]interface{}, err error) {
p := filepath.Join(util.ThemesPath, themeDirName, "theme.json")
if !gulu.File.IsExist(p) {
err = os.ErrNotExist
return
}
data, err := os.ReadFile(p)
if nil != err {
logging.LogErrorf("read theme.json [%s] failed: %s", p, err)
return
}
if err = gulu.JSON.UnmarshalJSON(data, &ret); nil != err {
logging.LogErrorf("parse theme.json [%s] failed: %s", p, err)
return
}
if 5 > len(ret) {
logging.LogWarnf("invalid theme.json [%s]", p)
return nil, errors.New("invalid theme.json")
}
return
}
func getPkgIndex(pkgType string) (ret map[string]interface{}, err error) {
ret, err = util.GetRhyResult(false)
if nil != err {
return
}
bazaarHash := ret["bazaar"].(string)
ret = map[string]interface{}{}
request := httpclient.NewBrowserRequest()
u := util.BazaarOSSServer + "/bazaar@" + bazaarHash + "/stage/" + pkgType + ".json"
resp, reqErr := request.SetResult(&ret).Get(u)
if nil != reqErr {
logging.LogErrorf("get community stage index [%s] failed: %s", u, reqErr)
return
}
if 200 != resp.StatusCode {
logging.LogErrorf("get community stage index [%s] failed: %d", u, resp.StatusCode)
return
}
return
}
func isOutdatedPkg(fullURL, version string, pkgIndex map[string]interface{}) bool {
if !strings.HasPrefix(fullURL, "https://github.com/") {
return false
}
url := strings.TrimPrefix(fullURL, "https://github.com/")
repos := pkgIndex["repos"].([]interface{})
for _, repo := range repos {
r := repo.(map[string]interface{})
repoURL := r["url"].(string)
repoVer := r["version"].(string)
if url == repoURL && version != repoVer {
return true
}
}
return false
}
func GetPackageREADME(repoURL, repoHash string, systemID string) (ret string) {
repoURLHash := repoURL + "@" + repoHash
data, err := downloadPackage(repoURLHash+"/README.md", false, systemID)

View file

@ -19,11 +19,13 @@ package bazaar
import (
"errors"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"time"
"github.com/88250/gulu"
"github.com/dustin/go-humanize"
"github.com/panjf2000/ants/v2"
"github.com/siyuan-note/httpclient"
@ -57,27 +59,13 @@ type Template struct {
func Templates() (templates []*Template) {
templates = []*Template{}
result, err := util.GetRhyResult(false)
pkgIndex, err := getPkgIndex("templates")
if nil != err {
return
}
bazaarIndex := getBazaarIndex()
bazaarHash := result["bazaar"].(string)
result = map[string]interface{}{}
request := httpclient.NewBrowserRequest()
u := util.BazaarOSSServer + "/bazaar@" + bazaarHash + "/stage/templates.json"
resp, reqErr := request.SetResult(&result).Get(u)
if nil != reqErr {
logging.LogErrorf("get community stage index [%s] failed: %s", u, reqErr)
return
}
if 200 != resp.StatusCode {
logging.LogErrorf("get community stage index [%s] failed: %d", u, resp.StatusCode)
return
}
repos := result["repos"].([]interface{})
repos := pkgIndex["repos"].([]interface{})
waitGroup := &sync.WaitGroup{}
lock := &sync.Mutex{}
p, _ := ants.NewPoolWithFunc(2, func(arg interface{}) {
@ -130,6 +118,53 @@ func Templates() (templates []*Template) {
return
}
func InstalledTemplates() (ret []*Template) {
dir, err := os.Open(filepath.Join(util.DataDir, "templates"))
if nil != err {
logging.LogWarnf("open templates folder [%s] failed: %s", util.ThemesPath, err)
return
}
templateDirs, err := dir.Readdir(-1)
if nil != err {
logging.LogWarnf("read templates folder failed: %s", err)
return
}
dir.Close()
for _, templateDir := range templateDirs {
if !templateDir.IsDir() {
continue
}
dirName := templateDir.Name()
templateConf, parseErr := TemplateJSON(dirName)
if nil != parseErr || nil == templateConf {
continue
}
template := &Template{}
template.Name = templateConf["name"].(string)
template.Author = templateConf["author"].(string)
template.URL = templateConf["url"].(string)
template.Version = templateConf["version"].(string)
template.RepoURL = template.URL
template.PreviewURL = "/templates/" + dirName + "/preview.png"
template.PreviewURLThumb = "/templates/" + dirName + "/preview.png"
template.Updated = templateDir.ModTime().Format("2006-01-02 15:04:05")
template.Size = templateDir.Size()
template.HSize = humanize.Bytes(uint64(template.Size))
template.HUpdated = formatUpdated(template.Updated)
readme, readErr := os.ReadFile(filepath.Join(util.DataDir, "templates", dirName, "README.md"))
if nil != readErr {
logging.LogWarnf("read install template README.md failed: %s", readErr)
continue
}
template.README = gulu.Str.FromBytes(readme)
ret = append(ret, template)
}
return
}
func InstallTemplate(repoURL, repoHash, installPath string, systemID string) error {
repoURLHash := repoURL + "@" + repoHash
data, err := downloadPackage(repoURLHash, true, systemID)

View file

@ -19,10 +19,12 @@ package bazaar
import (
"errors"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"github.com/88250/gulu"
"github.com/dustin/go-humanize"
ants "github.com/panjf2000/ants/v2"
"github.com/siyuan-note/httpclient"
@ -58,27 +60,13 @@ type Theme struct {
func Themes() (ret []*Theme) {
ret = []*Theme{}
result, err := util.GetRhyResult(false)
pkgIndex, err := getPkgIndex("themes")
if nil != err {
return
}
bazaarIndex := getBazaarIndex()
bazaarHash := result["bazaar"].(string)
result = map[string]interface{}{}
request := httpclient.NewBrowserRequest()
u := util.BazaarOSSServer + "/bazaar@" + bazaarHash + "/stage/themes.json"
resp, reqErr := request.SetResult(&result).Get(u)
if nil != reqErr {
logging.LogErrorf("get community stage index [%s] failed: %s", u, reqErr)
return
}
if 200 != resp.StatusCode {
logging.LogErrorf("get community stage index [%s] failed: %d", u, resp.StatusCode)
return
}
repos := result["repos"].([]interface{})
repos := pkgIndex["repos"].([]interface{})
waitGroup := &sync.WaitGroup{}
lock := &sync.Mutex{}
p, _ := ants.NewPoolWithFunc(8, func(arg interface{}) {
@ -95,7 +83,7 @@ func Themes() (ret []*Theme) {
return
}
if 200 != innerResp.StatusCode {
logging.LogErrorf("get bazaar package [%s] failed: %d", innerU, resp.StatusCode)
logging.LogErrorf("get bazaar package [%s] failed: %d", innerU, innerResp.StatusCode)
return
}
@ -129,6 +117,67 @@ func Themes() (ret []*Theme) {
return
}
func InstalledThemes() (ret []*Theme) {
dir, err := os.Open(util.ThemesPath)
if nil != err {
logging.LogWarnf("open appearance themes folder [%s] failed: %s", util.ThemesPath, err)
return
}
themeDirs, err := dir.Readdir(-1)
if nil != err {
logging.LogWarnf("read appearance themes folder failed: %s", err)
return
}
dir.Close()
pkgIndex, err := getPkgIndex("themes")
if nil != err {
return
}
for _, themeDir := range themeDirs {
if !themeDir.IsDir() {
continue
}
dirName := themeDir.Name()
if isBuiltInTheme(dirName) {
continue
}
themeConf, parseErr := ThemeJSON(dirName)
if nil != parseErr || nil == themeConf {
continue
}
theme := &Theme{}
theme.Name = themeConf["name"].(string)
theme.Author = themeConf["author"].(string)
theme.URL = themeConf["url"].(string)
theme.Version = themeConf["version"].(string)
theme.Modes = make([]string, 0, len(themeConf["modes"].([]interface{})))
theme.RepoURL = theme.URL
theme.PreviewURL = "/appearance/themes/" + dirName + "/preview.png"
theme.PreviewURLThumb = "/appearance/themes/" + dirName + "/preview.png"
theme.Updated = themeDir.ModTime().Format("2006-01-02 15:04:05")
theme.Size = themeDir.Size()
theme.HSize = humanize.Bytes(uint64(theme.Size))
theme.HUpdated = formatUpdated(theme.Updated)
readme, readErr := os.ReadFile(filepath.Join(util.ThemesPath, dirName, "README.md"))
if nil != readErr {
logging.LogWarnf("read install theme README.md failed: %s", readErr)
continue
}
theme.README = gulu.Str.FromBytes(readme)
theme.Outdated = isOutdatedPkg(theme.URL, theme.Version, pkgIndex)
ret = append(ret, theme)
}
return
}
func isBuiltInTheme(dirName string) bool {
return "daylight" == dirName || "midnight" == dirName
}
func InstallTheme(repoURL, repoHash, installPath string, systemID string) error {
repoURLHash := repoURL + "@" + repoHash
data, err := downloadPackage(repoURLHash, true, systemID)

View file

@ -57,27 +57,14 @@ type Widget struct {
func Widgets() (widgets []*Widget) {
widgets = []*Widget{}
result, err := util.GetRhyResult(false)
pkgIndex, err := getPkgIndex("widgets")
if nil != err {
return
}
bazaarIndex := getBazaarIndex()
bazaarHash := result["bazaar"].(string)
result = map[string]interface{}{}
request := httpclient.NewBrowserRequest()
u := util.BazaarOSSServer + "/bazaar@" + bazaarHash + "/stage/widgets.json"
resp, err := request.SetResult(&result).Get(u)
if nil != err {
logging.LogErrorf("get community stage index [%s] failed: %s", u, err)
return
}
if 200 != resp.StatusCode {
logging.LogErrorf("get community stage index [%s] failed: %d", u, resp.StatusCode)
return
}
repos := result["repos"].([]interface{})
repos := pkgIndex["repos"].([]interface{})
waitGroup := &sync.WaitGroup{}
lock := &sync.Mutex{}
p, _ := ants.NewPoolWithFunc(8, func(arg interface{}) {

View file

@ -7,7 +7,7 @@ require (
github.com/88250/css v0.1.2
github.com/88250/flock v0.8.2
github.com/88250/gulu v1.2.3-0.20220720144315-065ef35ec583
github.com/88250/lute v1.7.5-0.20220829155050-5c5d032f7b68
github.com/88250/lute v1.7.5-0.20220901071335-8565d1e64571
github.com/88250/melody v0.0.0-20201115062536-c0b3394adcd1
github.com/88250/pdfcpu v0.3.13
github.com/88250/vitess-sqlparser v0.0.0-20210205111146-56a2ded2aba1

View file

@ -19,8 +19,8 @@ github.com/88250/go-sqlite3 v1.14.13-0.20220714142610-fbbda1ee84f5 h1:8HdZozCsXS
github.com/88250/go-sqlite3 v1.14.13-0.20220714142610-fbbda1ee84f5/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/88250/gulu v1.2.3-0.20220720144315-065ef35ec583 h1:FhA/zJemLrbOYJpdMIMBezO5rGigQSdPR1kv+aztHfA=
github.com/88250/gulu v1.2.3-0.20220720144315-065ef35ec583/go.mod h1:I1qBzsksFL2ciGSuqDE7R3XW4BUMrfDgOvSXEk7FsAI=
github.com/88250/lute v1.7.5-0.20220829155050-5c5d032f7b68 h1:BSVqhd18YpBEECvek7lJu13qcmQGJgQwaiLrnsUyRvw=
github.com/88250/lute v1.7.5-0.20220829155050-5c5d032f7b68/go.mod h1:Bdu9LRNjQhtL3TftbtpjIWTwDVAXoS7AD8QsZQPk7zo=
github.com/88250/lute v1.7.5-0.20220901071335-8565d1e64571 h1:InniTKfj4OZjE0VFhLZmJT6PKGZQfqw6k06/Zvwh35c=
github.com/88250/lute v1.7.5-0.20220901071335-8565d1e64571/go.mod h1:Bdu9LRNjQhtL3TftbtpjIWTwDVAXoS7AD8QsZQPk7zo=
github.com/88250/melody v0.0.0-20201115062536-c0b3394adcd1 h1:9Cb+iN639vUI2OcIBc+4oGwml9/0J6bL6dWNb8Al+1s=
github.com/88250/melody v0.0.0-20201115062536-c0b3394adcd1/go.mod h1:jH6MMPr8G7AMzaVmWHXZQiB1DKO3giWbcWZ7UoJ1teI=
github.com/88250/pdfcpu v0.3.13 h1:touMWMZkCGalMIbEg9bxYp7rETM+zwb9hXjwhqi4I7Q=

View file

@ -28,6 +28,7 @@ import (
"github.com/88250/gulu"
"github.com/fsnotify/fsnotify"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/bazaar"
"github.com/siyuan-note/siyuan/kernel/util"
)
@ -115,8 +116,8 @@ func loadThemes() {
continue
}
name := themeDir.Name()
themeConf, err := themeJSON(name)
if nil != err || nil == themeConf {
themeConf, parseErr := bazaar.ThemeJSON(name)
if nil != parseErr || nil == themeConf {
continue
}
@ -145,28 +146,6 @@ func loadThemes() {
}
}
func themeJSON(themeName string) (ret map[string]interface{}, err error) {
p := filepath.Join(util.ThemesPath, themeName, "theme.json")
if !gulu.File.IsExist(p) {
err = os.ErrNotExist
return
}
data, err := os.ReadFile(p)
if nil != err {
logging.LogErrorf("read theme.json [%s] failed: %s", p, err)
return
}
if err = gulu.JSON.UnmarshalJSON(data, &ret); nil != err {
logging.LogErrorf("parse theme.json [%s] failed: %s", p, err)
return
}
if 5 > len(ret) {
logging.LogWarnf("invalid theme.json [%s]", p)
return nil, errors.New("invalid theme.json")
}
return
}
func iconJSON(iconName string) (ret map[string]interface{}, err error) {
p := filepath.Join(util.IconsPath, iconName, "icon.json")
if !gulu.File.IsExist(p) {

View file

@ -128,7 +128,7 @@ func BazaarThemes() (ret []*bazaar.Theme) {
for _, theme := range ret {
if installed == theme.Name {
theme.Installed = true
if themeConf, err := themeJSON(theme.Name); nil == err {
if themeConf, err := bazaar.ThemeJSON(theme.Name); nil == err {
theme.Outdated = theme.Version != themeConf["version"].(string)
}
theme.Current = theme.Name == Conf.Appearance.ThemeDark || theme.Name == Conf.Appearance.ThemeLight

View file

@ -210,18 +210,22 @@ func ExportDocx(id, savePath string, removeAssets bool) (err error) {
}
tmpDir := filepath.Join(util.TempDir, "export", gulu.Rand.String(7))
if err = os.MkdirAll(tmpDir, 0755); nil != err {
return
}
defer os.Remove(tmpDir)
name, dom := ExportMarkdownHTML(id, tmpDir, true)
name, content := ExportMarkdownHTML(id, tmpDir, true)
tmpDocxPath := filepath.Join(tmpDir, name+".docx")
args := []string{ // pandoc -f html --resource-path=请从这里开始 请从这里开始\index.html -o test.docx
"-f", "html",
"-f", "html+tex_math_dollars",
"--resource-path", tmpDir,
"-o", tmpDocxPath,
}
pandoc := exec.Command(Conf.Export.PandocBin, args...)
util.CmdAttr(pandoc)
pandoc.Stdin = bytes.NewBufferString(dom)
pandoc.Stdin = bytes.NewBufferString(content)
output, err := pandoc.CombinedOutput()
if nil != err {
logging.LogErrorf("export docx failed: %s", gulu.Str.FromBytes(output))
@ -323,7 +327,14 @@ func ExportMarkdownHTML(id, savePath string, docx bool) (name, dom string) {
}
return ast.WalkContinue
})
dom = luteEngine.ProtylePreview(tree, luteEngine.RenderOptions)
if docx {
renderer := render.NewProtyleExportDocxRenderer(tree, luteEngine.RenderOptions)
output := renderer.Render()
dom = gulu.Str.FromBytes(output)
} else {
dom = luteEngine.ProtylePreview(tree, luteEngine.RenderOptions)
}
return
}
@ -964,6 +975,7 @@ func renderExportMdMathBlockContent(r *render.FormatRenderer, node *ast.Node, en
func renderExportMdInlineMathContent(r *render.FormatRenderer, node *ast.Node, entering bool) ast.WalkStatus {
if entering {
tokens := html.UnescapeHTML(node.Tokens)
tokens = gulu.Str.ToBytes("a" + gulu.Str.FromBytes(tokens) + "b")
r.Write(tokens)
}
return ast.WalkContinue

View file

@ -606,6 +606,9 @@ func imgHtmlBlock2InlineImg(tree *parse.Tree) {
logging.LogErrorf("parse html block [%s] failed: %s", n.Tokens, pErr)
return ast.WalkContinue
}
if 1 > len(htmlNodes) {
return ast.WalkContinue
}
if atom.Img == htmlNodes[0].DataAtom {
imgHtmlBlocks[n] = htmlNodes[0]
}

View file

@ -97,6 +97,10 @@ func serveEmojis(ginServer *gin.Engine) {
ginServer.Static("/emojis/", filepath.Join(util.DataDir, "emojis"))
}
func serveTemplates(ginServer *gin.Engine) {
ginServer.Static("/templates/", filepath.Join(util.DataDir, "templates"))
}
func serveAppearance(ginServer *gin.Engine) {
siyuan := ginServer.Group("", model.CheckAuth)