├── .gitignore ├── LICENSE ├── README.md └── deprecated ├── cache ├── index_map.go └── indexmap_test.go ├── config ├── conf.go └── config.toml ├── go.mod ├── go.sum ├── handlers ├── comment │ ├── post_comment_handler.go │ └── query_commentlist_handler.go ├── user_info │ ├── post_follow_action_handler.go │ ├── query_follow_list_handler.go │ ├── query_follower_handler.go │ └── userinfo_handler.go ├── user_login │ ├── user_login_handler.go │ └── user_register_handler.go └── video │ ├── feed_videolist_handler.go │ ├── post_favor_handler.go │ ├── publish_video_handler.go │ ├── query_favor_videolist_handler.go │ └── query_videolist_handler.go ├── lib ├── ffmpeg.exe └── ffprobe.exe ├── main.go ├── middleware ├── jwt.go ├── jwt_test.go ├── normal.go ├── password.go └── password_test.go ├── models ├── comment.go ├── common.go ├── init_db.go ├── user_info.go ├── user_info_test.go ├── user_login.go ├── video.go └── video_test.go ├── router └── router_douyin.go ├── service ├── comment │ ├── post_comment.go │ └── query_comment_list.go ├── user_info │ ├── post_follow_action.go │ ├── query_follow_list.go │ └── query_follower_list.go ├── user_login │ ├── post_user_login.go │ └── query_user_login.go └── video │ ├── feed_videolist.go │ ├── post_favor_state.go │ ├── post_video.go │ ├── query_favor_videolist.go │ └── query_videolist.go └── util ├── comment.go ├── ffmpeg.go └── video.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | !deprecated/static/1-1.jpg 3 | !deprecated/static/1-1.mp4 4 | deprecated/static/* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 L_B__ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [写给后续参加字节跳动青训营的同学](https://github.com/ACking-you/byte_douyin_project/issues/10) 2 | # 抖音极简版 3 | 4 | 5 | [![Contributors][contributors-shield]][contributors-url] 6 | [![Forks][forks-shield]][forks-url] 7 | [![Stargazers][stars-shield]][stars-url] 8 | [![Issues][issues-shield]][issues-url] 9 | [![MIT License][license-shield]][license-url] 10 | 11 | 12 | [your-project-path]:ACking-you/byte_douyin_project 13 | [contributors-shield]: https://img.shields.io/github/contributors/ACking-you/byte_douyin_project.svg?style=flat-square 14 | [contributors-url]: https://github.com/ACking-you/byte_douyin_project/graphs/contributors 15 | [forks-shield]: https://img.shields.io/github/forks/ACking-you/byte_douyin_project.svg?style=flat-square 16 | [forks-url]: https://github.com/ACking-you/byte_douyin_project/network/members 17 | [stars-shield]: https://img.shields.io/github/stars/ACking-you/byte_douyin_project.svg?style=flat-square 18 | [stars-url]: https://github.com/ACking-you/byte_douyin_project/stargazers 19 | [issues-shield]: https://img.shields.io/github/issues/ACking-you/byte_douyin_project.svg?style=flat-square 20 | [issues-url]: https://img.shields.io/github/issues/ACking-you/byte_douyin_project.svg 21 | [license-shield]: https://img.shields.io/github/license/ACking-you/byte_douyin_project?style=flat-square 22 | [license-url]: https://github.com/ACking-you/byte_douyin_project/blob/master/LICENSE 23 | 24 | 25 | 26 | * [数据库说明](#数据库说明) 27 | * [数据库关系说明](#数据库关系说明) 28 | * [数据库建立说明](#数据库建立说明) 29 | * [架构说明](#架构说明) 30 | * [各模块代码详细说明](#各模块代码详细说明) 31 | * [Handlers](#handlers) 32 | * [Service](#service) 33 | * [Models](#models) 34 | * [遇到的问题及对应解决方案](#遇到的问题及对应解决方案) 35 | * [返回json数据的完整性和前端要求的一致性](#返回json数据的完整性和前端要求的一致性) 36 | * [is\_favorite和is\_follow字段的更新](#is_favorite和is_follow字段的更新) 37 | * [视频的保存和封面的切片](#视频的保存和封面的切片) 38 | * [视频的保存](#视频的保存) 39 | * [封面的截取](#封面的截取) 40 | * [可改进的地方](#可改进的地方) 41 | * [项目运行](#项目运行) 42 | 43 | ## 数据库说明 44 | 45 | 46 | ![database.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/892fbbe46695467ebe4fb4a12ebd412e~tplv-k3u1fbpfcp-watermark.image?) 47 | 48 | > 单纯看上面的图会感觉很混乱,现在我们来将关系拆解。 49 | 50 | ### 数据库关系说明 51 | 52 | **关系图如下:** 53 | 54 | 55 | ![database_relation.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f08918db1ea84126bc21d23fe9401a75~tplv-k3u1fbpfcp-watermark.image?) 56 | 57 | > 所有的表都有自己的id主键为唯一的标识。 58 | 59 | user_logins:存下用户的用户名和密码 60 | 61 | user_infos:存下用户的基本信息 62 | 63 | videos:存下视频的基本信息 64 | 65 | comment:存下每个评论的基本信息 66 | 67 | **具体的关系索引:** 68 | 69 | 所有的一对一和一对多关系,只需要在一个表中加入对方的id索引。 70 | 71 | * 比如user_infos和user_logins的一对一关系,在user_logins中加入user_id字段设为外键存储user_infos中对应的行的id信息。 72 | * 比如user_infos和和videos的一对多关系,在videos中加入user_id字段设为外键存储user_infos中对应的行的id信息。 73 | 74 | 所有的多对多关系,需要多建立一张表,用该表作为媒介存储两个对象的id作为关系的产生,而它们各自表中不需要再存下额外的字段。 75 | 76 | * 比如user_infos和videos的多对多关系,创建一张user_favor_videos中间表,然后将该表的字段均设为外键,分别存下user_infos和videos对应行的id。如id为1的用户对id为2的视频点了个赞,那么就把这个1和2存入中间表user_favor_videos即可。 77 | 78 | ### 数据库建立说明 79 | 80 | 数据库各表的建立无需自己实现额外的建表操作,一切都由gorm框架自动建表,具体逻辑在models层的代码中。 81 | 82 | > gorm官方文档链接:[链接](https://gorm.io/zh_CN/docs/index.html) 83 | 84 | 建表和初始化操作由init_db.go来执行: 85 | 86 | ```go 87 | func InitDB() { 88 | var err error 89 | DB, err = gorm.Open(mysql.Open(config.DBConnectString()), &gorm.Config{ 90 | PrepareStmt: true, //缓存预编译命令 91 | SkipDefaultTransaction: true, //禁用默认事务操作 92 | //Logger: logger.Default.LogMode(logger.Info), //打印sql语句 93 | }) 94 | if err != nil { 95 | panic(err) 96 | } 97 | err = DB.AutoMigrate(&UserInfo{}, &Video{}, &Comment{}, &UserLogin{}) 98 | if err != nil { 99 | panic(err) 100 | } 101 | } 102 | ``` 103 | 104 | ## 架构说明 105 | 106 | 107 | ![architecture.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ae11d82b8de74787a258ef36f4cf2557~tplv-k3u1fbpfcp-watermark.image?) 108 | 109 | > 以用户登录为例共需要经过以下过程: 110 | 111 | 1. 进入中间件SHAMiddleWare内的函数逻辑,得到password明文加密后再设置password。具体需要调用gin.Context的Set方法设置password。随后调用next()方法继续下层路由。 112 | 2. 进入UserLoginHandler函数逻辑,获取username,并调用gin.Context的Get方法得到中间件设置的password。再调用service层的QueryUserLogin函数。 113 | 3. 进入QueryUserLogin函数逻辑,执行三个过程:checkNum,prepareData,packData。也就是检查参数、准备数据、打包数据,准备数据的过程中会调用models层的UserLoginDAO。 114 | 4. 进入UserLoginDAO的逻辑,执行最终的数据库请求过程,返回给上层。 115 | 116 | ### 各模块代码详细说明 117 | 118 | 我开发的过程中是以单个函数为单个文件进行开发,所以代码会比较长,故我根据数据库内的模型对函数文件进行了如下分包: 119 | 120 | 121 | ![handlers.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6dc222793d6f4038b1bf2435053bfee4~tplv-k3u1fbpfcp-watermark.image?) 122 | 123 | service层的分包也是一样的。 124 | 125 | #### Handlers 126 | 127 | 对于handlers层级的所有函数实现有如下规范: 128 | 129 | 所有的逻辑由代理对象进行,完成以下两个逻辑 130 | 131 | 1. 解析得到参数。 132 | 2. 开始调用下层逻辑。 133 | 134 | 例如一个关注动作触发的逻辑: 135 | 136 | ```go 137 | NewProxyPostFollowAction().Do() 138 | //其中Do主要包含以下两个逻辑,对应两个方法 139 | p.parseNum() //解析参数 140 | p.startAction() //开始调用下层逻辑 141 | ``` 142 | 143 | #### Service 144 | 145 | 对于service层级的函数实现由如下规范: 146 | 147 | 同样由一个代理对象进行,完成以下三个或两个逻辑 148 | 149 | 当上层需要返回数据信息,则进行三个逻辑: 150 | 151 | 1. 检查参数。 152 | 2. 准备数据。 153 | 3. 打包数据。 154 | 155 | 当上层不需要返回数据信息,则进行两个逻辑: 156 | 157 | 1. 检查参数。 158 | 2. 执行上层指定的动作。 159 | 160 | 例如关注动作在service层的逻辑属于第二类: 161 | 162 | ```go 163 | NewPostFollowActionFlow(...).Do() 164 | //Do中包含以下两个逻辑 165 | p.checkNum() //检查参数 166 | p.publish() //执行动作 167 | ``` 168 | 169 | #### Models 170 | 171 | 对于models层的各个操作,没有像service和handler层针对前端发来的请求就行对应的处理,models层是面向于数据库的增删改查,不需要考虑和上层的交互。 172 | 173 | 而service层根据上层的需要来调用models层的不同代码请求数据库内的内容。 174 | 175 | ## 遇到的问题及对应解决方案 176 | 177 | ### 返回json数据的完整性和前端要求的一致性 178 | 179 | 由于数据库内的一对一、一对多、多对多关系是根据id进行映射,所以models层请求得到的字段并不包含前端所需要的直接数据,比如前端要求Comment结构中需要包含UserInfo,而我的Comment结构如下: 180 | 181 | ```go 182 | type Comment struct { 183 | Id int64 `json:"id"` 184 | UserInfoId int64 `json:"-"` //用于一对多关系的id 185 | VideoId int64 `json:"-"` //一对多,视频对评论 186 | User UserInfo `json:"user" gorm:"-"` 187 | Content string `json:"content"` 188 | CreatedAt time.Time `json:"-"` 189 | CreateDate string `json:"create_date" gorm:"-"` 190 | } 191 | ``` 192 | 193 | 很明显,为了与数据库中设计的表一一对应,在原数据的基础上加了几个字段,且在gorm屏蔽了User字段,所以service调用models层得到是Comment数据中User字段还未被填充,还需再填充这部分内容,好在由对应的UserId,故可以正确填充该字段。 194 | 195 | 为了重用以及不破坏代码的一致性,将填充逻辑写入util包内,比如以上的字段填充函数,同时前端要求的日期格式也能够按要求设置: 196 | 197 | ```go 198 | func FillCommentListFields(comments *[]*models.Comment) error { 199 | size := len(*comments) 200 | if comments == nil || size == 0 { 201 | return errors.New("util.FillCommentListFields comments为空") 202 | } 203 | dao := models.NewUserInfoDAO() 204 | for _, v := range *comments { 205 | _ = dao.QueryUserInfoById(v.UserInfoId, &v.User) //填充这条评论的作者信息 206 | v.CreateDate = v.CreatedAt.Format("1-2") //转为前端要求的日期格式 207 | } 208 | return nil 209 | } 210 | ``` 211 | 212 | 这里举了Comment这一个例子,其他的Video也是同理。 213 | 214 | ### is_favorite和is_follow字段的更新 215 | 216 | 每次为视频点赞都会在数据库的user_favor_videos表中加入用户的id和视频的id,很明显is_favorite字段是针对每个用户来判断的,而我所设计的数据库中的videos表也是包含这个字段的,但这个字段很明显不能直接进行复用,而是需要每次判断用户和此视频的关系来重新更新。 217 | 218 | 这个更新过程放入util包的填充函数中即可,为了点赞过程的迅速响应,我采取了nosql的方式存储了这个点赞的映射,也就是userId和videoId的映射,也就是用nosql代替了这个中间表的功效。 219 | 220 | 具体代码逻辑在cache包内。 221 | 222 | ### 视频的保存和封面的切片 223 | 224 | #### 视频的保存 225 | 226 | 在本地建立static文件夹存储视频和封面图片。 227 | 228 | 具体逻辑如下: 229 | 230 | 1. 检查视频格式 231 | 2. 根据userId和该作者发布的视频数量产生唯一的名称,如id为1的用户发布了0个视频,那么本次上传的名称为1-0.mp4 232 | 3. 截取第一帧画面作为封面 233 | 4. 保存视频基本信息到数据库(包括视频链接和封面链接 234 | 235 | #### 封面的截取 236 | 237 | 使用ffmpeg调用命令行对视频进行截取。 238 | 239 | 设计ffmpeg请求类Video2Image,通过对它内部的参数设置来构造对应的命令行字符串。具体请看util包内的ffmpeg.go的实现。 240 | 241 | 由于我设计的命令请求字符串是直接的一行字符串,而go语言exec包里面的Command函数执行所需的仅仅是一个个参数。 242 | 243 | 所以此处我想到用cgo直接调用 system(args)来解决。 244 | 245 | 代码如下: 246 | 247 | ```go 248 | //#include 249 | //int startCmd(const char* cmd){ 250 | // return system(cmd); 251 | //} 252 | import "C" 253 | 254 | func (v *Video2Image) ExecCommand(cmd string) error { 255 | if v.debug { 256 | log.Println(cmd) 257 | } 258 | cCmd := C.CString(cmd) 259 | defer C.free(unsafe.Pointer(cCmd)) 260 | status := C.startCmd(cCmd) 261 | if status != 0 { 262 | return errors.New("视频切截图失败") 263 | } 264 | return nil 265 | } 266 | ``` 267 | 268 | ## 可改进的地方 269 | 270 | 1. 写到后面发现很多mysql的数据可以用redis优化。 271 | 2. 很多执行逻辑可以通过并行优化。 272 | 3. 路由分组可以更为详实。 273 | 4. ... 274 | 275 | ## 项目运行 276 | 277 | > 本项目运行不需要手动建表,项目启动后会自动建表。 278 | 279 | **运行所需环境**: 280 | 281 | * mysql 5.7及以上 282 | * redis 5.0.14及以上 283 | * ffmepg(已放入lib自带,用于对视频切片得到封面 284 | * 需要gcc环境(主要用于cgo,windows请将mingw-w64设置到环境变量 285 | 286 | **运行需要更改配置**: 287 | 288 | > 进入config目录更改对应的mysql、redis、server、path信息。 289 | 290 | * mysql:mysql相关的配置信息 291 | * redis:redis相关配置信息 292 | * server:当前服务器(当前启动的机器)的配置信息,用于生成对应的视频和图片链接 293 | * path:其中ffmpeg_path为lib里的文件路径,static_source_path为本项目的static目录,这里请根据本地的绝对路径进行更改 294 | 295 | > 完成config配置文件的更改后,需要再更改conf.go里的解析文件路径为config.toml文件的绝对路径,内容如下: 296 | > 297 | > ```go 298 | > if _, err := toml.DecodeFile("你的绝对路径\\config.toml", &Info); err != nil { 299 | > panic(err) 300 | > } 301 | > ``` 302 | > 303 | > 304 | 305 | **运行所需命令**: 306 | 307 | ```shell 308 | cd .\byte_douyin_project\ 309 | go run main.go 310 | ``` 311 | -------------------------------------------------------------------------------- /deprecated/cache/index_map.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/ACking-you/byte_douyin_project/config" 7 | "github.com/go-redis/redis/v8" 8 | ) 9 | 10 | // 用户id->被点赞的视频id集合->是否含有该视频id 11 | 12 | var ctx = context.Background() 13 | var rdb *redis.Client 14 | 15 | const ( 16 | favor = "favor" 17 | relation = "relation" 18 | ) 19 | 20 | func init() { 21 | rdb = redis.NewClient( 22 | &redis.Options{ 23 | Addr: fmt.Sprintf("%s:%d", config.Global.RDB.IP, config.Global.RDB.Port), 24 | Password: "", //没有设置密码 25 | DB: config.Global.RDB.Database, 26 | }) 27 | } 28 | 29 | var ( 30 | proxyIndexOperation ProxyIndexMap 31 | ) 32 | 33 | type ProxyIndexMap struct { 34 | } 35 | 36 | func NewProxyIndexMap() *ProxyIndexMap { 37 | return &proxyIndexOperation 38 | } 39 | 40 | // UpdateVideoFavorState 更新点赞状态,state:true为点赞,false为取消点赞 41 | func (i *ProxyIndexMap) UpdateVideoFavorState(userId int64, videoId int64, state bool) { 42 | key := fmt.Sprintf("%s:%d", favor, userId) 43 | if state { 44 | rdb.SAdd(ctx, key, videoId) 45 | return 46 | } 47 | rdb.SRem(ctx, key, videoId) 48 | } 49 | 50 | // GetVideoFavorState 得到点赞状态 51 | func (i *ProxyIndexMap) GetVideoFavorState(userId int64, videoId int64) bool { 52 | key := fmt.Sprintf("%s:%d", favor, userId) 53 | ret := rdb.SIsMember(ctx, key, videoId) 54 | return ret.Val() 55 | } 56 | 57 | // UpdateUserRelation 更新点赞状态,state:true为点关注,false为取消关注 58 | func (i *ProxyIndexMap) UpdateUserRelation(userId int64, followId int64, state bool) { 59 | key := fmt.Sprintf("%s:%d", relation, userId) 60 | if state { 61 | rdb.SAdd(ctx, key, followId) 62 | return 63 | } 64 | rdb.SRem(ctx, key, followId) 65 | } 66 | 67 | // GetUserRelation 得到关注状态 68 | func (i *ProxyIndexMap) GetUserRelation(userId int64, followId int64) bool { 69 | key := fmt.Sprintf("%s:%d", relation, userId) 70 | ret := rdb.SIsMember(ctx, key, followId) 71 | return ret.Val() 72 | } 73 | -------------------------------------------------------------------------------- /deprecated/cache/indexmap_test.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestProxyIndexMap_UpdateUserRelation(t *testing.T) { 9 | NewProxyIndexMap().UpdateUserRelation(1, 2, true) 10 | fmt.Println(NewProxyIndexMap().GetUserRelation(1, 3)) 11 | } 12 | 13 | func TestProxyIndexMap_GetVideoFavorState(t *testing.T) { 14 | fmt.Println(NewProxyIndexMap().GetVideoFavorState(1, 2)) 15 | NewProxyIndexMap().UpdateVideoFavorState(1, 2, true) 16 | fmt.Println(NewProxyIndexMap().GetVideoFavorState(1, 2)) 17 | } 18 | -------------------------------------------------------------------------------- /deprecated/config/conf.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | "github.com/BurntSushi/toml" 6 | "log" 7 | "os" 8 | "os/exec" 9 | "path/filepath" 10 | "strings" 11 | ) 12 | 13 | type Mysql struct { 14 | Host string 15 | Port int 16 | Database string 17 | Username string 18 | Password string 19 | Charset string 20 | ParseTime bool `toml:"parse_time"` 21 | Loc string 22 | } 23 | 24 | type Redis struct { 25 | IP string 26 | Port int 27 | Database int 28 | } 29 | 30 | type Server struct { 31 | IP string 32 | Port int 33 | } 34 | 35 | type Path struct { 36 | FfmpegPath string `toml:"ffmpeg_path"` 37 | StaticSourcePath string `toml:"static_source_path"` 38 | } 39 | 40 | type Config struct { 41 | DB Mysql `toml:"mysql"` 42 | RDB Redis `toml:"redis"` 43 | Server `toml:"server"` 44 | Path `toml:"path"` 45 | } 46 | 47 | var Global Config 48 | 49 | func ensurePathValid() { 50 | var err error 51 | if _, err = os.Stat(Global.StaticSourcePath); os.IsNotExist(err) { 52 | if err = os.Mkdir(Global.StaticSourcePath, 0755); err != nil { 53 | log.Fatalf("mkdir error:path %s", Global.StaticSourcePath) 54 | } 55 | } 56 | if _, err = os.Stat(Global.FfmpegPath); os.IsNotExist(err) { 57 | if _, err = exec.Command("ffmpeg", "-version").Output(); err != nil { 58 | log.Fatalf("ffmpeg not valid %s", Global.FfmpegPath) 59 | } else { 60 | Global.FfmpegPath = "ffmpeg" 61 | } 62 | } else { 63 | Global.FfmpegPath, err = filepath.Abs(Global.FfmpegPath) 64 | if err != nil { 65 | log.Fatalln("get abs path failed:", Global.FfmpegPath) 66 | } 67 | } 68 | //把资源路径转化为绝对路径,防止调用ffmpeg命令失效 69 | Global.StaticSourcePath, err = filepath.Abs(Global.StaticSourcePath) 70 | if err != nil { 71 | log.Fatalln("get abs path failed:", Global.StaticSourcePath) 72 | } 73 | } 74 | 75 | //包初始化加载时候会调用的函数 76 | func init() { 77 | if _, err := toml.DecodeFile("./config/config.toml", &Global); err != nil { 78 | panic(err) 79 | } 80 | //去除左右的空格 81 | strings.Trim(Global.Server.IP, " ") 82 | strings.Trim(Global.RDB.IP, " ") 83 | strings.Trim(Global.DB.Host, " ") 84 | //保证路径正常 85 | ensurePathValid() 86 | } 87 | 88 | // DBConnectString 填充得到数据库连接字符串 89 | func DBConnectString() string { 90 | arg := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=%v&loc=%s", 91 | Global.DB.Username, Global.DB.Password, Global.DB.Host, Global.DB.Port, Global.DB.Database, 92 | Global.DB.Charset, Global.DB.ParseTime, Global.DB.Loc) 93 | log.Println(arg) 94 | return arg 95 | } 96 | -------------------------------------------------------------------------------- /deprecated/config/config.toml: -------------------------------------------------------------------------------- 1 | #关系型数据库配置 2 | [mysql] 3 | host = "127.0.0.1" 4 | port = 3306 5 | database = "douyin" 6 | username = "root" 7 | password = "123" 8 | charset = "utf8mb4" 9 | parse_time = true 10 | loc = "Local" 11 | 12 | #nosql配置,用于存储每个用户是否对某个视频点赞,以及关注了某个人(主要用于反馈前端情况,比如点了赞后会变成红心 13 | [redis] 14 | host = "127.0.0.1" 15 | port = 49153 16 | database = 0 17 | 18 | #记录当前服务器的ip和启动端口号,当前服务器的ip用于生成对应的视频链接地址 19 | [server] 20 | ip = "127.0.0.1" 21 | port = 8080 22 | 23 | #用于保存资源的路径,以及用于截图工具的路径(截图工具放在lib目录 24 | [path] 25 | ffmpeg_path = "./lib/ffmpeg.exe" 26 | static_source_path = "./static" -------------------------------------------------------------------------------- /deprecated/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ACking-you/byte_douyin_project 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/BurntSushi/toml v1.1.0 7 | github.com/dgrijalva/jwt-go v3.2.0+incompatible 8 | github.com/gin-gonic/gin v1.7.7 9 | github.com/go-redis/redis/v8 v8.11.5 // indirect 10 | github.com/golang/protobuf v1.5.2 // indirect 11 | gorm.io/driver/mysql v1.3.3 12 | gorm.io/gorm v1.23.5 13 | ) 14 | -------------------------------------------------------------------------------- /deprecated/go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= 2 | github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 3 | github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= 4 | github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 5 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 6 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 7 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 8 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 10 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 11 | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 12 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 13 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= 14 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= 15 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 16 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 17 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 18 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 19 | github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= 20 | github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= 21 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= 22 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 23 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 24 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 25 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 26 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 27 | github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= 28 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 29 | github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= 30 | github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= 31 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 32 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 33 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 34 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 35 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 36 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 37 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 38 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 39 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 40 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 41 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 42 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 43 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 44 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 45 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 46 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 47 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 48 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 49 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 50 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 51 | github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 52 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 53 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 54 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 55 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 56 | github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= 57 | github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 58 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 59 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 60 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 61 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 62 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 63 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 64 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 65 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 66 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= 67 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 68 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 69 | github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 70 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 71 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 72 | github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= 73 | github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= 74 | github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= 75 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 76 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 77 | github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= 78 | github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= 79 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 80 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 81 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 82 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 83 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 84 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 85 | github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= 86 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 87 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 88 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 89 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 90 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 91 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 92 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 93 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 94 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 95 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 96 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 97 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 98 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 99 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 100 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 101 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 102 | golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= 103 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 104 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 105 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 106 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 107 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 108 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 109 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 110 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 111 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 112 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 113 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= 114 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 115 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 116 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 117 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 118 | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 119 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 120 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= 121 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 122 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 123 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 124 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 125 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 126 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 127 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 128 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 129 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 130 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 131 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 132 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 133 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 134 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 135 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 136 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 137 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 138 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 139 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 140 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 141 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 142 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 143 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 144 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 145 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 146 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 147 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 148 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 149 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 150 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 151 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 152 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 153 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 154 | gorm.io/driver/mysql v1.3.3 h1:jXG9ANrwBc4+bMvBcSl8zCfPBaVoPyBEBshA8dA93X8= 155 | gorm.io/driver/mysql v1.3.3/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U= 156 | gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= 157 | gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM= 158 | gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= 159 | -------------------------------------------------------------------------------- /deprecated/handlers/comment/post_comment_handler.go: -------------------------------------------------------------------------------- 1 | package comment 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/ACking-you/byte_douyin_project/models" 7 | "github.com/ACking-you/byte_douyin_project/service/comment" 8 | "github.com/gin-gonic/gin" 9 | "net/http" 10 | "strconv" 11 | ) 12 | 13 | type PostCommentResponse struct { 14 | models.CommonResponse 15 | *comment.Response 16 | } 17 | 18 | func PostCommentHandler(c *gin.Context) { 19 | NewProxyPostCommentHandler(c).Do() 20 | } 21 | 22 | type ProxyPostCommentHandler struct { 23 | *gin.Context 24 | 25 | videoId int64 26 | userId int64 27 | commentId int64 28 | actionType int64 29 | commentText string 30 | } 31 | 32 | func NewProxyPostCommentHandler(context *gin.Context) *ProxyPostCommentHandler { 33 | return &ProxyPostCommentHandler{Context: context} 34 | } 35 | 36 | func (p *ProxyPostCommentHandler) Do() { 37 | //解析参数 38 | if err := p.parseNum(); err != nil { 39 | p.SendError(err.Error()) 40 | return 41 | } 42 | 43 | //正式调用Service层 44 | commentRes, err := comment.PostComment(p.userId, p.videoId, p.commentId, p.actionType, p.commentText) 45 | if err != nil { 46 | p.SendError(err.Error()) 47 | return 48 | } 49 | 50 | //成功返回 51 | p.SendOk(commentRes) 52 | } 53 | 54 | func (p *ProxyPostCommentHandler) parseNum() error { 55 | rawUserId, _ := p.Get("user_id") 56 | userId, ok := rawUserId.(int64) 57 | if !ok { 58 | return errors.New("userId解析出错") 59 | } 60 | p.userId = userId 61 | 62 | rawVideoId := p.Query("video_id") 63 | videoId, err := strconv.ParseInt(rawVideoId, 10, 64) 64 | if err != nil { 65 | return err 66 | } 67 | p.videoId = videoId 68 | 69 | //根据actionType解析对应的可选参数 70 | rawActionType := p.Query("action_type") 71 | actionType, err := strconv.ParseInt(rawActionType, 10, 64) 72 | switch actionType { 73 | case comment.CREATE: 74 | p.commentText = p.Query("comment_text") 75 | case comment.DELETE: 76 | p.commentId, err = strconv.ParseInt(p.Query("comment_id"), 10, 64) 77 | if err != nil { 78 | return err 79 | } 80 | default: 81 | return fmt.Errorf("未定义的行为%d", actionType) 82 | } 83 | p.actionType = actionType 84 | return nil 85 | } 86 | 87 | func (p *ProxyPostCommentHandler) SendError(msg string) { 88 | p.JSON(http.StatusOK, PostCommentResponse{ 89 | CommonResponse: models.CommonResponse{StatusCode: 1, StatusMsg: msg}, Response: &comment.Response{}}) 90 | } 91 | 92 | func (p *ProxyPostCommentHandler) SendOk(comment *comment.Response) { 93 | p.JSON(http.StatusOK, PostCommentResponse{ 94 | CommonResponse: models.CommonResponse{StatusCode: 0}, 95 | Response: comment, 96 | }) 97 | } 98 | -------------------------------------------------------------------------------- /deprecated/handlers/comment/query_commentlist_handler.go: -------------------------------------------------------------------------------- 1 | package comment 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/handlers/video" 6 | "github.com/ACking-you/byte_douyin_project/models" 7 | "github.com/ACking-you/byte_douyin_project/service/comment" 8 | "github.com/gin-gonic/gin" 9 | "net/http" 10 | "strconv" 11 | ) 12 | 13 | type ListResponse struct { 14 | models.CommonResponse 15 | *comment.List 16 | } 17 | 18 | func QueryCommentListHandler(c *gin.Context) { 19 | NewProxyCommentListHandler(c).Do() 20 | } 21 | 22 | type ProxyCommentListHandler struct { 23 | *gin.Context 24 | 25 | videoId int64 26 | userId int64 27 | } 28 | 29 | func NewProxyCommentListHandler(context *gin.Context) *ProxyCommentListHandler { 30 | return &ProxyCommentListHandler{Context: context} 31 | } 32 | 33 | func (p *ProxyCommentListHandler) Do() { 34 | //解析参数 35 | if err := p.parseNum(); err != nil { 36 | p.SendError(err.Error()) 37 | return 38 | } 39 | 40 | //正式调用 41 | commentList, err := comment.QueryCommentList(p.userId, p.videoId) 42 | if err != nil { 43 | p.SendError(err.Error()) 44 | return 45 | } 46 | 47 | //成功返回 48 | p.SendOk(commentList) 49 | } 50 | 51 | func (p *ProxyCommentListHandler) parseNum() error { 52 | rawUserId, _ := p.Get("user_id") 53 | userId, ok := rawUserId.(int64) 54 | if !ok { 55 | return errors.New("userId解析出错") 56 | } 57 | p.userId = userId 58 | 59 | rawVideoId := p.Query("video_id") 60 | videoId, err := strconv.ParseInt(rawVideoId, 10, 64) 61 | if err != nil { 62 | return err 63 | } 64 | p.videoId = videoId 65 | 66 | return nil 67 | } 68 | 69 | func (p *ProxyCommentListHandler) SendError(msg string) { 70 | p.JSON(http.StatusOK, video.FavorVideoListResponse{ 71 | CommonResponse: models.CommonResponse{StatusCode: 1, StatusMsg: msg}}) 72 | } 73 | 74 | func (p *ProxyCommentListHandler) SendOk(commentList *comment.List) { 75 | p.JSON(http.StatusOK, ListResponse{CommonResponse: models.CommonResponse{StatusCode: 0}, 76 | List: commentList, 77 | }) 78 | } 79 | -------------------------------------------------------------------------------- /deprecated/handlers/user_info/post_follow_action_handler.go: -------------------------------------------------------------------------------- 1 | package user_info 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/models" 6 | "github.com/ACking-you/byte_douyin_project/service/user_info" 7 | "github.com/gin-gonic/gin" 8 | "net/http" 9 | "strconv" 10 | ) 11 | 12 | func PostFollowActionHandler(c *gin.Context) { 13 | NewProxyPostFollowAction(c).Do() 14 | } 15 | 16 | type ProxyPostFollowAction struct { 17 | *gin.Context 18 | 19 | userId int64 20 | followId int64 21 | actionType int 22 | } 23 | 24 | func NewProxyPostFollowAction(context *gin.Context) *ProxyPostFollowAction { 25 | return &ProxyPostFollowAction{Context: context} 26 | } 27 | 28 | func (p *ProxyPostFollowAction) Do() { 29 | var err error 30 | if err = p.prepareNum(); err != nil { 31 | p.SendError(err.Error()) 32 | return 33 | } 34 | if err = p.startAction(); err != nil { 35 | //当错误为model层发生的,那么就是重复键值的插入了 36 | if errors.Is(err, user_info.ErrIvdAct) || errors.Is(err, user_info.ErrIvdFolUsr) { 37 | p.SendError(err.Error()) 38 | } else { 39 | p.SendError("请勿重复关注") 40 | } 41 | return 42 | } 43 | p.SendOk("操作成功") 44 | } 45 | 46 | func (p *ProxyPostFollowAction) prepareNum() error { 47 | rawUserId, _ := p.Get("user_id") 48 | userId, ok := rawUserId.(int64) 49 | if !ok { 50 | return errors.New("userId解析出错") 51 | } 52 | p.userId = userId 53 | 54 | //解析需要关注的id 55 | followId := p.Query("to_user_id") 56 | parseInt, err := strconv.ParseInt(followId, 10, 64) 57 | if err != nil { 58 | return err 59 | } 60 | p.followId = parseInt 61 | 62 | //解析action_type 63 | actionType := p.Query("action_type") 64 | parseInt, err = strconv.ParseInt(actionType, 10, 32) 65 | if err != nil { 66 | return err 67 | } 68 | p.actionType = int(parseInt) 69 | return nil 70 | } 71 | 72 | func (p *ProxyPostFollowAction) startAction() error { 73 | err := user_info.PostFollowAction(p.userId, p.followId, p.actionType) 74 | if err != nil { 75 | return err 76 | } 77 | return nil 78 | } 79 | 80 | func (p *ProxyPostFollowAction) SendError(msg string) { 81 | p.JSON(http.StatusOK, models.CommonResponse{StatusCode: 1, StatusMsg: msg}) 82 | } 83 | 84 | func (p *ProxyPostFollowAction) SendOk(msg string) { 85 | p.JSON(http.StatusOK, models.CommonResponse{StatusCode: 1, StatusMsg: msg}) 86 | } 87 | -------------------------------------------------------------------------------- /deprecated/handlers/user_info/query_follow_list_handler.go: -------------------------------------------------------------------------------- 1 | package user_info 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/models" 6 | "github.com/ACking-you/byte_douyin_project/service/user_info" 7 | "github.com/gin-gonic/gin" 8 | "net/http" 9 | ) 10 | 11 | type FollowListResponse struct { 12 | models.CommonResponse 13 | *user_info.FollowList 14 | } 15 | 16 | func QueryFollowListHandler(c *gin.Context) { 17 | NewProxyQueryFollowList(c).Do() 18 | } 19 | 20 | type ProxyQueryFollowList struct { 21 | *gin.Context 22 | 23 | userId int64 24 | 25 | *user_info.FollowList 26 | } 27 | 28 | func NewProxyQueryFollowList(context *gin.Context) *ProxyQueryFollowList { 29 | return &ProxyQueryFollowList{Context: context} 30 | } 31 | 32 | func (p *ProxyQueryFollowList) Do() { 33 | var err error 34 | if err = p.parseNum(); err != nil { 35 | p.SendError(err.Error()) 36 | return 37 | } 38 | if err = p.prepareData(); err != nil { 39 | p.SendError(err.Error()) 40 | return 41 | } 42 | p.SendOk("请求成功") 43 | } 44 | 45 | func (p *ProxyQueryFollowList) parseNum() error { 46 | rawUserId, _ := p.Get("user_id") 47 | userId, ok := rawUserId.(int64) 48 | if !ok { 49 | return errors.New("userId解析出错") 50 | } 51 | p.userId = userId 52 | return nil 53 | } 54 | 55 | func (p *ProxyQueryFollowList) prepareData() error { 56 | list, err := user_info.QueryFollowList(p.userId) 57 | if err != nil { 58 | return err 59 | } 60 | p.FollowList = list 61 | return nil 62 | } 63 | 64 | func (p *ProxyQueryFollowList) SendError(msg string) { 65 | p.JSON(http.StatusOK, FollowListResponse{ 66 | CommonResponse: models.CommonResponse{StatusCode: 1, StatusMsg: msg}, 67 | }) 68 | } 69 | 70 | func (p *ProxyQueryFollowList) SendOk(msg string) { 71 | p.JSON(http.StatusOK, FollowListResponse{ 72 | CommonResponse: models.CommonResponse{StatusCode: 0, StatusMsg: msg}, 73 | FollowList: p.FollowList, 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /deprecated/handlers/user_info/query_follower_handler.go: -------------------------------------------------------------------------------- 1 | package user_info 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/models" 6 | user_info2 "github.com/ACking-you/byte_douyin_project/service/user_info" 7 | "github.com/gin-gonic/gin" 8 | "net/http" 9 | ) 10 | 11 | type FollowerListResponse struct { 12 | models.CommonResponse 13 | *user_info2.FollowerList 14 | } 15 | 16 | func QueryFollowerHandler(c *gin.Context) { 17 | NewProxyQueryFollowerHandler(c).Do() 18 | } 19 | 20 | type ProxyQueryFollowerHandler struct { 21 | *gin.Context 22 | 23 | userId int64 24 | 25 | *user_info2.FollowerList 26 | } 27 | 28 | func NewProxyQueryFollowerHandler(context *gin.Context) *ProxyQueryFollowerHandler { 29 | return &ProxyQueryFollowerHandler{Context: context} 30 | } 31 | 32 | func (p *ProxyQueryFollowerHandler) Do() { 33 | var err error 34 | if err = p.parseNum(); err != nil { 35 | p.SendError(err.Error()) 36 | return 37 | } 38 | if err = p.prepareData(); err != nil { 39 | if errors.Is(err, user_info2.ErrUserNotExist) { 40 | p.SendError(err.Error()) 41 | } else { 42 | p.SendError("准备数据出错") 43 | } 44 | return 45 | } 46 | p.SendOk("成功") 47 | } 48 | 49 | func (p *ProxyQueryFollowerHandler) parseNum() error { 50 | rawUserId, _ := p.Get("user_id") 51 | userId, ok := rawUserId.(int64) 52 | if !ok { 53 | return errors.New("userId解析出错") 54 | } 55 | p.userId = userId 56 | return nil 57 | } 58 | 59 | func (p *ProxyQueryFollowerHandler) prepareData() error { 60 | list, err := user_info2.QueryFollowerList(p.userId) 61 | if err != nil { 62 | return err 63 | } 64 | p.FollowerList = list 65 | return nil 66 | } 67 | 68 | func (p *ProxyQueryFollowerHandler) SendError(msg string) { 69 | p.JSON(http.StatusOK, FollowerListResponse{ 70 | CommonResponse: models.CommonResponse{ 71 | StatusCode: 1, 72 | StatusMsg: msg, 73 | }, 74 | }) 75 | } 76 | 77 | func (p *ProxyQueryFollowerHandler) SendOk(msg string) { 78 | p.JSON(http.StatusOK, FollowerListResponse{ 79 | CommonResponse: models.CommonResponse{ 80 | StatusCode: 1, 81 | StatusMsg: msg, 82 | }, 83 | FollowerList: p.FollowerList, 84 | }) 85 | } 86 | -------------------------------------------------------------------------------- /deprecated/handlers/user_info/userinfo_handler.go: -------------------------------------------------------------------------------- 1 | package user_info 2 | 3 | import ( 4 | "errors" 5 | models2 "github.com/ACking-you/byte_douyin_project/models" 6 | "github.com/gin-gonic/gin" 7 | "net/http" 8 | ) 9 | 10 | type UserResponse struct { 11 | models2.CommonResponse 12 | User *models2.UserInfo `json:"user"` 13 | } 14 | 15 | func UserInfoHandler(c *gin.Context) { 16 | p := NewProxyUserInfo(c) 17 | //得到上层中间件根据token解析的userId 18 | rawId, ok := c.Get("user_id") 19 | if !ok { 20 | p.UserInfoError("解析userId出错") 21 | return 22 | } 23 | err := p.DoQueryUserInfoByUserId(rawId) 24 | if err != nil { 25 | p.UserInfoError(err.Error()) 26 | } 27 | } 28 | 29 | type ProxyUserInfo struct { 30 | c *gin.Context 31 | } 32 | 33 | func NewProxyUserInfo(c *gin.Context) *ProxyUserInfo { 34 | return &ProxyUserInfo{c: c} 35 | } 36 | 37 | func (p *ProxyUserInfo) DoQueryUserInfoByUserId(rawId interface{}) error { 38 | userId, ok := rawId.(int64) 39 | if !ok { 40 | return errors.New("解析userId失败") 41 | } 42 | //由于得到userinfo不需要组装model层的数据,所以直接调用model层的接口 43 | userinfoDAO := models2.NewUserInfoDAO() 44 | 45 | var userInfo models2.UserInfo 46 | err := userinfoDAO.QueryUserInfoById(userId, &userInfo) 47 | if err != nil { 48 | return err 49 | } 50 | p.UserInfoOk(&userInfo) 51 | return nil 52 | } 53 | 54 | func (p *ProxyUserInfo) UserInfoError(msg string) { 55 | p.c.JSON(http.StatusOK, UserResponse{ 56 | CommonResponse: models2.CommonResponse{StatusCode: 1, StatusMsg: msg}, 57 | }) 58 | } 59 | 60 | func (p *ProxyUserInfo) UserInfoOk(user *models2.UserInfo) { 61 | p.c.JSON(http.StatusOK, UserResponse{ 62 | CommonResponse: models2.CommonResponse{StatusCode: 0}, 63 | User: user, 64 | }) 65 | } 66 | -------------------------------------------------------------------------------- /deprecated/handlers/user_login/user_login_handler.go: -------------------------------------------------------------------------------- 1 | package user_login 2 | 3 | import ( 4 | "github.com/ACking-you/byte_douyin_project/models" 5 | "github.com/ACking-you/byte_douyin_project/service/user_login" 6 | "github.com/gin-gonic/gin" 7 | "net/http" 8 | ) 9 | 10 | type UserLoginResponse struct { 11 | models.CommonResponse 12 | *user_login.LoginResponse 13 | } 14 | 15 | func UserLoginHandler(c *gin.Context) { 16 | username := c.Query("username") 17 | raw, _ := c.Get("password") 18 | password, ok := raw.(string) 19 | if !ok { 20 | c.JSON(http.StatusOK, UserLoginResponse{ 21 | CommonResponse: models.CommonResponse{ 22 | StatusCode: 1, 23 | StatusMsg: "密码解析错误", 24 | }, 25 | }) 26 | } 27 | userLoginResponse, err := user_login.QueryUserLogin(username, password) 28 | 29 | //用户不存在返回对应的错误 30 | if err != nil { 31 | c.JSON(http.StatusOK, UserLoginResponse{ 32 | CommonResponse: models.CommonResponse{StatusCode: 1, StatusMsg: err.Error()}, 33 | }) 34 | return 35 | } 36 | 37 | //用户存在,返回相应的id和token 38 | c.JSON(http.StatusOK, UserLoginResponse{ 39 | CommonResponse: models.CommonResponse{StatusCode: 0}, 40 | LoginResponse: userLoginResponse, 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /deprecated/handlers/user_login/user_register_handler.go: -------------------------------------------------------------------------------- 1 | package user_login 2 | 3 | import ( 4 | "github.com/ACking-you/byte_douyin_project/models" 5 | user_login2 "github.com/ACking-you/byte_douyin_project/service/user_login" 6 | "github.com/gin-gonic/gin" 7 | "net/http" 8 | ) 9 | 10 | type UserRegisterResponse struct { 11 | models.CommonResponse 12 | *user_login2.LoginResponse 13 | } 14 | 15 | func UserRegisterHandler(c *gin.Context) { 16 | username := c.Query("username") 17 | rawVal, _ := c.Get("password") 18 | password, ok := rawVal.(string) 19 | if !ok { 20 | c.JSON(http.StatusOK, UserRegisterResponse{ 21 | CommonResponse: models.CommonResponse{ 22 | StatusCode: 1, 23 | StatusMsg: "密码解析出错", 24 | }, 25 | }) 26 | return 27 | } 28 | registerResponse, err := user_login2.PostUserLogin(username, password) 29 | 30 | if err != nil { 31 | c.JSON(http.StatusOK, UserRegisterResponse{ 32 | CommonResponse: models.CommonResponse{ 33 | StatusCode: 1, 34 | StatusMsg: err.Error(), 35 | }, 36 | }) 37 | return 38 | } 39 | c.JSON(http.StatusOK, UserRegisterResponse{ 40 | CommonResponse: models.CommonResponse{StatusCode: 0}, 41 | LoginResponse: registerResponse, 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /deprecated/handlers/video/feed_videolist_handler.go: -------------------------------------------------------------------------------- 1 | package video 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/middleware" 6 | "github.com/ACking-you/byte_douyin_project/models" 7 | "github.com/ACking-you/byte_douyin_project/service/video" 8 | "github.com/gin-gonic/gin" 9 | "net/http" 10 | "strconv" 11 | "time" 12 | ) 13 | 14 | type FeedResponse struct { 15 | models.CommonResponse 16 | *video.FeedVideoList 17 | } 18 | 19 | func FeedVideoListHandler(c *gin.Context) { 20 | p := NewProxyFeedVideoList(c) 21 | token, ok := c.GetQuery("token") 22 | //无登录状态 23 | if !ok { 24 | err := p.DoNoToken() 25 | if err != nil { 26 | p.FeedVideoListError(err.Error()) 27 | } 28 | return 29 | } 30 | 31 | //有登录状态 32 | err := p.DoHasToken(token) 33 | if err != nil { 34 | p.FeedVideoListError(err.Error()) 35 | } 36 | } 37 | 38 | type ProxyFeedVideoList struct { 39 | *gin.Context 40 | } 41 | 42 | func NewProxyFeedVideoList(c *gin.Context) *ProxyFeedVideoList { 43 | return &ProxyFeedVideoList{Context: c} 44 | } 45 | 46 | // DoNoToken 未登录的视频流推送处理 47 | func (p *ProxyFeedVideoList) DoNoToken() error { 48 | rawTimestamp := p.Query("latest_time") 49 | var latestTime time.Time 50 | intTime, err := strconv.ParseInt(rawTimestamp, 10, 64) 51 | if err == nil { 52 | latestTime = time.Unix(0, intTime*1e6) //注意:前端传来的时间戳是以ms为单位的 53 | } 54 | videoList, err := video.QueryFeedVideoList(0, latestTime) 55 | if err != nil { 56 | return err 57 | } 58 | p.FeedVideoListOk(videoList) 59 | return nil 60 | } 61 | 62 | // DoHasToken 如果是登录状态,则生成UserId字段 63 | func (p *ProxyFeedVideoList) DoHasToken(token string) error { 64 | //解析成功 65 | if claim, ok := middleware.ParseToken(token); ok { 66 | //token超时 67 | if time.Now().Unix() > claim.ExpiresAt { 68 | return errors.New("token超时") 69 | } 70 | rawTimestamp := p.Query("latest_time") 71 | var latestTime time.Time 72 | intTime, err := strconv.ParseInt(rawTimestamp, 10, 64) 73 | if err != nil { 74 | latestTime = time.Unix(0, intTime*1e6) //注意:前端传来的时间戳是以ms为单位的 75 | } 76 | //调用service层接口 77 | videoList, err := video.QueryFeedVideoList(claim.UserId, latestTime) 78 | if err != nil { 79 | return err 80 | } 81 | p.FeedVideoListOk(videoList) 82 | return nil 83 | } 84 | //解析失败 85 | return errors.New("token不正确") 86 | } 87 | 88 | func (p *ProxyFeedVideoList) FeedVideoListError(msg string) { 89 | p.JSON(http.StatusOK, FeedResponse{CommonResponse: models.CommonResponse{ 90 | StatusCode: 1, 91 | StatusMsg: msg, 92 | }}) 93 | } 94 | 95 | func (p *ProxyFeedVideoList) FeedVideoListOk(videoList *video.FeedVideoList) { 96 | p.JSON(http.StatusOK, FeedResponse{ 97 | CommonResponse: models.CommonResponse{ 98 | StatusCode: 0, 99 | }, 100 | FeedVideoList: videoList, 101 | }, 102 | ) 103 | } 104 | -------------------------------------------------------------------------------- /deprecated/handlers/video/post_favor_handler.go: -------------------------------------------------------------------------------- 1 | package video 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/models" 6 | "github.com/ACking-you/byte_douyin_project/service/video" 7 | "github.com/gin-gonic/gin" 8 | "net/http" 9 | "strconv" 10 | ) 11 | 12 | func PostFavorHandler(c *gin.Context) { 13 | NewProxyPostFavorHandler(c).Do() 14 | } 15 | 16 | type ProxyPostFavorHandler struct { 17 | *gin.Context 18 | 19 | userId int64 20 | videoId int64 21 | actionType int64 22 | } 23 | 24 | func NewProxyPostFavorHandler(c *gin.Context) *ProxyPostFavorHandler { 25 | return &ProxyPostFavorHandler{Context: c} 26 | } 27 | 28 | func (p *ProxyPostFavorHandler) Do() { 29 | //解析参数 30 | if err := p.parseNum(); err != nil { 31 | p.SendError(err.Error()) 32 | return 33 | } 34 | 35 | //正式调用 36 | err := video.PostFavorState(p.userId, p.videoId, p.actionType) 37 | if err != nil { 38 | p.SendError(err.Error()) 39 | return 40 | } 41 | 42 | //成功返回 43 | p.SendOk() 44 | } 45 | 46 | func (p *ProxyPostFavorHandler) parseNum() error { 47 | //解析userId 48 | rawUserId, _ := p.Get("user_id") 49 | userId, ok := rawUserId.(int64) 50 | if !ok { 51 | return errors.New("userId解析出错") 52 | } 53 | 54 | rawVideoId := p.Query("video_id") 55 | videoId, err := strconv.ParseInt(rawVideoId, 10, 64) 56 | if err != nil { 57 | return err 58 | } 59 | rawActionType := p.Query("action_type") 60 | actionType, err := strconv.ParseInt(rawActionType, 10, 64) 61 | if err != nil { 62 | return err 63 | } 64 | p.videoId = videoId 65 | p.actionType = actionType 66 | p.userId = userId 67 | return nil 68 | } 69 | 70 | func (p *ProxyPostFavorHandler) SendError(msg string) { 71 | p.JSON(http.StatusOK, models.CommonResponse{StatusCode: 1, StatusMsg: msg}) 72 | } 73 | 74 | func (p *ProxyPostFavorHandler) SendOk() { 75 | p.JSON(http.StatusOK, models.CommonResponse{StatusCode: 0}) 76 | } 77 | -------------------------------------------------------------------------------- /deprecated/handlers/video/publish_video_handler.go: -------------------------------------------------------------------------------- 1 | package video 2 | 3 | import ( 4 | "github.com/ACking-you/byte_douyin_project/config" 5 | "github.com/ACking-you/byte_douyin_project/models" 6 | "github.com/ACking-you/byte_douyin_project/service/video" 7 | util2 "github.com/ACking-you/byte_douyin_project/util" 8 | "github.com/gin-gonic/gin" 9 | "net/http" 10 | "path/filepath" 11 | ) 12 | 13 | var ( 14 | videoIndexMap = map[string]struct{}{ 15 | ".mp4": {}, 16 | ".avi": {}, 17 | ".wmv": {}, 18 | ".flv": {}, 19 | ".mpeg": {}, 20 | ".mov": {}, 21 | } 22 | pictureIndexMap = map[string]struct{}{ 23 | ".jpg": {}, 24 | ".bmp": {}, 25 | ".png": {}, 26 | ".svg": {}, 27 | } 28 | ) 29 | 30 | // PublishVideoHandler 发布视频,并截取一帧画面作为封面 31 | func PublishVideoHandler(c *gin.Context) { 32 | //准备参数 33 | rawId, _ := c.Get("user_id") 34 | 35 | userId, ok := rawId.(int64) 36 | if !ok { 37 | PublishVideoError(c, "解析UserId出错") 38 | return 39 | } 40 | 41 | title := c.PostForm("title") 42 | 43 | form, err := c.MultipartForm() 44 | if err != nil { 45 | PublishVideoError(c, err.Error()) 46 | return 47 | } 48 | 49 | //支持多文件上传 50 | files := form.File["data"] 51 | for _, file := range files { 52 | suffix := filepath.Ext(file.Filename) //得到后缀 53 | if _, ok := videoIndexMap[suffix]; !ok { //判断是否为视频格式 54 | PublishVideoError(c, "不支持的视频格式") 55 | continue 56 | } 57 | name := util2.NewFileName(userId) //根据userId得到唯一的文件名 58 | filename := name + suffix 59 | savePath := filepath.Join(config.Global.StaticSourcePath, filename) 60 | err = c.SaveUploadedFile(file, savePath) 61 | if err != nil { 62 | PublishVideoError(c, err.Error()) 63 | continue 64 | } 65 | //截取一帧画面作为封面 66 | err = util2.SaveImageFromVideo(name, false) 67 | if err != nil { 68 | PublishVideoError(c, err.Error()) 69 | continue 70 | } 71 | //数据库持久化 72 | err := video.PostVideo(userId, filename, name+util2.GetDefaultImageSuffix(), title) 73 | if err != nil { 74 | PublishVideoError(c, err.Error()) 75 | continue 76 | } 77 | PublishVideoOk(c, file.Filename+"上传成功") 78 | } 79 | } 80 | 81 | func PublishVideoError(c *gin.Context, msg string) { 82 | c.JSON(http.StatusOK, models.CommonResponse{StatusCode: 1, 83 | StatusMsg: msg}) 84 | } 85 | 86 | func PublishVideoOk(c *gin.Context, msg string) { 87 | c.JSON(http.StatusOK, models.CommonResponse{StatusCode: 0, StatusMsg: msg}) 88 | } 89 | -------------------------------------------------------------------------------- /deprecated/handlers/video/query_favor_videolist_handler.go: -------------------------------------------------------------------------------- 1 | package video 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/models" 6 | "github.com/ACking-you/byte_douyin_project/service/video" 7 | "github.com/gin-gonic/gin" 8 | "net/http" 9 | ) 10 | 11 | type FavorVideoListResponse struct { 12 | models.CommonResponse 13 | *video.FavorList 14 | } 15 | 16 | func QueryFavorVideoListHandler(c *gin.Context) { 17 | NewProxyFavorVideoListHandler(c).Do() 18 | } 19 | 20 | type ProxyFavorVideoListHandler struct { 21 | *gin.Context 22 | 23 | userId int64 24 | } 25 | 26 | func NewProxyFavorVideoListHandler(c *gin.Context) *ProxyFavorVideoListHandler { 27 | return &ProxyFavorVideoListHandler{Context: c} 28 | } 29 | 30 | func (p *ProxyFavorVideoListHandler) Do() { 31 | //解析参数 32 | if err := p.parseNum(); err != nil { 33 | p.SendError(err.Error()) 34 | return 35 | } 36 | 37 | //正式调用 38 | favorVideoList, err := video.QueryFavorVideoList(p.userId) 39 | if err != nil { 40 | p.SendError(err.Error()) 41 | return 42 | } 43 | 44 | //成功返回 45 | p.SendOk(favorVideoList) 46 | } 47 | 48 | func (p *ProxyFavorVideoListHandler) parseNum() error { 49 | rawUserId, _ := p.Get("user_id") 50 | userId, ok := rawUserId.(int64) 51 | if !ok { 52 | return errors.New("userId解析出错") 53 | } 54 | p.userId = userId 55 | return nil 56 | } 57 | 58 | func (p *ProxyFavorVideoListHandler) SendError(msg string) { 59 | p.JSON(http.StatusOK, FavorVideoListResponse{ 60 | CommonResponse: models.CommonResponse{StatusCode: 1, StatusMsg: msg}}) 61 | } 62 | 63 | func (p *ProxyFavorVideoListHandler) SendOk(favorList *video.FavorList) { 64 | p.JSON(http.StatusOK, FavorVideoListResponse{CommonResponse: models.CommonResponse{StatusCode: 0}, 65 | FavorList: favorList, 66 | }) 67 | } 68 | -------------------------------------------------------------------------------- /deprecated/handlers/video/query_videolist_handler.go: -------------------------------------------------------------------------------- 1 | package video 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/models" 6 | "github.com/ACking-you/byte_douyin_project/service/video" 7 | "github.com/gin-gonic/gin" 8 | "net/http" 9 | ) 10 | 11 | type ListResponse struct { 12 | models.CommonResponse 13 | *video.List 14 | } 15 | 16 | func QueryVideoListHandler(c *gin.Context) { 17 | p := NewProxyQueryVideoList(c) 18 | rawId, _ := c.Get("user_id") 19 | err := p.DoQueryVideoListByUserId(rawId) 20 | if err != nil { 21 | p.QueryVideoListError(err.Error()) 22 | } 23 | } 24 | 25 | // ProxyQueryVideoList 代理类 26 | type ProxyQueryVideoList struct { 27 | c *gin.Context 28 | } 29 | 30 | func NewProxyQueryVideoList(c *gin.Context) *ProxyQueryVideoList { 31 | return &ProxyQueryVideoList{c: c} 32 | } 33 | 34 | // DoQueryVideoListByUserId 根据userId字段进行查询 35 | func (p *ProxyQueryVideoList) DoQueryVideoListByUserId(rawId interface{}) error { 36 | userId, ok := rawId.(int64) 37 | if !ok { 38 | return errors.New("userId解析出错") 39 | } 40 | 41 | videoList, err := video.QueryVideoListByUserId(userId) 42 | if err != nil { 43 | return err 44 | } 45 | 46 | p.QueryVideoListOk(videoList) 47 | return nil 48 | } 49 | 50 | func (p *ProxyQueryVideoList) QueryVideoListError(msg string) { 51 | p.c.JSON(http.StatusOK, ListResponse{CommonResponse: models.CommonResponse{ 52 | StatusCode: 1, 53 | StatusMsg: msg, 54 | }}) 55 | } 56 | 57 | func (p *ProxyQueryVideoList) QueryVideoListOk(videoList *video.List) { 58 | p.c.JSON(http.StatusOK, ListResponse{ 59 | CommonResponse: models.CommonResponse{ 60 | StatusCode: 0, 61 | }, 62 | List: videoList, 63 | }) 64 | } 65 | -------------------------------------------------------------------------------- /deprecated/lib/ffmpeg.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acking-you/byte_douyin_project/09a12ca6caf1ae42e72d6c28d4e8d945ca6cd7d2/deprecated/lib/ffmpeg.exe -------------------------------------------------------------------------------- /deprecated/lib/ffprobe.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acking-you/byte_douyin_project/09a12ca6caf1ae42e72d6c28d4e8d945ca6cd7d2/deprecated/lib/ffprobe.exe -------------------------------------------------------------------------------- /deprecated/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/ACking-you/byte_douyin_project/config" 6 | "github.com/ACking-you/byte_douyin_project/router" 7 | ) 8 | 9 | func main() { 10 | r := router.Init() 11 | err := r.Run(fmt.Sprintf(":%d", config.Global.Port)) // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080") 12 | if err != nil { 13 | return 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /deprecated/middleware/jwt.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | models2 "github.com/ACking-you/byte_douyin_project/models" 5 | "github.com/dgrijalva/jwt-go" 6 | "github.com/gin-gonic/gin" 7 | "net/http" 8 | "time" 9 | ) 10 | 11 | var jwtKey = []byte("acking-you.xyz") 12 | 13 | type Claims struct { 14 | UserId int64 15 | jwt.StandardClaims 16 | } 17 | 18 | // ReleaseToken 颁发token 19 | func ReleaseToken(user models2.UserLogin) (string, error) { 20 | expirationTime := time.Now().Add(7 * 24 * time.Hour) 21 | claims := &Claims{ 22 | UserId: user.UserInfoId, 23 | StandardClaims: jwt.StandardClaims{ 24 | ExpiresAt: expirationTime.Unix(), 25 | IssuedAt: time.Now().Unix(), 26 | Issuer: "douyin_pro_131", 27 | Subject: "L_B__", 28 | }} 29 | 30 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 31 | tokenString, err := token.SignedString(jwtKey) 32 | if err != nil { 33 | return "", err 34 | } 35 | return tokenString, nil 36 | } 37 | 38 | // ParseToken 解析token 39 | func ParseToken(tokenString string) (*Claims, bool) { 40 | token, _ := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) { 41 | return jwtKey, nil 42 | }) 43 | if token != nil { 44 | if key, ok := token.Claims.(*Claims); ok { 45 | if token.Valid { 46 | return key, true 47 | } else { 48 | return key, false 49 | } 50 | } 51 | } 52 | return nil, false 53 | } 54 | 55 | // JWTMiddleWare 鉴权中间件,鉴权并设置user_id 56 | func JWTMiddleWare() gin.HandlerFunc { 57 | return func(c *gin.Context) { 58 | tokenStr := c.Query("token") 59 | if tokenStr == "" { 60 | tokenStr = c.PostForm("token") 61 | } 62 | //用户不存在 63 | if tokenStr == "" { 64 | c.JSON(http.StatusOK, models2.CommonResponse{StatusCode: 401, StatusMsg: "用户不存在"}) 65 | c.Abort() //阻止执行 66 | return 67 | } 68 | //验证token 69 | tokenStruck, ok := ParseToken(tokenStr) 70 | if !ok { 71 | c.JSON(http.StatusOK, models2.CommonResponse{ 72 | StatusCode: 403, 73 | StatusMsg: "token不正确", 74 | }) 75 | c.Abort() //阻止执行 76 | return 77 | } 78 | //token超时 79 | if time.Now().Unix() > tokenStruck.ExpiresAt { 80 | c.JSON(http.StatusOK, models2.CommonResponse{ 81 | StatusCode: 402, 82 | StatusMsg: "token过期", 83 | }) 84 | c.Abort() //阻止执行 85 | return 86 | } 87 | c.Set("user_id", tokenStruck.UserId) 88 | c.Next() 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /deprecated/middleware/jwt_test.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestJwt(t *testing.T) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /deprecated/middleware/normal.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/ACking-you/byte_douyin_project/models" 5 | "github.com/gin-gonic/gin" 6 | "net/http" 7 | "strconv" 8 | ) 9 | 10 | func NoAuthToGetUserId() gin.HandlerFunc { 11 | return func(c *gin.Context) { 12 | rawId := c.Query("user_id") 13 | if rawId == "" { 14 | rawId = c.PostForm("user_id") 15 | } 16 | //用户不存在 17 | if rawId == "" { 18 | c.JSON(http.StatusOK, models.CommonResponse{StatusCode: 401, StatusMsg: "用户不存在"}) 19 | c.Abort() //阻止执行 20 | return 21 | } 22 | userId, err := strconv.ParseInt(rawId, 10, 64) 23 | if err != nil { 24 | c.JSON(http.StatusOK, models.CommonResponse{StatusCode: 401, StatusMsg: "用户不存在"}) 25 | c.Abort() //阻止执行 26 | } 27 | c.Set("user_id", userId) 28 | c.Next() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /deprecated/middleware/password.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "crypto/sha1" 5 | "encoding/hex" 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | func SHA1(s string) string { 10 | 11 | o := sha1.New() 12 | 13 | o.Write([]byte(s)) 14 | 15 | return hex.EncodeToString(o.Sum(nil)) 16 | } 17 | 18 | func SHAMiddleWare() gin.HandlerFunc { 19 | return func(context *gin.Context) { 20 | password := context.Query("password") 21 | if password == "" { 22 | password = context.PostForm("password") 23 | } 24 | context.Set("password", SHA1(password)) 25 | context.Next() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /deprecated/middleware/password_test.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import "testing" 4 | 5 | //40bd001563085fc35165329ea1ff5c5ecbdbbeef 6 | func TestSHA1(t *testing.T) { 7 | print(SHA1("123")) 8 | } 9 | -------------------------------------------------------------------------------- /deprecated/models/comment.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "gorm.io/gorm" 6 | "time" 7 | ) 8 | 9 | type Comment struct { 10 | Id int64 `json:"id"` 11 | UserInfoId int64 `json:"-"` //用于一对多关系的id 12 | VideoId int64 `json:"-"` //一对多,视频对评论 13 | User UserInfo `json:"user" gorm:"-"` 14 | Content string `json:"content"` 15 | CreatedAt time.Time `json:"-"` 16 | CreateDate string `json:"create_date" gorm:"-"` 17 | } 18 | 19 | type CommentDAO struct { 20 | } 21 | 22 | var ( 23 | commentDao CommentDAO 24 | ) 25 | 26 | func NewCommentDAO() *CommentDAO { 27 | return &commentDao 28 | } 29 | 30 | func (c *CommentDAO) AddCommentAndUpdateCount(comment *Comment) error { 31 | if comment == nil { 32 | return errors.New("AddCommentAndUpdateCount comment空指针") 33 | } 34 | //执行事务 35 | return DB.Transaction(func(tx *gorm.DB) error { 36 | //添加评论数据 37 | if err := tx.Create(comment).Error; err != nil { 38 | // 返回任何错误都会回滚事务 39 | return err 40 | } 41 | //增加count 42 | if err := tx.Exec("UPDATE videos v SET v.comment_count = v.comment_count+1 WHERE v.id=?", comment.VideoId).Error; err != nil { 43 | return err 44 | } 45 | 46 | // 返回 nil 提交事务 47 | return nil 48 | }) 49 | } 50 | 51 | func (c *CommentDAO) DeleteCommentAndUpdateCountById(commentId, videoId int64) error { 52 | //执行事务 53 | return DB.Transaction(func(tx *gorm.DB) error { 54 | //删除评论 55 | if err := tx.Exec("DELETE FROM comments WHERE id = ?", commentId).Error; err != nil { 56 | // 返回任何错误都会回滚事务 57 | return err 58 | } 59 | //减少count 60 | if err := tx.Exec("UPDATE videos v SET v.comment_count = v.comment_count-1 WHERE v.id=? AND v.comment_count>0", videoId).Error; err != nil { 61 | return err 62 | } 63 | // 返回 nil 提交事务 64 | return nil 65 | }) 66 | } 67 | 68 | func (c *CommentDAO) QueryCommentById(id int64, comment *Comment) error { 69 | if comment == nil { 70 | return errors.New("QueryCommentById comment 空指针") 71 | } 72 | return DB.Where("id=?", id).First(comment).Error 73 | } 74 | 75 | func (c *CommentDAO) QueryCommentListByVideoId(videoId int64, comments *[]*Comment) error { 76 | if comments == nil { 77 | return errors.New("QueryCommentListByVideoId comments空指针") 78 | } 79 | if err := DB.Model(&Comment{}).Where("video_id=?", videoId).Find(comments).Error; err != nil { 80 | return err 81 | } 82 | return nil 83 | } 84 | -------------------------------------------------------------------------------- /deprecated/models/common.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type CommonResponse struct { 4 | StatusCode int32 `json:"status_code"` 5 | StatusMsg string `json:"status_msg,omitempty"` 6 | } 7 | -------------------------------------------------------------------------------- /deprecated/models/init_db.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/ACking-you/byte_douyin_project/config" 5 | "gorm.io/driver/mysql" 6 | "gorm.io/gorm" 7 | ) 8 | 9 | var DB *gorm.DB 10 | 11 | func InitDB() { 12 | var err error 13 | DB, err = gorm.Open(mysql.Open(config.DBConnectString()), &gorm.Config{ 14 | PrepareStmt: true, //缓存预编译命令 15 | SkipDefaultTransaction: true, //禁用默认事务操作 16 | //Logger: logger.Default.LogMode(logger.Global), //打印sql语句 17 | }) 18 | if err != nil { 19 | panic(err) 20 | } 21 | err = DB.AutoMigrate(&UserInfo{}, &Video{}, &Comment{}, &UserLogin{}) 22 | if err != nil { 23 | panic(err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /deprecated/models/user_info.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "gorm.io/gorm" 6 | "log" 7 | "sync" 8 | ) 9 | 10 | var ( 11 | ErrIvdPtr = errors.New("空指针错误") 12 | ErrEmptyUserList = errors.New("用户列表为空") 13 | ) 14 | 15 | type UserInfo struct { 16 | Id int64 `json:"id" gorm:"id,omitempty"` 17 | Name string `json:"name" gorm:"name,omitempty"` 18 | FollowCount int64 `json:"follow_count" gorm:"follow_count,omitempty"` 19 | FollowerCount int64 `json:"follower_count" gorm:"follower_count,omitempty"` 20 | IsFollow bool `json:"is_follow" gorm:"is_follow,omitempty"` 21 | User *UserLogin `json:"-"` //用户与账号密码之间的一对一 22 | Videos []*Video `json:"-"` //用户与投稿视频的一对多 23 | Follows []*UserInfo `json:"-" gorm:"many2many:user_relations;"` //用户之间的多对多 24 | FavorVideos []*Video `json:"-" gorm:"many2many:user_favor_videos;"` //用户与点赞视频之间的多对多 25 | Comments []*Comment `json:"-"` //用户与评论的一对多 26 | } 27 | 28 | type UserInfoDAO struct { 29 | } 30 | 31 | var ( 32 | userInfoDAO *UserInfoDAO 33 | userInfoOnce sync.Once 34 | ) 35 | 36 | func NewUserInfoDAO() *UserInfoDAO { 37 | userInfoOnce.Do(func() { 38 | userInfoDAO = new(UserInfoDAO) 39 | }) 40 | return userInfoDAO 41 | } 42 | 43 | func (u *UserInfoDAO) QueryUserInfoById(userId int64, userinfo *UserInfo) error { 44 | if userinfo == nil { 45 | return ErrIvdPtr 46 | } 47 | //DB.Where("id=?",userId).First(userinfo) 48 | DB.Where("id=?", userId).Select([]string{"id", "name", "follow_count", "follower_count", "is_follow"}).First(userinfo) 49 | //id为零值,说明sql执行失败 50 | if userinfo.Id == 0 { 51 | return errors.New("该用户不存在") 52 | } 53 | return nil 54 | } 55 | 56 | func (u *UserInfoDAO) AddUserInfo(userinfo *UserInfo) error { 57 | if userinfo == nil { 58 | return ErrIvdPtr 59 | } 60 | return DB.Create(userinfo).Error 61 | } 62 | 63 | func (u *UserInfoDAO) IsUserExistById(id int64) bool { 64 | var userinfo UserInfo 65 | if err := DB.Where("id=?", id).Select("id").First(&userinfo).Error; err != nil { 66 | log.Println(err) 67 | } 68 | if userinfo.Id == 0 { 69 | return false 70 | } 71 | return true 72 | } 73 | func (u *UserInfoDAO) AddUserFollow(userId, userToId int64) error { 74 | return DB.Transaction(func(tx *gorm.DB) error { 75 | if err := tx.Exec("UPDATE user_infos SET follow_count=follow_count+1 WHERE id = ?", userId).Error; err != nil { 76 | return err 77 | } 78 | if err := tx.Exec("UPDATE user_infos SET follower_count=follower_count+1 WHERE id = ?", userToId).Error; err != nil { 79 | return err 80 | } 81 | if err := tx.Exec("INSERT INTO `user_relations` (`user_info_id`,`follow_id`) VALUES (?,?)", userId, userToId).Error; err != nil { 82 | return err 83 | } 84 | return nil 85 | }) 86 | } 87 | 88 | func (u *UserInfoDAO) CancelUserFollow(userId, userToId int64) error { 89 | return DB.Transaction(func(tx *gorm.DB) error { 90 | if err := tx.Exec("UPDATE user_infos SET follow_count=follow_count-1 WHERE id = ? AND follow_count>0", userId).Error; err != nil { 91 | return err 92 | } 93 | if err := tx.Exec("UPDATE user_infos SET follower_count=follower_count-1 WHERE id = ? AND follower_count>0", userToId).Error; err != nil { 94 | return err 95 | } 96 | if err := tx.Exec("DELETE FROM `user_relations` WHERE user_info_id=? AND follow_id=?", userId, userToId).Error; err != nil { 97 | return err 98 | } 99 | return nil 100 | }) 101 | } 102 | 103 | func (u *UserInfoDAO) GetFollowListByUserId(userId int64, userList *[]*UserInfo) error { 104 | if userList == nil { 105 | return ErrIvdPtr 106 | } 107 | var err error 108 | if err = DB.Raw("SELECT u.* FROM user_relations r, user_infos u WHERE r.user_info_id = ? AND r.follow_id = u.id", userId).Scan(userList).Error; err != nil { 109 | return err 110 | } 111 | if len(*userList) == 0 || (*userList)[0].Id == 0 { 112 | return ErrEmptyUserList 113 | } 114 | return nil 115 | } 116 | 117 | func (u *UserInfoDAO) GetFollowerListByUserId(userId int64, userList *[]*UserInfo) error { 118 | if userList == nil { 119 | return ErrIvdPtr 120 | } 121 | var err error 122 | if err = DB.Raw("SELECT u.* FROM user_relations r, user_infos u WHERE r.follow_id = ? AND r.user_info_id = u.id", userId).Scan(userList).Error; err != nil { 123 | return err 124 | } 125 | //if len(*userList) == 0 || (*userList)[0].Id == 0 { 126 | // return ErrEmptyUserList 127 | //} 128 | return nil 129 | } 130 | -------------------------------------------------------------------------------- /deprecated/models/user_info_test.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | func TestMain(m *testing.M) { 10 | InitDB() 11 | code := m.Run() 12 | os.Exit(code) 13 | } 14 | 15 | func TestUserInfoDAO_GetFollowListByUserId(t *testing.T) { 16 | var userList []*UserInfo 17 | err := NewUserInfoDAO().GetFollowListByUserId(1, &userList) 18 | if err != nil { 19 | panic(err) 20 | } 21 | for _, user := range userList { 22 | fmt.Printf("%#v\n", *user) 23 | } 24 | } 25 | 26 | func TestUserInfoDAO_GetFollowerListByUserId(t *testing.T) { 27 | var userList []*UserInfo 28 | err := NewUserInfoDAO().GetFollowerListByUserId(2, &userList) 29 | if err != nil { 30 | panic(err) 31 | } 32 | for _, user := range userList { 33 | fmt.Printf("%#v\n", *user) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /deprecated/models/user_login.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "sync" 6 | ) 7 | 8 | // UserLogin 用户登录表,和UserInfo属于一对一关系 9 | type UserLogin struct { 10 | Id int64 `gorm:"primary_key"` 11 | UserInfoId int64 12 | Username string `gorm:"primary_key"` 13 | Password string `gorm:"size:200;notnull"` 14 | } 15 | 16 | type UserLoginDAO struct { 17 | } 18 | 19 | var ( 20 | userLoginDao *UserLoginDAO 21 | userLoginOnce sync.Once 22 | ) 23 | 24 | func NewUserLoginDao() *UserLoginDAO { 25 | userLoginOnce.Do(func() { 26 | userLoginDao = new(UserLoginDAO) 27 | }) 28 | return userLoginDao 29 | } 30 | 31 | func (u *UserLoginDAO) QueryUserLogin(username, password string, login *UserLogin) error { 32 | if login == nil { 33 | return errors.New("结构体指针为空") 34 | } 35 | DB.Where("username=? and password=?", username, password).First(login) 36 | if login.Id == 0 { 37 | return errors.New("用户不存在,账号或密码出错") 38 | } 39 | return nil 40 | } 41 | 42 | func (u *UserLoginDAO) IsUserExistByUsername(username string) bool { 43 | var userLogin UserLogin 44 | DB.Where("username=?", username).First(&userLogin) 45 | if userLogin.Id == 0 { 46 | return false 47 | } 48 | return true 49 | } 50 | -------------------------------------------------------------------------------- /deprecated/models/video.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "errors" 5 | "gorm.io/gorm" 6 | "log" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | type Video struct { 12 | Id int64 `json:"id,omitempty"` 13 | UserInfoId int64 `json:"-"` 14 | Author UserInfo `json:"author,omitempty" gorm:"-"` //这里应该是作者对视频的一对多的关系,而不是视频对作者,故gorm不能存他,但json需要返回它 15 | PlayUrl string `json:"play_url,omitempty"` 16 | CoverUrl string `json:"cover_url,omitempty"` 17 | FavoriteCount int64 `json:"favorite_count,omitempty"` 18 | CommentCount int64 `json:"comment_count,omitempty"` 19 | IsFavorite bool `json:"is_favorite,omitempty"` 20 | Title string `json:"title,omitempty"` 21 | Users []*UserInfo `json:"-" gorm:"many2many:user_favor_videos;"` 22 | Comments []*Comment `json:"-"` 23 | CreatedAt time.Time `json:"-"` 24 | UpdatedAt time.Time `json:"-"` 25 | } 26 | 27 | type VideoDAO struct { 28 | } 29 | 30 | var ( 31 | videoDAO *VideoDAO 32 | videoOnce sync.Once 33 | ) 34 | 35 | func NewVideoDAO() *VideoDAO { 36 | videoOnce.Do(func() { 37 | videoDAO = new(VideoDAO) 38 | }) 39 | return videoDAO 40 | } 41 | 42 | // AddVideo 添加视频 43 | // 注意:由于视频和userinfo有多对一的关系,所以传入的Video参数一定要进行id的映射处理! 44 | func (v *VideoDAO) AddVideo(video *Video) error { 45 | if video == nil { 46 | return errors.New("AddVideo video 空指针") 47 | } 48 | return DB.Create(video).Error 49 | } 50 | 51 | func (v *VideoDAO) QueryVideoByVideoId(videoId int64, video *Video) error { 52 | if video == nil { 53 | return errors.New("QueryVideoByVideoId 空指针") 54 | } 55 | return DB.Where("id=?", videoId). 56 | Select([]string{"id", "user_info_id", "play_url", "cover_url", "favorite_count", "comment_count", "is_favorite", "title"}). 57 | First(video).Error 58 | } 59 | 60 | func (v *VideoDAO) QueryVideoCountByUserId(userId int64, count *int64) error { 61 | if count == nil { 62 | return errors.New("QueryVideoCountByUserId count 空指针") 63 | } 64 | return DB.Model(&Video{}).Where("user_info_id=?", userId).Count(count).Error 65 | } 66 | 67 | func (v *VideoDAO) QueryVideoListByUserId(userId int64, videoList *[]*Video) error { 68 | if videoList == nil { 69 | return errors.New("QueryVideoListByUserId videoList 空指针") 70 | } 71 | return DB.Where("user_info_id=?", userId). 72 | Select([]string{"id", "user_info_id", "play_url", "cover_url", "favorite_count", "comment_count", "is_favorite", "title"}). 73 | Find(videoList).Error 74 | } 75 | 76 | // QueryVideoListByLimitAndTime 返回按投稿时间倒序的视频列表,并限制为最多limit个 77 | func (v *VideoDAO) QueryVideoListByLimitAndTime(limit int, latestTime time.Time, videoList *[]*Video) error { 78 | if videoList == nil { 79 | return errors.New("QueryVideoListByLimit videoList 空指针") 80 | } 81 | return DB.Model(&Video{}).Where("created_at0", videoId).Error; err != nil { 105 | return err 106 | } 107 | if err := tx.Exec("DELETE FROM `user_favor_videos` WHERE `user_info_id` = ? AND `video_id` = ?", userId, videoId).Error; err != nil { 108 | return err 109 | } 110 | return nil 111 | }) 112 | } 113 | 114 | func (v *VideoDAO) QueryFavorVideoListByUserId(userId int64, videoList *[]*Video) error { 115 | if videoList == nil { 116 | return errors.New("QueryFavorVideoListByUserId videoList 空指针") 117 | } 118 | //多表查询,左连接得到结果,再映射到数据 119 | if err := DB.Raw("SELECT v.* FROM user_favor_videos u , videos v WHERE u.user_info_id = ? AND u.video_id = v.id", userId).Scan(videoList).Error; err != nil { 120 | return err 121 | } 122 | //如果id为0,则说明没有查到数据 123 | if len(*videoList) == 0 || (*videoList)[0].Id == 0 { 124 | return errors.New("点赞列表为空") 125 | } 126 | return nil 127 | } 128 | 129 | func (v *VideoDAO) IsVideoExistById(id int64) bool { 130 | var video Video 131 | if err := DB.Where("id=?", id).Select("id").First(&video).Error; err != nil { 132 | log.Println(err) 133 | } 134 | if video.Id == 0 { 135 | return false 136 | } 137 | return true 138 | } 139 | -------------------------------------------------------------------------------- /deprecated/models/video_test.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestVideoDAO_QueryVideoListByUserId(t *testing.T) { 10 | InitDB() 11 | s := make([]*Video, 8) 12 | err := NewVideoDAO().QueryVideoListByUserId(1, &s) 13 | if err != nil { 14 | panic(err) 15 | } 16 | for _, v := range s { 17 | fmt.Printf("%#v\n", *v) 18 | } 19 | } 20 | 21 | func TestVideoDAO_QueryVideoListByLimit(t *testing.T) { 22 | InitDB() 23 | s := make([]*Video, 8) 24 | err := NewVideoDAO().QueryVideoListByLimitAndTime(2, time.Unix(1652895580, 0), &s) 25 | if err != nil { 26 | panic(err) 27 | } 28 | for _, v := range s { 29 | fmt.Printf("%#v\n", *v) 30 | } 31 | } 32 | 33 | func TestTime(t *testing.T) { 34 | println(time.Now().UnixNano()) 35 | } 36 | -------------------------------------------------------------------------------- /deprecated/router/router_douyin.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/ACking-you/byte_douyin_project/config" 5 | comment2 "github.com/ACking-you/byte_douyin_project/handlers/comment" 6 | user_info2 "github.com/ACking-you/byte_douyin_project/handlers/user_info" 7 | user_login2 "github.com/ACking-you/byte_douyin_project/handlers/user_login" 8 | video2 "github.com/ACking-you/byte_douyin_project/handlers/video" 9 | middleware2 "github.com/ACking-you/byte_douyin_project/middleware" 10 | "github.com/ACking-you/byte_douyin_project/models" 11 | "github.com/gin-gonic/gin" 12 | ) 13 | 14 | func Init() *gin.Engine { 15 | models.InitDB() 16 | r := gin.Default() 17 | 18 | r.Static("static", config.Global.StaticSourcePath) 19 | 20 | baseGroup := r.Group("/douyin") 21 | //根据灵活性考虑是否加入JWT中间件来进行鉴权,还是在之后再做鉴权 22 | // basic apis 23 | baseGroup.GET("/feed/", video2.FeedVideoListHandler) 24 | baseGroup.GET("/user/", middleware2.JWTMiddleWare(), user_info2.UserInfoHandler) 25 | baseGroup.POST("/user/login/", middleware2.SHAMiddleWare(), user_login2.UserLoginHandler) 26 | baseGroup.POST("/user/register/", middleware2.SHAMiddleWare(), user_login2.UserRegisterHandler) 27 | baseGroup.POST("/publish/action/", middleware2.JWTMiddleWare(), video2.PublishVideoHandler) 28 | baseGroup.GET("/publish/list/", middleware2.NoAuthToGetUserId(), video2.QueryVideoListHandler) 29 | 30 | //extend 1 31 | baseGroup.POST("/favorite/action/", middleware2.JWTMiddleWare(), video2.PostFavorHandler) 32 | baseGroup.GET("/favorite/list/", middleware2.NoAuthToGetUserId(), video2.QueryFavorVideoListHandler) 33 | baseGroup.POST("/comment/action/", middleware2.JWTMiddleWare(), comment2.PostCommentHandler) 34 | baseGroup.GET("/comment/list/", middleware2.JWTMiddleWare(), comment2.QueryCommentListHandler) 35 | 36 | //extend 2 37 | baseGroup.POST("/relation/action/", middleware2.JWTMiddleWare(), user_info2.PostFollowActionHandler) 38 | baseGroup.GET("/relation/follow/list/", middleware2.NoAuthToGetUserId(), user_info2.QueryFollowListHandler) 39 | baseGroup.GET("/relation/follower/list/", middleware2.NoAuthToGetUserId(), user_info2.QueryFollowerHandler) 40 | return r 41 | } 42 | -------------------------------------------------------------------------------- /deprecated/service/comment/post_comment.go: -------------------------------------------------------------------------------- 1 | package comment 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | models2 "github.com/ACking-you/byte_douyin_project/models" 7 | "github.com/ACking-you/byte_douyin_project/util" 8 | ) 9 | 10 | const ( 11 | CREATE = 1 12 | DELETE = 2 13 | ) 14 | 15 | type Response struct { 16 | MyComment *models2.Comment `json:"comment"` 17 | } 18 | 19 | func PostComment(userId int64, videoId int64, commentId int64, actionType int64, commentText string) (*Response, error) { 20 | return NewPostCommentFlow(userId, videoId, commentId, actionType, commentText).Do() 21 | } 22 | 23 | type PostCommentFlow struct { 24 | userId int64 25 | videoId int64 26 | commentId int64 27 | actionType int64 28 | commentText string 29 | 30 | comment *models2.Comment 31 | 32 | *Response 33 | } 34 | 35 | func NewPostCommentFlow(userId int64, videoId int64, commentId int64, actionType int64, commentText string) *PostCommentFlow { 36 | return &PostCommentFlow{userId: userId, videoId: videoId, commentId: commentId, actionType: actionType, commentText: commentText} 37 | } 38 | 39 | func (p *PostCommentFlow) Do() (*Response, error) { 40 | var err error 41 | if err = p.checkNum(); err != nil { 42 | return nil, err 43 | } 44 | if err = p.prepareData(); err != nil { 45 | return nil, err 46 | } 47 | if err = p.packData(); err != nil { 48 | return nil, err 49 | } 50 | return p.Response, err 51 | } 52 | 53 | // CreateComment 增加评论 54 | func (p *PostCommentFlow) CreateComment() (*models2.Comment, error) { 55 | comment := models2.Comment{UserInfoId: p.userId, VideoId: p.videoId, Content: p.commentText} 56 | err := models2.NewCommentDAO().AddCommentAndUpdateCount(&comment) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | return &comment, nil 62 | } 63 | 64 | // DeleteComment 删除评论 65 | func (p *PostCommentFlow) DeleteComment() (*models2.Comment, error) { 66 | //获取comment 67 | var comment models2.Comment 68 | err := models2.NewCommentDAO().QueryCommentById(p.commentId, &comment) 69 | if err != nil { 70 | return nil, err 71 | } 72 | //删除comment 73 | err = models2.NewCommentDAO().DeleteCommentAndUpdateCountById(p.commentId, p.videoId) 74 | if err != nil { 75 | return nil, err 76 | } 77 | return &comment, nil 78 | } 79 | 80 | func (p *PostCommentFlow) checkNum() error { 81 | if !models2.NewUserInfoDAO().IsUserExistById(p.userId) { 82 | return fmt.Errorf("用户%d不存在", p.userId) 83 | } 84 | if !models2.NewVideoDAO().IsVideoExistById(p.videoId) { 85 | return fmt.Errorf("视频%d不存在", p.videoId) 86 | } 87 | if p.actionType != CREATE && p.actionType != DELETE { 88 | return errors.New("未定义的行为") 89 | } 90 | return nil 91 | } 92 | 93 | func (p *PostCommentFlow) prepareData() error { 94 | var err error 95 | switch p.actionType { 96 | case CREATE: 97 | p.comment, err = p.CreateComment() 98 | case DELETE: 99 | p.comment, err = p.DeleteComment() 100 | default: 101 | return errors.New("未定义的操作") 102 | } 103 | return err 104 | } 105 | 106 | func (p *PostCommentFlow) packData() error { 107 | //填充字段 108 | userInfo := models2.UserInfo{} 109 | _ = models2.NewUserInfoDAO().QueryUserInfoById(p.comment.UserInfoId, &userInfo) 110 | p.comment.User = userInfo 111 | _ = util.FillCommentFields(p.comment) 112 | 113 | p.Response = &Response{MyComment: p.comment} 114 | 115 | return nil 116 | } 117 | -------------------------------------------------------------------------------- /deprecated/service/comment/query_comment_list.go: -------------------------------------------------------------------------------- 1 | package comment 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | models2 "github.com/ACking-you/byte_douyin_project/models" 7 | "github.com/ACking-you/byte_douyin_project/util" 8 | ) 9 | 10 | type List struct { 11 | Comments []*models2.Comment `json:"comment_list"` 12 | } 13 | 14 | func QueryCommentList(userId, videoId int64) (*List, error) { 15 | return NewQueryCommentListFlow(userId, videoId).Do() 16 | } 17 | 18 | type QueryCommentListFlow struct { 19 | userId int64 20 | videoId int64 21 | 22 | comments []*models2.Comment 23 | 24 | commentList *List 25 | } 26 | 27 | func NewQueryCommentListFlow(userId, videoId int64) *QueryCommentListFlow { 28 | return &QueryCommentListFlow{userId: userId, videoId: videoId} 29 | } 30 | 31 | func (q *QueryCommentListFlow) Do() (*List, error) { 32 | if err := q.checkNum(); err != nil { 33 | return nil, err 34 | } 35 | if err := q.prepareData(); err != nil { 36 | return nil, err 37 | } 38 | if err := q.packData(); err != nil { 39 | return nil, err 40 | } 41 | return q.commentList, nil 42 | } 43 | 44 | func (q *QueryCommentListFlow) checkNum() error { 45 | if !models2.NewUserInfoDAO().IsUserExistById(q.userId) { 46 | return fmt.Errorf("用户%d处于登出状态", q.userId) 47 | } 48 | if !models2.NewVideoDAO().IsVideoExistById(q.videoId) { 49 | return fmt.Errorf("视频%d不存在或已经被删除", q.videoId) 50 | } 51 | return nil 52 | } 53 | 54 | func (q *QueryCommentListFlow) prepareData() error { 55 | err := models2.NewCommentDAO().QueryCommentListByVideoId(q.videoId, &q.comments) 56 | if err != nil { 57 | return err 58 | } 59 | //根据前端的要求填充正确的时间格式 60 | err = util.FillCommentListFields(&q.comments) 61 | if err != nil { 62 | return errors.New("暂时还没有人评论") 63 | } 64 | return nil 65 | } 66 | 67 | func (q *QueryCommentListFlow) packData() error { 68 | q.commentList = &List{Comments: q.comments} 69 | return nil 70 | } 71 | -------------------------------------------------------------------------------- /deprecated/service/user_info/post_follow_action.go: -------------------------------------------------------------------------------- 1 | package user_info 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/cache" 6 | "github.com/ACking-you/byte_douyin_project/models" 7 | ) 8 | 9 | const ( 10 | FOLLOW = 1 11 | CANCEL = 2 12 | ) 13 | 14 | var ( 15 | ErrIvdAct = errors.New("未定义操作") 16 | ErrIvdFolUsr = errors.New("关注用户不存在") 17 | ) 18 | 19 | func PostFollowAction(userId, userToId int64, actionType int) error { 20 | return NewPostFollowActionFlow(userId, userToId, actionType).Do() 21 | } 22 | 23 | type PostFollowActionFlow struct { 24 | userId int64 25 | userToId int64 26 | actionType int 27 | } 28 | 29 | func NewPostFollowActionFlow(userId int64, userToId int64, actionType int) *PostFollowActionFlow { 30 | return &PostFollowActionFlow{userId: userId, userToId: userToId, actionType: actionType} 31 | } 32 | 33 | func (p *PostFollowActionFlow) Do() error { 34 | var err error 35 | if err = p.checkNum(); err != nil { 36 | return err 37 | } 38 | if err = p.publish(); err != nil { 39 | return err 40 | } 41 | return nil 42 | } 43 | 44 | func (p *PostFollowActionFlow) checkNum() error { 45 | //由于userId是经过乐token鉴权故不需要check,只需要检查userToId 46 | if !models.NewUserInfoDAO().IsUserExistById(p.userToId) { 47 | return ErrIvdFolUsr 48 | } 49 | if p.actionType != FOLLOW && p.actionType != CANCEL { 50 | return ErrIvdAct 51 | } 52 | //自己不能关注自己 53 | if p.userId == p.userToId { 54 | return ErrIvdAct 55 | } 56 | return nil 57 | } 58 | 59 | func (p *PostFollowActionFlow) publish() error { 60 | userDAO := models.NewUserInfoDAO() 61 | var err error 62 | switch p.actionType { 63 | case FOLLOW: 64 | err = userDAO.AddUserFollow(p.userId, p.userToId) 65 | //更新redis的关注信息 66 | cache.NewProxyIndexMap().UpdateUserRelation(p.userId, p.userToId, true) 67 | case CANCEL: 68 | err = userDAO.CancelUserFollow(p.userId, p.userToId) 69 | cache.NewProxyIndexMap().UpdateUserRelation(p.userId, p.userToId, false) 70 | default: 71 | return ErrIvdAct 72 | } 73 | return err 74 | } 75 | -------------------------------------------------------------------------------- /deprecated/service/user_info/query_follow_list.go: -------------------------------------------------------------------------------- 1 | package user_info 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/models" 6 | ) 7 | 8 | var ( 9 | ErrUserNotExist = errors.New("用户不存在或已注销") 10 | ) 11 | 12 | type FollowList struct { 13 | UserList []*models.UserInfo `json:"user_list"` 14 | } 15 | 16 | func QueryFollowList(userId int64) (*FollowList, error) { 17 | return NewQueryFollowListFlow(userId).Do() 18 | } 19 | 20 | type QueryFollowListFlow struct { 21 | userId int64 22 | 23 | userList []*models.UserInfo 24 | 25 | *FollowList 26 | } 27 | 28 | func NewQueryFollowListFlow(userId int64) *QueryFollowListFlow { 29 | return &QueryFollowListFlow{userId: userId} 30 | } 31 | 32 | func (q *QueryFollowListFlow) Do() (*FollowList, error) { 33 | var err error 34 | if err = q.checkNum(); err != nil { 35 | return nil, err 36 | } 37 | if err = q.prepareData(); err != nil { 38 | return nil, err 39 | } 40 | if err = q.packData(); err != nil { 41 | return nil, err 42 | } 43 | 44 | return q.FollowList, nil 45 | } 46 | 47 | func (q *QueryFollowListFlow) checkNum() error { 48 | if !models.NewUserInfoDAO().IsUserExistById(q.userId) { 49 | return ErrUserNotExist 50 | } 51 | return nil 52 | } 53 | 54 | func (q *QueryFollowListFlow) prepareData() error { 55 | var userList []*models.UserInfo 56 | err := models.NewUserInfoDAO().GetFollowListByUserId(q.userId, &userList) 57 | if err != nil { 58 | return err 59 | } 60 | for i, _ := range userList { 61 | userList[i].IsFollow = true //当前用户的关注列表,故isFollow定为true 62 | } 63 | q.userList = userList 64 | return nil 65 | } 66 | 67 | func (q *QueryFollowListFlow) packData() error { 68 | q.FollowList = &FollowList{UserList: q.userList} 69 | 70 | return nil 71 | } 72 | -------------------------------------------------------------------------------- /deprecated/service/user_info/query_follower_list.go: -------------------------------------------------------------------------------- 1 | package user_info 2 | 3 | import ( 4 | "github.com/ACking-you/byte_douyin_project/cache" 5 | "github.com/ACking-you/byte_douyin_project/models" 6 | ) 7 | 8 | type FollowerList struct { 9 | UserList []*models.UserInfo `json:"user_list"` 10 | } 11 | 12 | func QueryFollowerList(userId int64) (*FollowerList, error) { 13 | return NewQueryFollowerListFlow(userId).Do() 14 | } 15 | 16 | type QueryFollowerListFlow struct { 17 | userId int64 18 | 19 | userList []*models.UserInfo 20 | 21 | *FollowerList 22 | } 23 | 24 | func NewQueryFollowerListFlow(userId int64) *QueryFollowerListFlow { 25 | return &QueryFollowerListFlow{userId: userId} 26 | } 27 | 28 | func (q *QueryFollowerListFlow) Do() (*FollowerList, error) { 29 | var err error 30 | if err = q.checkNum(); err != nil { 31 | return nil, err 32 | } 33 | if err = q.prepareData(); err != nil { 34 | return nil, err 35 | } 36 | if err = q.packData(); err != nil { 37 | return nil, err 38 | } 39 | return q.FollowerList, nil 40 | } 41 | 42 | func (q *QueryFollowerListFlow) checkNum() error { 43 | if !models.NewUserInfoDAO().IsUserExistById(q.userId) { 44 | return ErrUserNotExist 45 | } 46 | return nil 47 | } 48 | 49 | func (q *QueryFollowerListFlow) prepareData() error { 50 | 51 | err := models.NewUserInfoDAO().GetFollowerListByUserId(q.userId, &q.userList) 52 | if err != nil { 53 | return err 54 | } 55 | //填充is_follow字段 56 | for _, v := range q.userList { 57 | v.IsFollow = cache.NewProxyIndexMap().GetUserRelation(q.userId, v.Id) 58 | } 59 | return nil 60 | } 61 | 62 | func (q *QueryFollowerListFlow) packData() error { 63 | q.FollowerList = &FollowerList{UserList: q.userList} 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /deprecated/service/user_login/post_user_login.go: -------------------------------------------------------------------------------- 1 | package user_login 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/middleware" 6 | models2 "github.com/ACking-you/byte_douyin_project/models" 7 | ) 8 | 9 | // PostUserLogin 注册用户并得到token和id 10 | func PostUserLogin(username, password string) (*LoginResponse, error) { 11 | return NewPostUserLoginFlow(username, password).Do() 12 | } 13 | 14 | func NewPostUserLoginFlow(username, password string) *PostUserLoginFlow { 15 | return &PostUserLoginFlow{username: username, password: password} 16 | } 17 | 18 | type PostUserLoginFlow struct { 19 | username string 20 | password string 21 | 22 | data *LoginResponse 23 | userid int64 24 | token string 25 | } 26 | 27 | func (q *PostUserLoginFlow) Do() (*LoginResponse, error) { 28 | //对参数进行合法性验证 29 | if err := q.checkNum(); err != nil { 30 | return nil, err 31 | } 32 | 33 | //更新数据到数据库 34 | if err := q.updateData(); err != nil { 35 | return nil, err 36 | } 37 | 38 | //打包response 39 | if err := q.packResponse(); err != nil { 40 | return nil, err 41 | } 42 | return q.data, nil 43 | } 44 | 45 | func (q *PostUserLoginFlow) checkNum() error { 46 | if q.username == "" { 47 | return errors.New("用户名为空") 48 | } 49 | if len(q.username) > MaxUsernameLength { 50 | return errors.New("用户名长度超出限制") 51 | } 52 | if q.password == "" { 53 | return errors.New("密码为空") 54 | } 55 | return nil 56 | } 57 | 58 | func (q *PostUserLoginFlow) updateData() error { 59 | 60 | //准备好userInfo,默认name为username 61 | userLogin := models2.UserLogin{Username: q.username, Password: q.password} 62 | userinfo := models2.UserInfo{User: &userLogin, Name: q.username} 63 | 64 | //判断用户名是否已经存在 65 | userLoginDAO := models2.NewUserLoginDao() 66 | if userLoginDAO.IsUserExistByUsername(q.username) { 67 | return errors.New("用户名已存在") 68 | } 69 | 70 | //更新操作,由于userLogin属于userInfo,故更新userInfo即可,且由于传入的是指针,所以插入的数据内容也是清楚的 71 | userInfoDAO := models2.NewUserInfoDAO() 72 | err := userInfoDAO.AddUserInfo(&userinfo) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | //颁发token 78 | token, err := middleware.ReleaseToken(userLogin) 79 | if err != nil { 80 | return err 81 | } 82 | q.token = token 83 | q.userid = userinfo.Id 84 | return nil 85 | } 86 | 87 | func (q *PostUserLoginFlow) packResponse() error { 88 | q.data = &LoginResponse{ 89 | UserId: q.userid, 90 | Token: q.token, 91 | } 92 | return nil 93 | } 94 | -------------------------------------------------------------------------------- /deprecated/service/user_login/query_user_login.go: -------------------------------------------------------------------------------- 1 | package user_login 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/middleware" 6 | "github.com/ACking-you/byte_douyin_project/models" 7 | ) 8 | 9 | const ( 10 | MaxUsernameLength = 100 11 | MaxPasswordLength = 20 12 | MinPasswordLength = 8 13 | ) 14 | 15 | type LoginResponse struct { 16 | UserId int64 `json:"user_id"` 17 | Token string `json:"token"` 18 | } 19 | 20 | // QueryUserLogin 查询用户是否存在,并返回token和id 21 | func QueryUserLogin(username, password string) (*LoginResponse, error) { 22 | return NewQueryUserLoginFlow(username, password).Do() 23 | } 24 | 25 | func NewQueryUserLoginFlow(username, password string) *QueryUserLoginFlow { 26 | return &QueryUserLoginFlow{username: username, password: password} 27 | } 28 | 29 | type QueryUserLoginFlow struct { 30 | username string 31 | password string 32 | 33 | data *LoginResponse 34 | userid int64 35 | token string 36 | } 37 | 38 | func (q *QueryUserLoginFlow) Do() (*LoginResponse, error) { 39 | //对参数进行合法性验证 40 | if err := q.checkNum(); err != nil { 41 | return nil, err 42 | } 43 | //准备好数据 44 | if err := q.prepareData(); err != nil { 45 | return nil, err 46 | } 47 | //打包最终数据 48 | if err := q.packData(); err != nil { 49 | return nil, err 50 | } 51 | return q.data, nil 52 | } 53 | 54 | func (q *QueryUserLoginFlow) checkNum() error { 55 | if q.username == "" { 56 | return errors.New("用户名为空") 57 | } 58 | if len(q.username) > MaxUsernameLength { 59 | return errors.New("用户名长度超出限制") 60 | } 61 | if q.password == "" { 62 | return errors.New("密码为空") 63 | } 64 | return nil 65 | } 66 | 67 | func (q *QueryUserLoginFlow) prepareData() error { 68 | userLoginDAO := models.NewUserLoginDao() 69 | var login models.UserLogin 70 | //准备好userid 71 | err := userLoginDAO.QueryUserLogin(q.username, q.password, &login) 72 | if err != nil { 73 | return err 74 | } 75 | q.userid = login.UserInfoId 76 | 77 | //准备颁发token 78 | token, err := middleware.ReleaseToken(login) 79 | if err != nil { 80 | return err 81 | } 82 | q.token = token 83 | return nil 84 | } 85 | 86 | func (q *QueryUserLoginFlow) packData() error { 87 | q.data = &LoginResponse{ 88 | UserId: q.userid, 89 | Token: q.token, 90 | } 91 | return nil 92 | } 93 | -------------------------------------------------------------------------------- /deprecated/service/video/feed_videolist.go: -------------------------------------------------------------------------------- 1 | package video 2 | 3 | import ( 4 | "github.com/ACking-you/byte_douyin_project/models" 5 | "github.com/ACking-you/byte_douyin_project/util" 6 | "time" 7 | ) 8 | 9 | // MaxVideoNum 每次最多返回的视频流数量 10 | const ( 11 | MaxVideoNum = 30 12 | ) 13 | 14 | type FeedVideoList struct { 15 | Videos []*models.Video `json:"video_list,omitempty"` 16 | NextTime int64 `json:"next_time,omitempty"` 17 | } 18 | 19 | func QueryFeedVideoList(userId int64, latestTime time.Time) (*FeedVideoList, error) { 20 | return NewQueryFeedVideoListFlow(userId, latestTime).Do() 21 | } 22 | 23 | type QueryFeedVideoListFlow struct { 24 | userId int64 25 | latestTime time.Time 26 | 27 | videos []*models.Video 28 | nextTime int64 29 | 30 | feedVideo *FeedVideoList 31 | } 32 | 33 | func NewQueryFeedVideoListFlow(userId int64, latestTime time.Time) *QueryFeedVideoListFlow { 34 | return &QueryFeedVideoListFlow{userId: userId, latestTime: latestTime} 35 | } 36 | 37 | func (q *QueryFeedVideoListFlow) Do() (*FeedVideoList, error) { 38 | //所有传入的参数不填也应该给他正常处理 39 | q.checkNum() 40 | 41 | if err := q.prepareData(); err != nil { 42 | return nil, err 43 | } 44 | if err := q.packData(); err != nil { 45 | return nil, err 46 | } 47 | return q.feedVideo, nil 48 | } 49 | 50 | func (q *QueryFeedVideoListFlow) checkNum() { 51 | //上层通过把userId置零,表示userId不存在或不需要 52 | if q.userId > 0 { 53 | //这里说明userId是有效的,可以定制性的做一些登录用户的专属视频推荐 54 | } 55 | 56 | if q.latestTime.IsZero() { 57 | q.latestTime = time.Now() 58 | } 59 | } 60 | 61 | func (q *QueryFeedVideoListFlow) prepareData() error { 62 | err := models.NewVideoDAO().QueryVideoListByLimitAndTime(MaxVideoNum, q.latestTime, &q.videos) 63 | if err != nil { 64 | return err 65 | } 66 | //如果用户为登录状态,则更新该视频是否被该用户点赞的状态 67 | latestTime, _ := util.FillVideoListFields(q.userId, &q.videos) //不是致命错误,不返回 68 | 69 | //准备好时间戳 70 | if latestTime != nil { 71 | q.nextTime = (*latestTime).UnixNano() / 1e6 72 | return nil 73 | } 74 | q.nextTime = time.Now().Unix() / 1e6 75 | return nil 76 | } 77 | 78 | func (q *QueryFeedVideoListFlow) packData() error { 79 | q.feedVideo = &FeedVideoList{ 80 | Videos: q.videos, 81 | NextTime: q.nextTime, 82 | } 83 | return nil 84 | } 85 | -------------------------------------------------------------------------------- /deprecated/service/video/post_favor_state.go: -------------------------------------------------------------------------------- 1 | package video 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/cache" 6 | models2 "github.com/ACking-you/byte_douyin_project/models" 7 | ) 8 | 9 | const ( 10 | PLUS = 1 11 | MINUS = 2 12 | ) 13 | 14 | func PostFavorState(userId, videoId, actionType int64) error { 15 | return NewPostFavorStateFlow(userId, videoId, actionType).Do() 16 | } 17 | 18 | type PostFavorStateFlow struct { 19 | userId int64 20 | videoId int64 21 | actionType int64 22 | } 23 | 24 | func NewPostFavorStateFlow(userId, videoId, action int64) *PostFavorStateFlow { 25 | return &PostFavorStateFlow{ 26 | userId: userId, 27 | videoId: videoId, 28 | actionType: action, 29 | } 30 | } 31 | 32 | func (p *PostFavorStateFlow) Do() error { 33 | var err error 34 | if err = p.checkNum(); err != nil { 35 | return err 36 | } 37 | 38 | switch p.actionType { 39 | case PLUS: 40 | err = p.PlusOperation() 41 | case MINUS: 42 | err = p.MinusOperation() 43 | default: 44 | return errors.New("未定义的操作") 45 | } 46 | return err 47 | } 48 | 49 | // PlusOperation 点赞操作 50 | func (p *PostFavorStateFlow) PlusOperation() error { 51 | //视频点赞数目+1 52 | err := models2.NewVideoDAO().PlusOneFavorByUserIdAndVideoId(p.userId, p.videoId) 53 | if err != nil { 54 | return errors.New("不要重复点赞") 55 | } 56 | //对应的用户是否点赞的映射状态更新 57 | cache.NewProxyIndexMap().UpdateVideoFavorState(p.userId, p.videoId, true) 58 | return nil 59 | } 60 | 61 | // MinusOperation 取消点赞 62 | func (p *PostFavorStateFlow) MinusOperation() error { 63 | //视频点赞数目-1 64 | err := models2.NewVideoDAO().MinusOneFavorByUserIdAndVideoId(p.userId, p.videoId) 65 | if err != nil { 66 | return errors.New("点赞数目已经为0") 67 | } 68 | //对应的用户是否点赞的映射状态更新 69 | cache.NewProxyIndexMap().UpdateVideoFavorState(p.userId, p.videoId, false) 70 | return nil 71 | } 72 | 73 | func (p *PostFavorStateFlow) checkNum() error { 74 | if !models2.NewUserInfoDAO().IsUserExistById(p.userId) { 75 | return errors.New("用户不存在") 76 | } 77 | if p.actionType != PLUS && p.actionType != MINUS { 78 | return errors.New("未定义的行为") 79 | } 80 | return nil 81 | } 82 | -------------------------------------------------------------------------------- /deprecated/service/video/post_video.go: -------------------------------------------------------------------------------- 1 | package video 2 | 3 | import ( 4 | "github.com/ACking-you/byte_douyin_project/models" 5 | "github.com/ACking-you/byte_douyin_project/util" 6 | ) 7 | 8 | // PostVideo 投稿视频 9 | func PostVideo(userId int64, videoName, coverName, title string) error { 10 | return NewPostVideoFlow(userId, videoName, coverName, title).Do() 11 | } 12 | 13 | func NewPostVideoFlow(userId int64, videoName, coverName, title string) *PostVideoFlow { 14 | return &PostVideoFlow{ 15 | videoName: videoName, 16 | coverName: coverName, 17 | userId: userId, 18 | title: title, 19 | } 20 | } 21 | 22 | type PostVideoFlow struct { 23 | videoName string 24 | coverName string 25 | title string 26 | userId int64 27 | 28 | video *models.Video 29 | } 30 | 31 | func (f *PostVideoFlow) Do() error { 32 | f.prepareParam() 33 | 34 | if err := f.publish(); err != nil { 35 | return err 36 | } 37 | return nil 38 | } 39 | 40 | //准备好参数 41 | func (f *PostVideoFlow) prepareParam() { 42 | f.videoName = util.GetFileUrl(f.videoName) 43 | f.coverName = util.GetFileUrl(f.coverName) 44 | } 45 | 46 | //组合并添加到数据库 47 | func (f *PostVideoFlow) publish() error { 48 | video := &models.Video{ 49 | UserInfoId: f.userId, 50 | PlayUrl: f.videoName, 51 | CoverUrl: f.coverName, 52 | Title: f.title, 53 | } 54 | return models.NewVideoDAO().AddVideo(video) 55 | } 56 | -------------------------------------------------------------------------------- /deprecated/service/video/query_favor_videolist.go: -------------------------------------------------------------------------------- 1 | package video 2 | 3 | import ( 4 | "errors" 5 | models2 "github.com/ACking-you/byte_douyin_project/models" 6 | ) 7 | 8 | type FavorList struct { 9 | Videos []*models2.Video `json:"video_list"` 10 | } 11 | 12 | func QueryFavorVideoList(userId int64) (*FavorList, error) { 13 | return NewQueryFavorVideoListFlow(userId).Do() 14 | } 15 | 16 | type QueryFavorVideoListFlow struct { 17 | userId int64 18 | 19 | videos []*models2.Video 20 | 21 | videoList *FavorList 22 | } 23 | 24 | func NewQueryFavorVideoListFlow(userId int64) *QueryFavorVideoListFlow { 25 | return &QueryFavorVideoListFlow{userId: userId} 26 | } 27 | 28 | func (q *QueryFavorVideoListFlow) Do() (*FavorList, error) { 29 | if err := q.checkNum(); err != nil { 30 | return nil, err 31 | } 32 | if err := q.prepareData(); err != nil { 33 | return nil, err 34 | } 35 | if err := q.packData(); err != nil { 36 | return nil, err 37 | } 38 | return q.videoList, nil 39 | } 40 | 41 | func (q *QueryFavorVideoListFlow) checkNum() error { 42 | if !models2.NewUserInfoDAO().IsUserExistById(q.userId) { 43 | return errors.New("用户状态异常") 44 | } 45 | return nil 46 | } 47 | 48 | func (q *QueryFavorVideoListFlow) prepareData() error { 49 | err := models2.NewVideoDAO().QueryFavorVideoListByUserId(q.userId, &q.videos) 50 | if err != nil { 51 | return err 52 | } 53 | //填充信息(Author和IsFavorite字段,由于是点赞列表,故所有的都是点赞状态 54 | for i := range q.videos { 55 | //作者信息查询 56 | var userInfo models2.UserInfo 57 | err = models2.NewUserInfoDAO().QueryUserInfoById(q.videos[i].UserInfoId, &userInfo) 58 | if err == nil { //若查询未出错则更新,否则不更新作者信息 59 | q.videos[i].Author = userInfo 60 | } 61 | q.videos[i].IsFavorite = true 62 | } 63 | return nil 64 | } 65 | 66 | func (q *QueryFavorVideoListFlow) packData() error { 67 | q.videoList = &FavorList{Videos: q.videos} 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /deprecated/service/video/query_videolist.go: -------------------------------------------------------------------------------- 1 | package video 2 | 3 | import ( 4 | "errors" 5 | "github.com/ACking-you/byte_douyin_project/cache" 6 | models2 "github.com/ACking-you/byte_douyin_project/models" 7 | ) 8 | 9 | type List struct { 10 | Videos []*models2.Video `json:"video_list,omitempty"` 11 | } 12 | 13 | func QueryVideoListByUserId(userId int64) (*List, error) { 14 | return NewQueryVideoListByUserIdFlow(userId).Do() 15 | } 16 | 17 | func NewQueryVideoListByUserIdFlow(userId int64) *QueryVideoListByUserIdFlow { 18 | return &QueryVideoListByUserIdFlow{userId: userId} 19 | } 20 | 21 | type QueryVideoListByUserIdFlow struct { 22 | userId int64 23 | videos []*models2.Video 24 | 25 | videoList *List 26 | } 27 | 28 | func (q *QueryVideoListByUserIdFlow) Do() (*List, error) { 29 | if err := q.checkNum(); err != nil { 30 | return nil, err 31 | } 32 | if err := q.packData(); err != nil { 33 | return nil, err 34 | } 35 | return q.videoList, nil 36 | } 37 | 38 | func (q *QueryVideoListByUserIdFlow) checkNum() error { 39 | //检查userId是否存在 40 | if !models2.NewUserInfoDAO().IsUserExistById(q.userId) { 41 | return errors.New("用户不存在") 42 | } 43 | 44 | return nil 45 | } 46 | 47 | //注意:Video由于在数据库中没有存储作者信息,所以需要手动填充 48 | func (q *QueryVideoListByUserIdFlow) packData() error { 49 | err := models2.NewVideoDAO().QueryVideoListByUserId(q.userId, &q.videos) 50 | if err != nil { 51 | return err 52 | } 53 | //作者信息查询 54 | var userInfo models2.UserInfo 55 | err = models2.NewUserInfoDAO().QueryUserInfoById(q.userId, &userInfo) 56 | p := cache.NewProxyIndexMap() 57 | if err != nil { 58 | return err 59 | } 60 | //填充信息(Author和IsFavorite字段 61 | for i := range q.videos { 62 | q.videos[i].Author = userInfo 63 | q.videos[i].IsFavorite = p.GetVideoFavorState(q.userId, q.videos[i].Id) 64 | } 65 | 66 | q.videoList = &List{Videos: q.videos} 67 | 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /deprecated/util/comment.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "errors" 5 | models2 "github.com/ACking-you/byte_douyin_project/models" 6 | ) 7 | 8 | func FillCommentListFields(comments *[]*models2.Comment) error { 9 | size := len(*comments) 10 | if comments == nil || size == 0 { 11 | return errors.New("util.FillCommentListFields comments为空") 12 | } 13 | dao := models2.NewUserInfoDAO() 14 | for _, v := range *comments { 15 | _ = dao.QueryUserInfoById(v.UserInfoId, &v.User) //填充这条评论的作者信息 16 | v.CreateDate = v.CreatedAt.Format("1-2") //转为前端要求的日期格式 17 | } 18 | return nil 19 | } 20 | 21 | func FillCommentFields(comment *models2.Comment) error { 22 | if comment == nil { 23 | return errors.New("FillCommentFields comments为空") 24 | } 25 | comment.CreateDate = comment.CreatedAt.Format("1-2") //转为前端要求的日期格式 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /deprecated/util/ffmpeg.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os/exec" 7 | "path/filepath" 8 | "strconv" 9 | "sync" 10 | 11 | "github.com/ACking-you/byte_douyin_project/config" 12 | "log" 13 | ) 14 | 15 | // 可以更改 16 | var ( 17 | globalMutex sync.RWMutex 18 | defaultVideoSuffix = ".mp4" 19 | defaultImageSuffix = ".jpg" 20 | ) 21 | 22 | type Video2Image struct { 23 | inputPath string 24 | outputPath string 25 | startTime string 26 | keepTime string 27 | filter string 28 | frameCount int 29 | debug bool 30 | } 31 | 32 | func NewVideo2Image() *Video2Image { 33 | return &Video2Image{} // 每次返回新实例,避免共享状态 34 | } 35 | 36 | func GetDefaultVideoSuffix() string { 37 | globalMutex.RLock() 38 | defer globalMutex.RUnlock() 39 | return defaultVideoSuffix 40 | } 41 | 42 | func GetDefaultImageSuffix() string { 43 | globalMutex.RLock() 44 | defer globalMutex.RUnlock() 45 | return defaultImageSuffix 46 | } 47 | 48 | // ChangeVideoDefaultSuffix 全局配置修改方法(线程安全) 49 | func ChangeVideoDefaultSuffix(suffix string) { 50 | globalMutex.Lock() 51 | defer globalMutex.Unlock() 52 | defaultVideoSuffix = normalizeExtension(suffix) 53 | } 54 | 55 | func ChangeImageDefaultSuffix(suffix string) { 56 | globalMutex.Lock() 57 | defer globalMutex.Unlock() 58 | defaultImageSuffix = normalizeExtension(suffix) 59 | } 60 | 61 | func normalizeExtension(ext string) string { 62 | if ext == "" { 63 | return ext 64 | } 65 | if ext[0] != '.' { 66 | return "." + ext 67 | } 68 | return ext 69 | } 70 | 71 | // SetInputPath 方法链式调用(非共享实例,无需加锁) 72 | func (v *Video2Image) SetInputPath(path string) *Video2Image { 73 | v.inputPath = path 74 | return v 75 | } 76 | 77 | func (v *Video2Image) SetOutputPath(path string) *Video2Image { 78 | v.outputPath = path 79 | return v 80 | } 81 | 82 | func (v *Video2Image) SetTimeOptions(start, duration string) *Video2Image { 83 | v.startTime = start 84 | v.keepTime = duration 85 | return v 86 | } 87 | 88 | func (v *Video2Image) SetFilter(filter string) *Video2Image { 89 | v.filter = filter 90 | return v 91 | } 92 | 93 | func (v *Video2Image) SetFrameCount(count int) *Video2Image { 94 | v.frameCount = count 95 | return v 96 | } 97 | 98 | func (v *Video2Image) SetDebug(debug bool) *Video2Image { 99 | v.debug = debug 100 | return v 101 | } 102 | 103 | func (v *Video2Image) buildArgs() ([]string, error) { 104 | if v.inputPath == "" || v.outputPath == "" { 105 | return nil, errors.New("input and output path must be specified") 106 | } 107 | 108 | args := []string{ 109 | "-i", filepath.ToSlash(v.inputPath), 110 | "-f", "image2", 111 | } 112 | 113 | if v.filter != "" { 114 | args = append(args, "-vf", v.filter) 115 | } 116 | if v.startTime != "" { 117 | args = append(args, "-ss", v.startTime) 118 | } 119 | if v.keepTime != "" { 120 | args = append(args, "-t", v.keepTime) 121 | } 122 | if v.frameCount > 0 { 123 | args = append(args, "-frames:v", strconv.Itoa(v.frameCount)) 124 | } 125 | 126 | args = append(args, "-y", filepath.ToSlash(v.outputPath)) 127 | return args, nil 128 | } 129 | 130 | func (v *Video2Image) Execute() error { 131 | args, err := v.buildArgs() 132 | if err != nil { 133 | return fmt.Errorf("参数构建失败: %w", err) 134 | } 135 | 136 | ffmpegPath := filepath.FromSlash(config.Global.FfmpegPath) 137 | 138 | cmd := exec.Command(ffmpegPath, args...) 139 | if v.debug { 140 | log.Printf("执行命令: %q", cmd.String()) 141 | cmd.Stdout = log.Writer() 142 | cmd.Stderr = log.Writer() 143 | } 144 | 145 | if err := cmd.Run(); err != nil { 146 | return fmt.Errorf("ffmpeg执行失败: %w (命令: %q)", err, cmd.String()) 147 | } 148 | return nil 149 | } 150 | -------------------------------------------------------------------------------- /deprecated/util/video.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/ACking-you/byte_douyin_project/cache" 7 | "github.com/ACking-you/byte_douyin_project/config" 8 | models2 "github.com/ACking-you/byte_douyin_project/models" 9 | "log" 10 | "path/filepath" 11 | "time" 12 | ) 13 | 14 | func GetFileUrl(fileName string) string { 15 | base := fmt.Sprintf("http://%s:%d/static/%s", config.Global.IP, config.Global.Port, fileName) 16 | return base 17 | } 18 | 19 | // NewFileName 根据userId+用户发布的视频数量连接成独一无二的文件名 20 | func NewFileName(userId int64) string { 21 | var count int64 22 | 23 | err := models2.NewVideoDAO().QueryVideoCountByUserId(userId, &count) 24 | if err != nil { 25 | log.Println(err) 26 | } 27 | return fmt.Sprintf("%d-%d", userId, count) 28 | } 29 | 30 | // FillVideoListFields 填充每个视频的作者信息(因为作者与视频的一对多关系,数据库中存下的是作者的id 31 | // 当userId>0时,我们判断当前为登录状态,其余情况为未登录状态,则不需要填充IsFavorite字段 32 | func FillVideoListFields(userId int64, videos *[]*models2.Video) (*time.Time, error) { 33 | if videos == nil || (len(*videos) == 0) { 34 | return nil, errors.New("util.FillVideoListFields videos为空") 35 | } 36 | size := len(*videos) 37 | dao := models2.NewUserInfoDAO() 38 | p := cache.NewProxyIndexMap() 39 | 40 | latestTime := (*videos)[size-1].CreatedAt //获取最近的投稿时间 41 | //添加作者信息,以及is_follow状态 42 | for i := 0; i < size; i++ { 43 | var userInfo models2.UserInfo 44 | err := dao.QueryUserInfoById((*videos)[i].UserInfoId, &userInfo) 45 | if err != nil { 46 | continue 47 | } 48 | userInfo.IsFollow = p.GetUserRelation(userId, userInfo.Id) //根据cache更新是否被点赞 49 | (*videos)[i].Author = userInfo 50 | //填充有登录信息的点赞状态 51 | if userId > 0 { 52 | (*videos)[i].IsFavorite = p.GetVideoFavorState(userId, (*videos)[i].Id) 53 | } 54 | } 55 | return &latestTime, nil 56 | } 57 | 58 | // SaveImageFromVideo 将视频切一帧保存到本地 59 | // isDebug用于控制是否打印出执行的ffmepg命令 60 | func SaveImageFromVideo(name string, isDebug bool) error { 61 | return NewVideo2Image(). 62 | SetInputPath(filepath.Join(config.Global.StaticSourcePath, name+GetDefaultVideoSuffix())). 63 | SetOutputPath(filepath.Join(config.Global.StaticSourcePath, name+GetDefaultImageSuffix())). 64 | SetFrameCount(1). 65 | SetDebug(isDebug).Execute() 66 | } 67 | --------------------------------------------------------------------------------