Memos 是一个Golang开发的免费开源备忘录. 在Github上47.5K的Star.
我也建了一个自己的memos https://m.scwy.net. 或许用它代替手机上的记事本.
开放了注册, 网友或其它朋友也可以用.
添加自己的Token(左下角用户设置-我的帐号-访问令牌), 下载APP, 可以在手机上使用它.

- 添加了WebHook, 还是比较简单. 但给自己的备忘录加个WebHook的意义在哪里? 不是应该给所有用户加WebHook才有用吗?
- 发现有时会无法保存, 如果保存了一些非法UTF8字符, 还会导致内容不能显示.
- Memos与博客的区别在哪里? 为什么有了博客还要个这? Memos也能作为博客使用,它是动态的.而Hugo是静态的.若象我两者都有,可以把Memos作为零碎信息的记录, 而博客作为整理过的文字.
-
二次开发除了golang环境,就是npm了. 进入web目录, npm install, 然后 npm run dev.
如果npm install 不成功, 使用npm 20.19.0版本是可以的(官方文档已旧).
如果本机npm版本不对, 可以安装nvm进行npm版本管理:
nvm install 20.19.0 –> nvm use 20.19.0 -
要编译为独立运行的程序, 需要npm run build, 将生成的dist放入 server/router/frontend 目录中, 再进行go build
-
添加系统WebHook, 让所有的操作都发送给hook. 这对我这种小站或许有一点点作用.
(1). 添加命令行功能
cmd/memos/main.go中添加一个Webhook参数的配置
instanceProfile := &profile.Profile{
Mode: viper.GetString("mode"),
Addr: viper.GetString("addr"),
Port: viper.GetInt("port"),
UNIXSock: viper.GetString("unix-sock"),
Data: viper.GetString("data"),
Driver: viper.GetString("driver"),
DSN: viper.GetString("dsn"),
InstanceURL: viper.GetString("instance-url"),
Webhook: viper.GetString("webhook"),
Version: version.GetCurrentVersion(viper.GetString("mode")),
}
....
rootCmd.PersistentFlags().String("mode", "dev", `mode of server, can be "prod" or "dev" or "demo"`)
rootCmd.PersistentFlags().String("addr", "", "address of server")
rootCmd.PersistentFlags().Int("port", 8081, "port of server")
rootCmd.PersistentFlags().String("unix-sock", "", "path to the unix socket, overrides --addr and --port")
rootCmd.PersistentFlags().String("data", "", "data directory")
rootCmd.PersistentFlags().String("driver", "sqlite", "database driver")
rootCmd.PersistentFlags().String("dsn", "", "database source name(aka. DSN)")
rootCmd.PersistentFlags().String("instance-url", "", "the url of your memos instance")
rootCmd.PersistentFlags().String("webhook", "", "the global webhook URL for all user activities")
....
if err := viper.BindPFlag("webhook", rootCmd.PersistentFlags().Lookup("webhook")); err != nil {
panic(err)
}
对应的配置文件 internal/profile/profile.go中
type Profile struct {
// Mode can be "prod" or "dev" or "demo"
Mode string
// Addr is the binding address for server
Addr string
// Port is the binding port for server
Port int
// UNIXSock is the IPC binding path. Overrides Addr and Port
UNIXSock string
// Data is the data directory
Data string
// DSN points to where memos stores its own data
DSN string
// Driver is the database driver
// sqlite, mysql
Driver string
// Version is the current version of server
Version string
// InstanceURL is the url of your memos instance.
InstanceURL string
// Webhook is the global webhook URL for all user activities.
Webhook string
}
(2). 响应WebHook 在通常用户的WebHook响应处, 添加全局的WebHook. 文件 server/router/api/v1/memo_service.go, dispatchMemoRelatedWebhook函数中
for _, hook := range webhooks {
payload, err := convertMemoToWebhookPayload(memo)
if err != nil {
return errors.Wrap(err, "failed to convert memo to webhook payload")
}
payload.ActivityType = activityType
payload.URL = hook.Url
// Use asynchronous webhook dispatch
webhook.PostAsync(payload)
}
// 添加这一部份
if s.Profile.Webhook != "" {
payload, err := convertMemoToWebhookPayload(memo)
if err != nil {
return errors.Wrap(err, "failed to convert memo to webhook payload for global webhook")
}
payload.ActivityType = activityType
payload.URL = s.Profile.Webhook
// Use asynchronous webhook dispatch
webhook.PostAsync(payload)
}
return nil
- 继续添加全局WebHook事件.(虽然我在官网文档看到过,但是不是升级就取消了?)
(1). 注册事件
server/router/api/v1/user_service.go文件CreateUser函数最后return之前添加
if s.Profile.Webhook != "" {
payload, err := convertUserToWebhookPayload(user, user.ID)
if err != nil {
slog.Warn("Failed to convert user to webhook payload for global webhook", slog.Any("err", err))
} else {
payload.URL = s.Profile.Webhook
payload.ActivityType = "USER_CREATED"
// 使用异步方式发送WebHook
webhook.PostAsync(payload)
}
}
...
// 添加辅助函数来转换用户数据为WebHook payload
func convertUserToWebhookPayload(user *store.User, creatorID int32) (*webhook.WebhookRequestPayload, error) {
return &webhook.WebhookRequestPayload{
Creator: fmt.Sprintf("%s%d", UserNamePrefix, creatorID),
// 注意:WebhookRequestPayload结构体目前只支持Memo字段
// 如果需要传递用户数据,可能需要扩展结构体或使用其他方式
// 这里可以考虑将用户数据转换为JSON字符串放在Memo字段中,或修改WebhookRequestPayload结构
}, nil
}
(2). 添加登陆WebHook
在 server/router/api/v1/auth_service.go 函数SignIn中添加, 也是在return之前
// 发送到全局WebHook
if s.Profile.Webhook != "" {
payload, err := convertUserToWebhookPayload(existingUser, existingUser.ID)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to create webhook payload: %v", err)
}
payload.URL = s.Profile.Webhook
payload.ActivityType = "USER_SIGNED_IN"
// 使用异步方式发送WebHook
webhook.PostAsync(payload)
}
- 通过 gox -os=“linux” -arch=“arm” 编译为Termux可用版本。
这样手机上就可以运行备忘录了。如果通过内网,通过Caddy,通过公网服务器。那任何人都可以通过域名进行访问。
也等于可以用旧手机作为服务器运行一个人人可访问的备忘录。
打赏