Something went wrong. Try again.
A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
Something went wrong. Try again.
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583// SiYuan - Refactor your thinking// Copyright (c) 2020-present, b3log.org//// This program is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU Affero General Public License for more details.//// You should have received a copy of the GNU Affero General Public License// along with this program. If not, see <https://www.gnu.org/licenses/>.
package model
import ( "errors" "fmt" "path" "path/filepath" "strings" "sync" "time"
"github.com/88250/gulu" "github.com/emirpasic/gods/sets/hashset" "github.com/siyuan-note/logging" "github.com/siyuan-note/siyuan/kernel/bazaar" "github.com/siyuan-note/siyuan/kernel/task" "github.com/siyuan-note/siyuan/kernel/util" "golang.org/x/mod/semver")
func BatchUpdateBazaarPackages(frontend string) { plugins, widgets, icons, themes, templates := UpdatedPackages(frontend)
total := len(plugins) + len(widgets) + len(icons) + len(themes) + len(templates) if 1 > total { return }
util.PushEndlessProgress(fmt.Sprintf(Conf.language(235), 1, total)) defer util.PushClearProgress() count := 1 for _, plugin := range plugins { err := bazaar.InstallPlugin(plugin.RepoURL, plugin.RepoHash, filepath.Join(util.DataDir, "plugins", plugin.Name), Conf.System.ID) if err != nil { logging.LogErrorf("update plugin [%s] failed: %s", plugin.Name, err) util.PushErrMsg(fmt.Sprintf(Conf.language(238), plugin.Name), 5000) return }
count++ util.PushEndlessProgress(fmt.Sprintf(Conf.language(236), count, total, plugin.Name)) }
for _, widget := range widgets { err := bazaar.InstallWidget(widget.RepoURL, widget.RepoHash, filepath.Join(util.DataDir, "widgets", widget.Name), Conf.System.ID) if err != nil { logging.LogErrorf("update widget [%s] failed: %s", widget.Name, err) util.PushErrMsg(fmt.Sprintf(Conf.language(238), widget.Name), 5000) return }
count++ util.PushEndlessProgress(fmt.Sprintf(Conf.language(236), count, total, widget.Name)) }
for _, icon := range icons { err := bazaar.InstallIcon(icon.RepoURL, icon.RepoHash, filepath.Join(util.IconsPath, icon.Name), Conf.System.ID) if err != nil { logging.LogErrorf("update icon [%s] failed: %s", icon.Name, err) util.PushErrMsg(fmt.Sprintf(Conf.language(238), icon.Name), 5000) return }
count++ util.PushEndlessProgress(fmt.Sprintf(Conf.language(236), count, total, icon.Name)) }
for _, template := range templates { err := bazaar.InstallTemplate(template.RepoURL, template.RepoHash, filepath.Join(util.DataDir, "templates", template.Name), Conf.System.ID) if err != nil { logging.LogErrorf("update template [%s] failed: %s", template.Name, err) util.PushErrMsg(fmt.Sprintf(Conf.language(238), template.Name), 5000) return }
count++ util.PushEndlessProgress(fmt.Sprintf(Conf.language(236), count, total, template.Name)) }
for _, theme := range themes { err := bazaar.InstallTheme(theme.RepoURL, theme.RepoHash, filepath.Join(util.ThemesPath, theme.Name), Conf.System.ID) if err != nil { logging.LogErrorf("update theme [%s] failed: %s", theme.Name, err) util.PushErrMsg(fmt.Sprintf(Conf.language(238), theme.Name), 5000) return }
count++ util.PushEndlessProgress(fmt.Sprintf(Conf.language(236), count, total, theme.Name)) }
util.ReloadUI() task.AppendAsyncTaskWithDelay(task.PushMsg, 3*time.Second, util.PushMsg, fmt.Sprintf(Conf.language(237), total), 5000) return}
func UpdatedPackages(frontend string) (plugins []*bazaar.Plugin, widgets []*bazaar.Widget, icons []*bazaar.Icon, themes []*bazaar.Theme, templates []*bazaar.Template) { wg := &sync.WaitGroup{} wg.Add(5) go func() { defer wg.Done() tmp := InstalledPlugins(frontend, "") for _, plugin := range tmp { if plugin.Outdated { plugins = append(plugins, plugin) } plugin.PreferredReadme = "" // 清空这个字段,前端会请求在线的 README } }()
go func() { defer wg.Done() tmp := InstalledWidgets("") for _, widget := range tmp { if widget.Outdated { widgets = append(widgets, widget) } widget.PreferredReadme = "" } }()
go func() { defer wg.Done() tmp := InstalledIcons("") for _, icon := range tmp { if icon.Outdated { icons = append(icons, icon) } icon.PreferredReadme = "" } }()
go func() { defer wg.Done() tmp := InstalledThemes("") for _, theme := range tmp { if theme.Outdated { themes = append(themes, theme) } theme.PreferredReadme = "" } }()
go func() { defer wg.Done() tmp := InstalledTemplates("") for _, template := range tmp { if template.Outdated { templates = append(templates, template) } template.PreferredReadme = "" } }()
wg.Wait()
if 1 > len(plugins) { plugins = []*bazaar.Plugin{} }
if 1 > len(widgets) { widgets = []*bazaar.Widget{} }
if 1 > len(icons) { icons = []*bazaar.Icon{} }
if 1 > len(themes) { themes = []*bazaar.Theme{} }
if 1 > len(templates) { templates = []*bazaar.Template{} } return}
func GetPackageREADME(repoURL, repoHash, packageType string) (ret string) { ret = bazaar.GetPackageREADME(repoURL, repoHash, packageType) return}
func BazaarPlugins(frontend, keyword string) (plugins []*bazaar.Plugin) { plugins = bazaar.Plugins(frontend) plugins = filterPlugins(plugins, keyword) for _, plugin := range plugins { plugin.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "plugins", plugin.Name)) if plugin.Installed { if pluginConf, err := bazaar.PluginJSON(plugin.Name); err == nil && nil != plugin { plugin.Outdated = 0 > semver.Compare("v"+pluginConf.Version, "v"+plugin.Version) } } else { plugin.Outdated = false } } return}
func filterPlugins(plugins []*bazaar.Plugin, keyword string) (ret []*bazaar.Plugin) { keywords := getSearchKeywords(keyword) if 0 == len(keywords) { return plugins } ret = []*bazaar.Plugin{} for _, plugin := range plugins { if matchPackage(keywords, plugin.Package) { ret = append(ret, plugin) } } return}
func InstalledPlugins(frontend, keyword string) (plugins []*bazaar.Plugin) { plugins = bazaar.InstalledPlugins(frontend) plugins = filterPlugins(plugins, keyword) petals := getPetals() for _, plugin := range plugins { petal := getPetalByName(plugin.Name, petals) if nil != petal { plugin.Enabled = petal.Enabled } } return}
func InstallBazaarPlugin(repoURL, repoHash, pluginName string) error { installPath := filepath.Join(util.DataDir, "plugins", pluginName) err := bazaar.InstallPlugin(repoURL, repoHash, installPath, Conf.System.ID) if err != nil { return errors.New(fmt.Sprintf(Conf.Language(46), pluginName, err)) } return nil}
func UninstallBazaarPlugin(pluginName, frontend string) error { installPath := filepath.Join(util.DataDir, "plugins", pluginName) err := bazaar.UninstallPlugin(installPath) if err != nil { return errors.New(fmt.Sprintf(Conf.Language(47), err.Error())) }
petals := getPetals() var tmp []*Petal for i, petal := range petals { if petal.Name != pluginName { tmp = append(tmp, petals[i]) } } petals = tmp savePetals(petals)
uninstallPluginSet := hashset.New(pluginName) PushReloadPlugin(nil, nil, nil, uninstallPluginSet, "") return nil}
func BazaarWidgets(keyword string) (widgets []*bazaar.Widget) { widgets = bazaar.Widgets() widgets = filterWidgets(widgets, keyword) for _, widget := range widgets { widget.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "widgets", widget.Name)) if widget.Installed { if widgetConf, err := bazaar.WidgetJSON(widget.Name); err == nil && nil != widget { widget.Outdated = 0 > semver.Compare("v"+widgetConf.Version, "v"+widget.Version) } } else { widget.Outdated = false } } return}
func filterWidgets(widgets []*bazaar.Widget, keyword string) (ret []*bazaar.Widget) { keywords := getSearchKeywords(keyword) if 0 == len(keywords) { return widgets } ret = []*bazaar.Widget{} for _, w := range widgets { if matchPackage(keywords, w.Package) { ret = append(ret, w) } } return}
func InstalledWidgets(keyword string) (widgets []*bazaar.Widget) { widgets = bazaar.InstalledWidgets() widgets = filterWidgets(widgets, keyword) return}
func InstallBazaarWidget(repoURL, repoHash, widgetName string) error { installPath := filepath.Join(util.DataDir, "widgets", widgetName) err := bazaar.InstallWidget(repoURL, repoHash, installPath, Conf.System.ID) if err != nil { return errors.New(fmt.Sprintf(Conf.Language(46), widgetName, err)) } return nil}
func UninstallBazaarWidget(widgetName string) error { installPath := filepath.Join(util.DataDir, "widgets", widgetName) err := bazaar.UninstallWidget(installPath) if err != nil { return errors.New(fmt.Sprintf(Conf.Language(47), err.Error())) } return nil}
func BazaarIcons(keyword string) (icons []*bazaar.Icon) { icons = bazaar.Icons() icons = filterIcons(icons, keyword) for _, installed := range Conf.Appearance.Icons { for _, icon := range icons { if installed == icon.Name { icon.Installed = true if iconConf, err := bazaar.IconJSON(icon.Name); err == nil { icon.Outdated = 0 > semver.Compare("v"+iconConf.Version, "v"+icon.Version) } } icon.Current = icon.Name == Conf.Appearance.Icon } } return}
func filterIcons(icons []*bazaar.Icon, keyword string) (ret []*bazaar.Icon) { keywords := getSearchKeywords(keyword) if 0 == len(keywords) { return icons } ret = []*bazaar.Icon{} for _, i := range icons { if matchPackage(keywords, i.Package) { ret = append(ret, i) } } return}
func InstalledIcons(keyword string) (icons []*bazaar.Icon) { icons = bazaar.InstalledIcons() icons = filterIcons(icons, keyword) for _, icon := range icons { icon.Current = icon.Name == Conf.Appearance.Icon } return}
func InstallBazaarIcon(repoURL, repoHash, iconName string) error { installPath := filepath.Join(util.IconsPath, iconName) err := bazaar.InstallIcon(repoURL, repoHash, installPath, Conf.System.ID) if err != nil { return errors.New(fmt.Sprintf(Conf.Language(46), iconName, err)) } Conf.Appearance.Icon = iconName Conf.Save() InitAppearance() util.BroadcastByType("main", "setAppearance", 0, "", Conf.Appearance) return nil}
func UninstallBazaarIcon(iconName string) error { installPath := filepath.Join(util.IconsPath, iconName) err := bazaar.UninstallIcon(installPath) if err != nil { return errors.New(fmt.Sprintf(Conf.Language(47), err.Error())) }
InitAppearance() return nil}
func BazaarThemes(keyword string) (ret []*bazaar.Theme) { ret = bazaar.Themes() ret = filterThemes(ret, keyword) installs := Conf.Appearance.DarkThemes installs = append(installs, Conf.Appearance.LightThemes...) for _, installed := range installs { for _, theme := range ret { if installed.Name == theme.Name { theme.Installed = true if themeConf, err := bazaar.ThemeJSON(theme.Name); err == nil { theme.Outdated = 0 > semver.Compare("v"+themeConf.Version, "v"+theme.Version) } theme.Current = theme.Name == Conf.Appearance.ThemeDark || theme.Name == Conf.Appearance.ThemeLight } } } return}
func filterThemes(themes []*bazaar.Theme, keyword string) (ret []*bazaar.Theme) { keywords := getSearchKeywords(keyword) if 0 == len(keywords) { return themes } ret = []*bazaar.Theme{} for _, t := range themes { if matchPackage(keywords, t.Package) { ret = append(ret, t) } } return}
func InstalledThemes(keyword string) (ret []*bazaar.Theme) { ret = bazaar.InstalledThemes() ret = filterThemes(ret, keyword) for _, theme := range ret { theme.Current = theme.Name == Conf.Appearance.ThemeDark || theme.Name == Conf.Appearance.ThemeLight } return}
func InstallBazaarTheme(repoURL, repoHash, themeName string, mode int, update bool) error { closeThemeWatchers()
installPath := filepath.Join(util.ThemesPath, themeName) err := bazaar.InstallTheme(repoURL, repoHash, installPath, Conf.System.ID) if err != nil { return errors.New(fmt.Sprintf(Conf.Language(46), themeName, err)) }
if !update { // 更新主题后不需要对该主题进行切换 https://github.com/siyuan-note/siyuan/issues/4966 if 0 == mode { Conf.Appearance.ThemeLight = themeName } else { Conf.Appearance.ThemeDark = themeName } Conf.Appearance.Mode = mode Conf.Appearance.ThemeJS = gulu.File.IsExist(filepath.Join(installPath, "theme.js")) Conf.Save() }
InitAppearance() util.BroadcastByType("main", "setAppearance", 0, "", Conf.Appearance) return nil}
func UninstallBazaarTheme(themeName string) error { closeThemeWatchers()
installPath := filepath.Join(util.ThemesPath, themeName) err := bazaar.UninstallTheme(installPath) if err != nil { return errors.New(fmt.Sprintf(Conf.Language(47), err.Error())) }
InitAppearance() return nil}
func BazaarTemplates(keyword string) (templates []*bazaar.Template) { templates = bazaar.Templates() templates = filterTemplates(templates, keyword) for _, template := range templates { template.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "templates", template.Name)) if template.Installed { if templateConf, err := bazaar.TemplateJSON(template.Name); err == nil && nil != templateConf { template.Outdated = 0 > semver.Compare("v"+templateConf.Version, "v"+template.Version) } } else { template.Outdated = false } } return}
func filterTemplates(templates []*bazaar.Template, keyword string) (ret []*bazaar.Template) { keywords := getSearchKeywords(keyword) if 0 == len(keywords) { return templates } ret = []*bazaar.Template{} for _, t := range templates { if matchPackage(keywords, t.Package) { ret = append(ret, t) } } return}
func InstalledTemplates(keyword string) (templates []*bazaar.Template) { templates = bazaar.InstalledTemplates() templates = filterTemplates(templates, keyword) return}
func InstallBazaarTemplate(repoURL, repoHash, templateName string) error { installPath := filepath.Join(util.DataDir, "templates", templateName) err := bazaar.InstallTemplate(repoURL, repoHash, installPath, Conf.System.ID) if err != nil { return errors.New(fmt.Sprintf(Conf.Language(46), templateName, err)) } return nil}
func UninstallBazaarTemplate(templateName string) error { installPath := filepath.Join(util.DataDir, "templates", templateName) err := bazaar.UninstallTemplate(installPath) if err != nil { return errors.New(fmt.Sprintf(Conf.Language(47), err.Error())) } return nil}
func matchPackage(keywords []string, pkg *bazaar.Package) bool { if 1 > len(keywords) { return true }
if nil == pkg { return false }
for _, kw := range keywords { if !packageContainsKeyword(pkg, kw) { return false } }
// 全部关键词匹配 return true}
func packageContainsKeyword(pkg *bazaar.Package, kw string) bool { if strings.Contains(strings.ToLower(path.Base(pkg.RepoURL)), kw) || strings.Contains(strings.ToLower(pkg.Author), kw) { return true } for _, s := range pkg.DisplayName { if strings.Contains(strings.ToLower(s), kw) { return true } } for _, s := range pkg.Description { if strings.Contains(strings.ToLower(s), kw) { return true } } for _, s := range pkg.Keywords { if strings.Contains(strings.ToLower(s), kw) { return true } } return false}
func getSearchKeywords(query string) (ret []string) { query = strings.TrimSpace(query) if "" == query { return }
keywords := strings.Split(query, " ") for _, k := range keywords { if "" != k { ret = append(ret, strings.ToLower(k)) } } return}