package handlers import ( "strconv" "time" "github.com/gin-gonic/gin" "github.com/niangaodev/art-code/models" "github.com/niangaodev/art-code/repositories" "github.com/niangaodev/art-code/utils" ) // ========== 公开 API ========== // GetVideoCategories 获取视频分类列表 func GetVideoCategories(c *gin.Context) { list, err := repositories.GetVideoCategories() if err != nil { utils.ServerError(c, err) return } utils.Success(c, repositories.BuildVideoCategoriesResponse(list)) } // GetVideoAlbums 获取视频专辑列表 func GetVideoAlbums(c *gin.Context) { categoryID, _ := strconv.ParseUint(c.Query("categoryId"), 10, 32) list, err := repositories.GetActiveVideoAlbums(uint(categoryID)) if err != nil { utils.ServerError(c, err) return } utils.Success(c, repositories.BuildVideoAlbumsResponse(list, true)) } // GetVideoAlbumByID 获取专辑详情 func GetVideoAlbumByID(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { utils.Error(c, 400, "Invalid album ID") return } album, err := repositories.GetVideoAlbumByID(uint(id)) if err != nil { utils.ServerError(c, err) return } if album == nil || album.IsActive != 1 { utils.Error(c, 404, "Album not found") return } utils.Success(c, repositories.BuildVideoAlbumResponse(album, true)) } // GetAlbumVideos 获取专辑内视频 func GetAlbumVideos(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { utils.Error(c, 400, "Invalid album ID") return } list, err := repositories.GetVideosByAlbumID(uint(id), true) if err != nil { utils.ServerError(c, err) return } utils.Success(c, repositories.BuildVideosResponse(list)) } // GetVideos 获取视频列表 func GetVideos(c *gin.Context) { categoryID, _ := strconv.ParseUint(c.Query("categoryId"), 10, 32) list, err := repositories.GetVideos(uint(categoryID), true) if err != nil { utils.ServerError(c, err) return } utils.Success(c, repositories.BuildVideosResponse(list)) } // GetVideoByID 获取视频详情 func GetVideoByID(c *gin.Context) { id := c.Param("id") video, err := repositories.GetVideoByID(id) if err != nil { utils.ServerError(c, err) return } if video == nil || video.IsPublished != 1 { utils.Error(c, 404, "Video not found") return } utils.Success(c, repositories.BuildVideoDetailResponse(video)) } // ========== 管理 API — 分类 ========== func AdminGetVideoCategories(c *gin.Context) { list, err := repositories.GetVideoCategories() if err != nil { utils.ServerError(c, err) return } utils.Success(c, repositories.BuildVideoCategoriesResponse(list)) } func AdminCreateVideoCategory(c *gin.Context) { var item models.VideoCategory if err := c.ShouldBindJSON(&item); err != nil { utils.Error(c, 400, err.Error()) return } if err := repositories.CreateVideoCategory(&item); err != nil { utils.ServerError(c, err) return } utils.Success(c, repositories.BuildVideoCategoryResponse(&item)) } func AdminUpdateVideoCategory(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { utils.Error(c, 400, "Invalid category ID") return } var item models.VideoCategory if err := c.ShouldBindJSON(&item); err != nil { utils.Error(c, 400, err.Error()) return } item.ID = uint(id) if err := repositories.UpdateVideoCategory(&item); err != nil { utils.ServerError(c, err) return } utils.Success(c, repositories.BuildVideoCategoryResponse(&item)) } func AdminDeleteVideoCategory(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { utils.Error(c, 400, "Invalid category ID") return } if err := repositories.DeleteVideoCategory(uint(id)); err != nil { utils.ServerError(c, err) return } utils.SuccessWithMsg(c, "Category deleted", nil) } // ========== 管理 API — 专辑 ========== func AdminGetVideoAlbums(c *gin.Context) { categoryID, _ := strconv.ParseUint(c.Query("categoryId"), 10, 32) list, err := repositories.GetVideoAlbums(uint(categoryID)) if err != nil { utils.ServerError(c, err) return } utils.Success(c, repositories.BuildVideoAlbumsResponse(list, false)) } func AdminCreateVideoAlbum(c *gin.Context) { var item models.VideoAlbum if err := c.ShouldBindJSON(&item); err != nil { utils.Error(c, 400, err.Error()) return } if err := repositories.CreateVideoAlbum(&item); err != nil { utils.ServerError(c, err) return } utils.Success(c, repositories.BuildVideoAlbumResponse(&item, false)) } func AdminUpdateVideoAlbum(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { utils.Error(c, 400, "Invalid album ID") return } var req struct { models.VideoAlbum VideoIDs []string `json:"videoIds"` } if err := c.ShouldBindJSON(&req); err != nil { utils.Error(c, 400, err.Error()) return } req.VideoAlbum.ID = uint(id) if err := repositories.UpdateVideoAlbum(&req.VideoAlbum); err != nil { utils.ServerError(c, err) return } if req.VideoIDs != nil { if err := repositories.SyncAlbumVideos(uint(id), req.VideoIDs); err != nil { utils.ServerError(c, err) return } } utils.Success(c, repositories.BuildVideoAlbumResponse(&req.VideoAlbum, false)) } func AdminDeleteVideoAlbum(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { utils.Error(c, 400, "Invalid album ID") return } if err := repositories.DeleteVideoAlbum(uint(id)); err != nil { utils.ServerError(c, err) return } utils.SuccessWithMsg(c, "Album deleted", nil) } func AdminAddVideoToAlbum(c *gin.Context) { albumID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { utils.Error(c, 400, "Invalid album ID") return } var req struct { VideoID string `json:"videoId"` SortOrder uint `json:"sortOrder"` } if err := c.ShouldBindJSON(&req); err != nil { utils.Error(c, 400, err.Error()) return } if err := repositories.AddVideoToAlbum(uint(albumID), req.VideoID, req.SortOrder); err != nil { utils.ServerError(c, err) return } utils.SuccessWithMsg(c, "Video added to album", nil) } func AdminRemoveVideoFromAlbum(c *gin.Context) { albumID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { utils.Error(c, 400, "Invalid album ID") return } videoID := c.Param("videoId") if err := repositories.RemoveVideoFromAlbum(uint(albumID), videoID); err != nil { utils.ServerError(c, err) return } utils.SuccessWithMsg(c, "Video removed from album", nil) } func AdminGetAlbumVideoIDs(c *gin.Context) { albumID, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { utils.Error(c, 400, "Invalid album ID") return } videos, err := repositories.GetVideosByAlbumID(uint(albumID), false) if err != nil { utils.ServerError(c, err) return } ids := make([]string, 0, len(videos)) for _, v := range videos { ids = append(ids, v.ID) } utils.Success(c, ids) } // ========== 管理 API — 视频 ========== func AdminGetVideos(c *gin.Context) { categoryID, _ := strconv.ParseUint(c.Query("categoryId"), 10, 32) list, err := repositories.GetVideos(uint(categoryID), false) if err != nil { utils.ServerError(c, err) return } utils.Success(c, repositories.BuildAdminVideosResponse(list)) } func AdminCreateVideo(c *gin.Context) { var req struct { models.Video AlbumIDs []uint `json:"albumIds"` } if err := c.ShouldBindJSON(&req); err != nil { utils.Error(c, 400, err.Error()) return } if req.Video.ID == "" { req.Video.ID = "video_" + strconv.FormatInt(time.Now().UnixNano(), 10) } if err := repositories.CreateVideo(&req.Video); err != nil { utils.ServerError(c, err) return } if req.AlbumIDs != nil { if err := repositories.SyncVideoAlbums(req.Video.ID, req.AlbumIDs); err != nil { utils.ServerError(c, err) return } } utils.Success(c, repositories.BuildAdminVideoResponse(&req.Video)) } func AdminUpdateVideo(c *gin.Context) { id := c.Param("id") var req struct { models.Video AlbumIDs []uint `json:"albumIds"` } if err := c.ShouldBindJSON(&req); err != nil { utils.Error(c, 400, err.Error()) return } req.Video.ID = id if err := repositories.UpdateVideo(&req.Video); err != nil { utils.ServerError(c, err) return } if req.AlbumIDs != nil { if err := repositories.SyncVideoAlbums(id, req.AlbumIDs); err != nil { utils.ServerError(c, err) return } } video, _ := repositories.GetVideoByID(id) if video == nil { utils.Error(c, 404, "Video not found") return } utils.Success(c, repositories.BuildAdminVideoResponse(video)) } func AdminDeleteVideo(c *gin.Context) { id := c.Param("id") if err := repositories.DeleteVideo(id); err != nil { utils.ServerError(c, err) return } utils.SuccessWithMsg(c, "Video deleted", nil) } func AdminGetVideoByID(c *gin.Context) { id := c.Param("id") video, err := repositories.GetVideoByID(id) if err != nil { utils.ServerError(c, err) return } if video == nil { utils.Error(c, 404, "Video not found") return } utils.Success(c, repositories.BuildAdminVideoResponse(video)) }