diff --git a/kernel/api/bazaar.go b/kernel/api/bazaar.go index 7df942210..78674f4cf 100644 --- a/kernel/api/bazaar.go +++ b/kernel/api/bazaar.go @@ -107,6 +107,15 @@ func getBazaarIcon(c *gin.Context) { } } +func getInstalledIcon(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + ret.Data = map[string]interface{}{ + "packages": bazaar.InstalledIcons(), + } +} + func installBazaarIcon(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 58acba501..119edc7ed 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -237,6 +237,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/bazaar/installBazaarWidget", model.CheckAuth, installBazaarWidget) ginServer.Handle("POST", "/api/bazaar/uninstallBazaarWidget", model.CheckAuth, uninstallBazaarWidget) ginServer.Handle("POST", "/api/bazaar/getBazaarIcon", model.CheckAuth, getBazaarIcon) + ginServer.Handle("POST", "/api/bazaar/getInstalledIcon", model.CheckAuth, getInstalledIcon) 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) diff --git a/kernel/bazaar/icon.go b/kernel/bazaar/icon.go index 395f6be81..c778e96bd 100644 --- a/kernel/bazaar/icon.go +++ b/kernel/bazaar/icon.go @@ -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" @@ -31,28 +33,7 @@ import ( ) type Icon struct { - Author string `json:"author"` - URL string `json:"url"` - Version string `json:"version"` - - Name string `json:"name"` - RepoURL string `json:"repoURL"` - RepoHash string `json:"repoHash"` - PreviewURL string `json:"previewURL"` - PreviewURLThumb string `json:"previewURLThumb"` - - README string `json:"readme"` - - Installed bool `json:"installed"` - Outdated bool `json:"outdated"` - Current bool `json:"current"` - Updated string `json:"updated"` - Stars int `json:"stars"` - OpenIssues int `json:"openIssues"` - Size int64 `json:"size"` - HSize string `json:"hSize"` - HUpdated string `json:"hUpdated"` - Downloads int `json:"downloads"` + Package } func Icons() (icons []*Icon) { @@ -114,6 +95,63 @@ func Icons() (icons []*Icon) { return } +func InstalledIcons() (ret []*Icon) { + dir, err := os.Open(filepath.Join(util.DataDir, "icons")) + if nil != err { + logging.LogWarnf("open icons folder [%s] failed: %s", util.ThemesPath, err) + return + } + iconDirs, err := dir.Readdir(-1) + if nil != err { + logging.LogWarnf("read icons folder failed: %s", err) + return + } + dir.Close() + + bazaarIcons := Icons() + + for _, iconDir := range iconDirs { + if !iconDir.IsDir() { + continue + } + dirName := iconDir.Name() + if isBuiltInIcon(dirName) { + continue + } + + iconConf, parseErr := IconJSON(dirName) + if nil != parseErr || nil == iconConf { + continue + } + + icon := &Icon{} + icon.Name = iconConf["name"].(string) + icon.Author = iconConf["author"].(string) + icon.URL = iconConf["url"].(string) + icon.Version = iconConf["version"].(string) + icon.RepoURL = icon.URL + icon.PreviewURL = "/appearance/icons/" + dirName + "/preview.png" + icon.PreviewURLThumb = "/appearance/icons/" + dirName + "/preview.png" + icon.Updated = iconDir.ModTime().Format("2006-01-02 15:04:05") + icon.Size = iconDir.Size() + icon.HSize = humanize.Bytes(uint64(icon.Size)) + icon.HUpdated = formatUpdated(icon.Updated) + readme, readErr := os.ReadFile(filepath.Join(util.DataDir, "icons", dirName, "README.md")) + if nil != readErr { + logging.LogWarnf("read install icon README.md failed: %s", readErr) + continue + } + icon.README = gulu.Str.FromBytes(readme) + icon.Outdated = isOutdatedIcon(icon.URL, icon.Version, bazaarIcons) + ret = append(ret, icon) + } + return +} + +func isBuiltInIcon(dirName string) bool { + return "and" == dirName || "material" == dirName +} + func InstallIcon(repoURL, repoHash, installPath string, systemID string) error { repoURLHash := repoURL + "@" + repoHash data, err := downloadPackage(repoURLHash, true, systemID) diff --git a/kernel/bazaar/package.go b/kernel/bazaar/package.go index 965b04c72..a54ef9bc4 100644 --- a/kernel/bazaar/package.go +++ b/kernel/bazaar/package.go @@ -37,6 +37,53 @@ import ( "golang.org/x/text/transform" ) +type Package struct { + Author string `json:"author"` + URL string `json:"url"` + Version string `json:"version"` + + Name string `json:"name"` + RepoURL string `json:"repoURL"` + RepoHash string `json:"repoHash"` + PreviewURL string `json:"previewURL"` + PreviewURLThumb string `json:"previewURLThumb"` + + README string `json:"readme"` + + Installed bool `json:"installed"` + Outdated bool `json:"outdated"` + Current bool `json:"current"` + Updated string `json:"updated"` + Stars int `json:"stars"` + OpenIssues int `json:"openIssues"` + Size int64 `json:"size"` + HSize string `json:"hSize"` + HUpdated string `json:"hUpdated"` + Downloads int `json:"downloads"` +} + +func IconJSON(iconDirName string) (ret map[string]interface{}, err error) { + p := filepath.Join(util.ThemesPath, iconDirName, "icon.json") + if !gulu.File.IsExist(p) { + err = os.ErrNotExist + return + } + data, err := os.ReadFile(p) + if nil != err { + logging.LogErrorf("read icon.json [%s] failed: %s", p, err) + return + } + if err = gulu.JSON.UnmarshalJSON(data, &ret); nil != err { + logging.LogErrorf("parse icon.json [%s] failed: %s", p, err) + return + } + if 4 > len(ret) { + logging.LogWarnf("invalid icon.json [%s]", p) + return nil, errors.New("invalid icon.json") + } + return +} + func TemplateJSON(templateDirName string) (ret map[string]interface{}, err error) { p := filepath.Join(util.ThemesPath, templateDirName, "template.json") if !gulu.File.IsExist(p) { @@ -103,18 +150,42 @@ func getPkgIndex(pkgType string) (ret map[string]interface{}, err error) { return } -func isOutdatedPkg(fullURL, version string, pkgIndex map[string]interface{}) bool { +func isOutdatedTheme(fullURL, version string, bazaarThemes []*Theme) 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 { + for _, pkg := range bazaarThemes { + if url == pkg.URL && version != pkg.Version { + return true + } + } + return false +} + +func isOutdatedIcon(fullURL, version string, bazaarIcons []*Icon) bool { + if !strings.HasPrefix(fullURL, "https://github.com/") { + return false + } + + url := strings.TrimPrefix(fullURL, "https://github.com/") + for _, pkg := range bazaarIcons { + if url == pkg.URL && version != pkg.Version { + return true + } + } + return false +} + +func isOutdatedTemplate(fullURL, version string, bazaarTemplates []*Template) bool { + if !strings.HasPrefix(fullURL, "https://github.com/") { + return false + } + + url := strings.TrimPrefix(fullURL, "https://github.com/") + for _, pkg := range bazaarTemplates { + if url == pkg.URL && version != pkg.Version { return true } } diff --git a/kernel/bazaar/template.go b/kernel/bazaar/template.go index bd151e624..44147a6b4 100644 --- a/kernel/bazaar/template.go +++ b/kernel/bazaar/template.go @@ -34,27 +34,7 @@ import ( ) type Template struct { - Author string `json:"author"` - URL string `json:"url"` - Version string `json:"version"` - - Name string `json:"name"` - RepoURL string `json:"repoURL"` - RepoHash string `json:"repoHash"` - PreviewURL string `json:"previewURL"` - PreviewURLThumb string `json:"previewURLThumb"` - - README string `json:"readme"` - - Installed bool `json:"installed"` - Outdated bool `json:"outdated"` - Updated string `json:"updated"` - Stars int `json:"stars"` - OpenIssues int `json:"openIssues"` - Size int64 `json:"size"` - HSize string `json:"hSize"` - HUpdated string `json:"hUpdated"` - Downloads int `json:"downloads"` + Package } func Templates() (templates []*Template) { @@ -131,11 +111,14 @@ func InstalledTemplates() (ret []*Template) { } dir.Close() + bazaarTemplates := Templates() + for _, templateDir := range templateDirs { if !templateDir.IsDir() { continue } dirName := templateDir.Name() + templateConf, parseErr := TemplateJSON(dirName) if nil != parseErr || nil == templateConf { continue @@ -159,7 +142,7 @@ func InstalledTemplates() (ret []*Template) { continue } template.README = gulu.Str.FromBytes(readme) - + template.Outdated = isOutdatedTemplate(template.URL, template.Version, bazaarTemplates) ret = append(ret, template) } return diff --git a/kernel/bazaar/theme.go b/kernel/bazaar/theme.go index c0cb1a49c..9b0d888b8 100644 --- a/kernel/bazaar/theme.go +++ b/kernel/bazaar/theme.go @@ -33,29 +33,9 @@ import ( ) type Theme struct { - Author string `json:"author"` - URL string `json:"url"` - Version string `json:"version"` - Modes []string `json:"modes"` + Package - Name string `json:"name"` - RepoURL string `json:"repoURL"` - RepoHash string `json:"repoHash"` - PreviewURL string `json:"previewURL"` - PreviewURLThumb string `json:"previewURLThumb"` - - README string `json:"readme"` - - Installed bool `json:"installed"` - Outdated bool `json:"outdated"` - Current bool `json:"current"` - Updated string `json:"updated"` - Stars int `json:"stars"` - OpenIssues int `json:"openIssues"` - Size int64 `json:"size"` - HSize string `json:"hSize"` - HUpdated string `json:"hUpdated"` - Downloads int `json:"downloads"` + Modes []string `json:"modes"` } func Themes() (ret []*Theme) { @@ -130,10 +110,7 @@ func InstalledThemes() (ret []*Theme) { } dir.Close() - pkgIndex, err := getPkgIndex("themes") - if nil != err { - return - } + bazaarThemes := Themes() for _, themeDir := range themeDirs { if !themeDir.IsDir() { @@ -168,7 +145,7 @@ func InstalledThemes() (ret []*Theme) { continue } theme.README = gulu.Str.FromBytes(readme) - theme.Outdated = isOutdatedPkg(theme.URL, theme.Version, pkgIndex) + theme.Outdated = isOutdatedTheme(theme.URL, theme.Version, bazaarThemes) ret = append(ret, theme) } return diff --git a/kernel/bazaar/widget.go b/kernel/bazaar/widget.go index 42f48ac3d..a0b93b1d9 100644 --- a/kernel/bazaar/widget.go +++ b/kernel/bazaar/widget.go @@ -31,28 +31,7 @@ import ( ) type Widget struct { - Author string `json:"author"` - URL string `json:"url"` - Version string `json:"version"` - - Name string `json:"name"` - RepoURL string `json:"repoURL"` - RepoHash string `json:"repoHash"` - PreviewURL string `json:"previewURL"` - PreviewURLThumb string `json:"previewURLThumb"` - - README string `json:"readme"` - - Installed bool `json:"installed"` - Outdated bool `json:"outdated"` - Current bool `json:"current"` - Updated string `json:"updated"` - Stars int `json:"stars"` - OpenIssues int `json:"openIssues"` - Size int64 `json:"size"` - HSize string `json:"hSize"` - HUpdated string `json:"hUpdated"` - Downloads int `json:"downloads"` + Package } func Widgets() (widgets []*Widget) {