diff --git a/Makefile b/Makefile index a1c447a..d91e6c5 100644 --- a/Makefile +++ b/Makefile @@ -28,3 +28,12 @@ service: sudo cp webp.service /etc/systemd/system/webp.service sudo systemctl enable webp sudo cp webp.logrotate /etc/logrotate.d/webp + +# 安装 zinc + + +# 安装 gorse +gorse: + export GORSE_DASHBOARD_USER="gorse" + export GORSE_DASHBOARD_PASS="gorse" + curl -fsSL https://gorse.io/playground | bash diff --git a/README.md b/README.md index 2298651..3dd8e2e 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,29 @@ # webp +- [ ] 原始图像 +- [ ] 缩略缓存 + +- [ ] 不同类型的用途(文章, 截图, 头像) +- [ ] 增量备份 + +cdn(img.gameui.net) -> main -> img +/articles/{id}/{hash} +/users/{id}/{hash} + +UPDATE web_images SET description = '' WHERE description IS NULL; +ALTER TABLE web_images MODIFY description VARCHAR(255) DEFAULT ''; + +- [ ] 解析 cdn.gameui.net 到 cdn 服务, 并将 cdn 回源指向 def.gameui.net 其解析到新服务器 +- [ ] 支持带参数下载指定尺寸图像 + + - [x] 提供webp生成服务 - [x] 提供流媒体服务 - [x] 点击播放之前不加载视频(减少流量消耗) - [x] 使用封面图片替代加载视屏第一帧 - [x] GraphQL 风格API - [ ] 列表翻页 + - [ ] OCR 查询支持 ```javascript diff --git a/api/graphql.go b/api/graphql.go index a06c5cc..9474411 100644 --- a/api/graphql.go +++ b/api/graphql.go @@ -3,6 +3,7 @@ package api import ( "fmt" "log" + "reflect" "strings" "git.satori.love/gameui/webp/models" @@ -12,6 +13,39 @@ import ( "github.com/mitchellh/mapstructure" ) +// 自动生成 GraphQL 类型的函数 +func generateGraphQLType(model interface{}) (*graphql.Object, error) { + modelType := reflect.TypeOf(model) + if modelType.Kind() != reflect.Struct { + return nil, fmt.Errorf("model must be a struct") + } + + fields := graphql.Fields{} + for i := 0; i < modelType.NumField(); i++ { + field := modelType.Field(i) + fieldType := graphql.String // 默认使用字符串类型 + + // 这里可以根据需要添加更多类型映射 + switch field.Type.Kind() { + case reflect.String: + fieldType = graphql.String + case reflect.Int: + fieldType = graphql.Int + case reflect.Bool: + fieldType = graphql.Boolean + } + + fields[field.Name] = &graphql.Field{ + Type: fieldType, + } + } + + return graphql.NewObject(graphql.ObjectConfig{ + Name: modelType.Name(), + Fields: fields, + }), nil +} + func NewSchema(config Config) (graphql.Schema, error) { // 打开数据库连接 @@ -27,8 +61,10 @@ func NewSchema(config Config) (graphql.Schema, error) { log.Fatalln("连接数据库失败", err) } + var user, article, text *graphql.Object + // 用户的可选字段 - user := graphql.NewObject(graphql.ObjectConfig{ + user = graphql.NewObject(graphql.ObjectConfig{ Name: "User", Description: "用户信息", Fields: graphql.Fields{ @@ -43,7 +79,7 @@ func NewSchema(config Config) (graphql.Schema, error) { }) // 文章的可选字段 - article := graphql.NewObject(graphql.ObjectConfig{ + article = graphql.NewObject(graphql.ObjectConfig{ Name: "Article", Description: "文章信息", Fields: graphql.Fields{ @@ -57,7 +93,7 @@ func NewSchema(config Config) (graphql.Schema, error) { }) // 图像中的文字提取 - text := graphql.NewObject(graphql.ObjectConfig{ + text = graphql.NewObject(graphql.ObjectConfig{ Name: "Text", Description: "图像中的文字提取", Fields: graphql.Fields{ @@ -80,18 +116,41 @@ func NewSchema(config Config) (graphql.Schema, error) { "description": &graphql.Field{Type: graphql.String, Description: "图像描述"}, "tags": &graphql.Field{Type: graphql.String, Description: "图像标签"}, "rank": &graphql.Field{Type: graphql.String, Description: "图像等级"}, - "text": &graphql.Field{Type: graphql.NewList(text), Description: "图像中的文字"}, "comment_num": &graphql.Field{Type: graphql.Int, Description: "评论数"}, "article_category_top_id": &graphql.Field{Type: graphql.Int, Description: "文章分类顶级ID"}, "praise_count": &graphql.Field{Type: graphql.Int, Description: "点赞数"}, "collect_count": &graphql.Field{Type: graphql.Int, Description: "收藏数"}, "create_time": &graphql.Field{Type: graphql.DateTime, Description: "图像创建时间"}, "update_time": &graphql.Field{Type: graphql.DateTime, Description: "图像更新时间"}, - "user": &graphql.Field{Type: user, Description: "图像所属用户"}, "article": &graphql.Field{Type: article, Description: "图像所属文章"}, + "text": &graphql.Field{ + Type: graphql.NewList(text), + Description: "图像中的文字", + Args: graphql.FieldConfigArgument{ + "text": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选含有指定文字的列"}, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + if p.Args["text"] != nil { + var texts TextList + for _, text := range p.Source.(Image).Text { + fmt.Println("san", text.Text) + if strings.Contains(text.Text, p.Args["text"].(string)) { + texts = append(texts, text) + } + } + return texts, nil + } + return p.Source.(Image).Text, nil + }, + }, }, }) + image.AddFieldConfig("user", &graphql.Field{Type: user, Description: "图像所属用户"}) + image.AddFieldConfig("similars", &graphql.Field{Type: graphql.NewList(image), Description: "相似的图像", Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return []Image{}, nil + }}) + // 将 list 中的字段提取出来用于查询 get_fields := func(requestedFields []ast.Selection) (fields []string) { for _, field := range requestedFields { @@ -108,6 +167,10 @@ func NewSchema(config Config) (graphql.Schema, error) { fields = append(fields, "article_id") continue } + if fieldAST.Name.Value == "similars" { + // 跳过自定义字段 + continue + } fields = append(fields, fieldAST.Name.Value) } } @@ -154,18 +217,15 @@ func NewSchema(config Config) (graphql.Schema, error) { if where_str != "" { where_str = "WHERE " + where_str } - var query strings.Builder var users []User var total int - fields := strings.Join(get_fields(p.Info.FieldASTs[0].SelectionSet.Selections), ",") query.WriteString(fmt.Sprintf("SELECT %s FROM web_member %s LIMIT %d OFFSET %d", fields, where_str, 10, 0)) if err := connection.Select(&users, query.String()); err != nil { fmt.Println("获取用户列表失败", err) return nil, err } - if len(users) > 0 { query.Reset() query.WriteString(fmt.Sprintf("SELECT COUNT(*) FROM web_member %s", where_str)) @@ -174,7 +234,6 @@ func NewSchema(config Config) (graphql.Schema, error) { return nil, err } } - return map[string]interface{}{ "list": users, "total": total, @@ -308,7 +367,7 @@ func NewSchema(config Config) (graphql.Schema, error) { "total": 0, }, nil } - where = append(where, fmt.Sprintf("id IN (%s) LIMIT %d", id_list_str, len(id_list))) + where = append(where, fmt.Sprintf("id IN (%s)", id_list_str)) } where_str := strings.Join(where, " AND ") @@ -342,17 +401,11 @@ func NewSchema(config Config) (graphql.Schema, error) { var images ImageList var q = query.String() - fmt.Println(q) if err := connection.Select(&images, q); err != nil { fmt.Println("获取图像列表失败", err) return nil, err } - // 按照 id_list 的顺序重新排序 - //if len(id_list) > 0 { - // images.SortByIDList(id_list) - //} - // 获取用户信息(如果图像列表不为空且请求字段中包含user) if len(images) > 0 && strings.Contains(fields, "user") { user_ids_str := images.ToAllUserID().ToString() diff --git a/api/struct.go b/api/struct.go index 7976eee..2061ce1 100644 --- a/api/struct.go +++ b/api/struct.go @@ -78,25 +78,24 @@ func (images *ImageList) SetArticle(articleList []Article) { } type Image struct { - ID int `json:"id" db:"id"` - Width int `json:"width" db:"width"` - Height int `json:"height" db:"height"` - Content string `json:"content" db:"content"` - Remark string `json:"remark" db:"remark"` - Description string `json:"description" db:"description"` - Tags string `json:"tags" db:"tags"` - Rank string `json:"rank" db:"rank"` - CommentNum int `json:"comment_num" db:"comment_num"` - ArticleCategoryTopId int `json:"article_category_top_id" db:"article_category_top_id"` - PraiseCount int `json:"praise_count" db:"praise_count"` - CollectCount int `json:"collect_count" db:"collect_count"` - ArticleID int `json:"article_id" db:"article_id"` - UserID int `json:"user_id" db:"user_id"` - User User `json:"user" db:"-"` - Article Article `json:"article" db:"-"` - CreateTime time.Time `json:"create_time" db:"create_time"` - UpdateTime time.Time `json:"update_time" db:"update_time"` - Text TextList `json:"text" db:"text"` + ID int `json:"id" db:"id"` + Width int `json:"width" db:"width"` + Height int `json:"height" db:"height"` + Content string `json:"content" db:"content"` + Remark string `json:"remark" db:"remark"` + Description string `json:"description" db:"description"` + Tags string `json:"tags" db:"tags"` + Rank string `json:"rank" db:"rank"` + CommentNum int `json:"comment_num" db:"comment_num"` + PraiseCount int `json:"praise_count" db:"praise_count"` + CollectCount int `json:"collect_count" db:"collect_count"` + ArticleID int `json:"article_id" db:"article_id"` + UserID int `json:"user_id" db:"user_id"` + CreateTime time.Time `json:"create_time" db:"create_time"` + UpdateTime time.Time `json:"update_time" db:"update_time"` + Text TextList `json:"text" db:"text"` + User User `json:"user" db:"-"` + Article Article `json:"article" db:"-"` } type TextList []struct {