Initial commit: web_hghl_server

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 16:28:14 +08:00
co-authored by Claude Opus 4.7
commit 65fca60622
653 changed files with 135901 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
package actressapi
import (
"videoweb/app/api/proto"
"videoweb/app/service/actressser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// QueryActressWorkList 指定女优详情和作品混排列表
// @Tags 女优相关接口
// @Summary 指定女优详情和作品列表 -- by 王鸣
// @Description 查询指定女优详情和作品列表,支持上架时间/观看量/收藏量升降序,每间隔8条作品数据插入一个广告
// @Accept json
// @Produce json
// @Param params query proto.QueryActressWorkListReq true "指定女优作品列表请求"
// @Success 200 {object} proto.QueryActressWorkListResp{list=[]proto.QueryVideoListItem{VideoInfo=proto.VideoInfo}} "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /api/app/actress/work/list [get]
func QueryActressWorkList(c *gin.Context) {
var req proto.QueryActressWorkListReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
data, err := actressser.QueryActressWorkList(c, &req)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// ActressList 女优榜单列表
// @Tags 女优相关接口
// @Summary 女优榜单列表 -- by 王鸣
// @Description 返回导航、广告和按热度值降序排列的女优列表
// @Accept json
// @Produce json
// @Success 200 {object} proto.QueryActressListResp "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/actress/list [get]
func ActressList(c *gin.Context) {
data, err := actressser.ActressListData(c, c.Request.URL.Path)
if err != nil {
common.ServerJSON(c, err, "")
return
}
if data == nil {
common.ServerJSON(c, srvdef.ErrDbQueryError, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
+54
View File
@@ -0,0 +1,54 @@
package appinfoapi
import (
"videoweb/app/api/proto"
"videoweb/app/service/appser"
"videoweb/app/service/configser"
"videoweb/app/service/translationser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// QueryAppList 查询应用列表
// @Tags 应用列表
// @Summary 查询应用列表
// @Description 返回应用分类列表,每个分类下含应用信息列表;categoryId=0 返回第一个分类
// @Accept json
// @Produce json
// @Param categoryId query int false "当前分类ID,0表示默认第一个分类"
// @Success 200 {object} proto.AppListResp "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/applist/list [get]
func QueryAppList(c *gin.Context) {
var req struct {
CategoryId int64 `form:"categoryId"`
}
if err := c.ShouldBindQuery(&req); err != nil || req.CategoryId < 0 {
req.CategoryId = 0
}
categoryList, category, serr := appser.AppCategoryData(c, req.CategoryId)
if serr != nil {
common.ServerJSON(c, serr, "")
return
}
if categoryList == nil {
categoryList = make([]proto.AppCategoryInfo, 0)
}
resp := proto.AppListResp{
Path: c.Request.URL.Path,
Translations: translationser.GetTranslationData(),
Config: configser.GetRequestConfig(c),
BottonTranslations: translationser.GetTranslationBottomList(),
Advitise: configser.GetAdvitise(),
Announcement: configser.GetAnnouncement(),
CategoryList: categoryList,
Category: category,
}
configser.RewriteImageCdn(c, &resp)
common.ServerJSON(c, srvdef.Success, resp)
}
+186
View File
@@ -0,0 +1,186 @@
package authapi
import (
"videoweb/app/service/authser"
"videoweb/app/service/wordsfilterser"
"videoweb/pub/common"
"videoweb/pub/common/enum/consts"
"videoweb/pub/common/srvdef"
"videoweb/pub/pubdef"
"github.com/gin-gonic/gin"
)
// extractUA 从 gin context 中提取 UA 中间件解析到的设备/系统信息
func extractUA(ctx *gin.Context) authser.UAInfo {
return authser.UAInfo{
Device: ctx.GetString(consts.CtxDevType),
SysType: pubdef.SysType(ctx.GetString(consts.CtxSysType)),
AppVer: ctx.GetString(consts.CtxVersion),
IP: ctx.ClientIP(),
}
}
type guestLoginReq struct {
DevID string `json:"devID"` // 设备 ID(首选)
Mac string `json:"mac"` // 设备 MAC 地址(备用)
DeviceId string `json:"deviceId"` // 设备 ID 第二版本(备用)
}
type registerReq struct {
AccountNo string `json:"accountNo" binding:"required"` // 账号
Password string `json:"password" binding:"required"` // 明文密码
AgentInviteCode string `json:"agentInviteCode"` // 邀请人的邀请码(可选)
}
type loginReq struct {
Account string `json:"account" binding:"required"` // 账号
Password string `json:"password" binding:"required"` // 明文密码
}
type updateProfileReq struct {
AccountNo string `json:"accountNo" binding:"required"` // 账号(必填,用于定位用户)
Avatar *string `json:"avatar"` // 新头像 URL(可选)
NikeName *string `json:"nikeName"` // 昵称
OldPassword *string `json:"oldPassword"` // 旧密码明文(修改密码时必填)
NewPassword *string `json:"newPassword"` // 新密码明文(修改密码时必填)
}
// GuestLogin 游客登录/自动注册
// @Tags 用户认证
// @Summary 游客登录
// @Description 按设备 ID 查找已有游客账号,找不到则自动注册。若请求携带有效 token 则优先复用该用户。
// @Accept json
// @Produce json
// @Param param body guestLoginReq true "设备信息"
// @Success 200 {object} authser.LoginResp "登录成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/login/guest [POST]
func GuestLogin(ctx *gin.Context) {
var req guestLoginReq
_ = ctx.ShouldBind(&req)
// 若设备信息为空,尝试从 UA 中间件补充 DevID
if req.DevID == "" {
req.DevID = ctx.GetString(consts.CtxDevId)
}
currentUserId := common.GetUserId(ctx)
resp, serr := authser.GuestLogin(ctx, &authser.GuestLoginReq{
DevID: req.DevID,
Mac: req.Mac,
DeviceId: req.DeviceId,
UA: extractUA(ctx),
}, currentUserId)
if serr != nil {
common.ServerJSON(ctx, serr.Code, serr.Tips)
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// Register 账号注册(游客升级 or 直接注册)
// @Tags 用户认证
// @Summary 注册
// @Description 已登录游客传入账号密码完成升级;未登录用户直接注册新账号。
// @Accept json
// @Produce json
// @Param param body registerReq true "注册参数"
// @Success 200 {object} authser.LoginResp "注册成功,返回 token 及用户基本信息"
// @Failure 400 {string} string "失败"
// @Router /api/app/auth/register [POST]
func Register(ctx *gin.Context) {
var req registerReq
if err := ctx.ShouldBind(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
currentUserId := common.GetUserId(ctx)
resp, serr := authser.Register(ctx, req.AccountNo, req.Password, req.AgentInviteCode, currentUserId, extractUA(ctx))
if serr != nil {
common.ServerJSON(ctx, serr.Code, serr.Tips)
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// Login 用户登录
// @Tags 用户认证
// @Summary 登录
// @Description 账号均可作为登录凭证
// @Accept json
// @Produce json
// @Param param body loginReq true "登录参数"
// @Success 200 {object} authser.LoginResp "登录成功,返回 token 及用户基本信息"
// @Failure 400 {string} string "失败"
// @Router /api/app/auth/login [POST]
func Login(ctx *gin.Context) {
var req loginReq
if err := ctx.ShouldBind(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
resp, serr := authser.Login(ctx, req.Account, req.Password, extractUA(ctx))
if serr != nil {
common.ServerJSON(ctx, serr.Code, serr.Tips)
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// GetInfo 获取当前登录用户信息
// @Tags 用户认证
// @Summary 获取当前登录用户信息
// @Description 根据当前登录 token 查询用户基础信息
// @Accept json
// @Produce json
// @Success 200 {object} authser.UserInfoResp "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/auth/getInfo [get]
func GetInfo(ctx *gin.Context) {
userId := common.GetUserId(ctx)
if userId <= 0 {
common.ServerJSON(ctx, srvdef.InvalidToken, nil)
return
}
resp, serr := authser.GetInfo(ctx, userId)
if serr != nil {
common.ServerJSON(ctx, serr.Code, serr.Tips)
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// UpdateProfile 修改用户资料
// @Tags 用户认证
// @Summary 修改用户资料(头像 / 密码,可任意组合)
// @Description 账号必填;avatar、oldPassword+newPassword 均为可选,至少提供一项。修改密码时旧密码和新密码必须同时提供。
// @Accept json
// @Produce json
// @Param param body updateProfileReq true "修改资料参数"
// @Success 200 {string} string "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/auth/profile [POST]
func UpdateProfile(ctx *gin.Context) {
var req updateProfileReq
if err := ctx.ShouldBind(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
if req.NikeName != nil && !wordsfilterser.Validate(*req.NikeName) {
common.ServerJSON(ctx, srvdef.ErrContainIllegalWord, "包含非法字符")
return
}
serr := authser.UpdateProfile(ctx, &authser.UpdateProfileReq{
AccountNo: req.AccountNo,
Avatar: req.Avatar,
NikeName: req.NikeName,
OldPassword: req.OldPassword,
NewPassword: req.NewPassword,
})
if serr != nil {
common.ServerJSON(ctx, serr.Code, serr.Tips)
return
}
common.ServerJSON(ctx, srvdef.Success, "")
}
+102
View File
@@ -0,0 +1,102 @@
package commentapi
import (
"videoweb/app/api/proto"
"videoweb/app/service/commentser"
"videoweb/pub/common"
"videoweb/pub/common/enum/consts"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// List 评论列表
// @Tags 评论APP
// @Summary 评论列表 -- by 王鸣
// @Description 按对象查询树形评论列表
// @Accept json
// @Produce json
// @Param params query proto.CommentListReq true "评论列表请求"
// @Success 200 {object} proto.CommentListResp{list=[]proto.CommentInfo} "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/comment/list [get]
func List(ctx *gin.Context) {
var req proto.CommentListReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
resp, err := commentser.ListCommentTree(ctx, common.GetUserId(ctx), &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// SendComment 发布评论
// @Tags 评论APP
// @Summary 发布评论 -- by 王鸣
// @Description 发布评论
// @Accept json
// @Produce json
// @Param param body proto.CommentSendReq true "参数列表"
// @Success 200 {object} string "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /api/app/comment/send [post]
func SendComment(ctx *gin.Context) {
var in proto.CommentSendReq
if err := ctx.ShouldBindJSON(&in); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
userId, exists := ctx.Get(consts.CtxUserID)
if !exists {
common.ServerJSON(ctx, srvdef.InvalidToken, nil)
return
}
userIdInt64, ok := userId.(int64)
if !ok || userIdInt64 <= 0 {
common.ServerJSON(ctx, srvdef.InvalidToken, nil)
return
}
ip := ctx.ClientIP()
ua, _ := common.GetUA(ctx)
err := commentser.SendComment(ctx, ip, userIdInt64, &in, ua)
if err != nil {
common.ServerJSON(ctx, err.Code, "")
return
}
common.ServerJSON(ctx, srvdef.Success, "success")
}
// SetLike 设置评论点赞状态
// @Tags 评论APP
// @Summary 评论点赞/取消点赞 -- by 王鸣
// @Accept json
// @Produce json
// @Param param body proto.CommentLikeSetReq true "点赞参数"
// @Success 200 {object} proto.CommentLikeSetResp "成功"
// @Security ApiKeyAuth
// @Router /api/app/comment/like/set [post]
func SetLike(ctx *gin.Context) {
var req proto.CommentLikeSetReq
if err := ctx.ShouldBindJSON(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
userId := common.GetUserId(ctx)
if userId <= 0 {
common.ServerJSON(ctx, srvdef.InvalidToken, nil)
return
}
resp, err := commentser.SetCommentLike(ctx, userId, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
+66
View File
@@ -0,0 +1,66 @@
package config
import (
"videoweb/app/api/proto"
"videoweb/app/service/configser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// FooterInfo 查询APP底部信息
// @Tags app配置相关接口
// @Summary 查询APP底部信息 -- by 王鸣
// @Description 返回APP底部品牌、底部导航和联系方式
// @Accept json
// @Produce json
// @Success 200 {object} proto.FooterInfoResp "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/config/footer/info [get]
func FooterInfo(ctx *gin.Context) {
resp := &proto.FooterInfoResp{
FooterInfo: configser.GetFooterInfo(),
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// RichTextList 查询APP富文本内容列表
// @Tags app配置相关接口
// @Summary 查询APP富文本内容列表 -- by 王鸣
// @Description 返回启用状态的富文本内容,支持按ids或titles过滤
// @Accept json
// @Produce json
// @Param ids query string false "富文本ID,多个用英文逗号分隔"
// @Param titles query string false "富文本标题,多个用英文逗号分隔"
// @Success 200 {object} proto.AppRichTextListResp "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/config/richtext/list [get]
func RichTextList(ctx *gin.Context) {
resp := configser.GetAppRichTextList(ctx.Query("ids"), ctx.Query("titles"))
common.ServerJSON(ctx, srvdef.Success, resp)
}
// ContentTagList 查询APP统一标签列表
// @Tags app配置相关接口
// @Summary 查询APP统一标签列表 -- by 王鸣
// @Description 返回启用且有绑定内容数量的统一标签,contentTagType非必填,按绑定内容数量倒序排序
// @Accept json
// @Produce json
// @Param params query proto.AppContentTagListReq false "统一标签列表请求"
// @Success 200 {object} proto.AppContentTagListResp "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/content/tag/list [get]
func ContentTagList(ctx *gin.Context) {
req := &proto.AppContentTagListReq{}
if err := ctx.ShouldBindQuery(req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
return
}
resp, err := configser.AppContentTagList(ctx, req)
if err != nil {
common.ServerJSON(ctx, err.Code, err.Tips)
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
+142
View File
@@ -0,0 +1,142 @@
package dhapi
import (
"fmt"
"strconv"
"videoweb/app/api/proto"
"videoweb/app/service/configser"
"videoweb/app/service/searchser"
"videoweb/app/service/translationser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// DHApi 导航
// @Tags 导航
// @Summary 导航
// @Description 导航
// @Accept json
// @Produce json
// @Param param body string true "参数列表"
// @Success 200 {object} proto.DHHtmlData "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /dh [get]
func DHApi(c *gin.Context) {
data := proto.DHHtmlData{
Path: c.Request.URL.Path,
Translations: translationser.GetTranslationData(),
BottonTranslations: translationser.GetTranslationBottomList(),
Config: configser.GetRequestConfig(c),
HotNavs: configser.GetHotNavs(),
}
configser.RewriteImageCdn(c, &data)
common.JSONWriterCache(c, srvdef.Success, data)
}
// BusinessCooperationApi 导航
// @Tags 导航
// @Summary 导航
// @Description 导航
// @Accept json
// @Produce json
// @Param param body string true "参数列表"
// @Success 200 {object} proto.HomeHtmlData "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /businessCooperation [get]
func BusinessCooperationApi(c *gin.Context) {
data := proto.DHHtmlData{
Path: c.Request.URL.Path,
Translations: translationser.GetTranslationData(),
BottonTranslations: translationser.GetTranslationBottomList(),
Config: configser.GetRequestConfig(c),
Announcement: configser.GetAnnouncement(),
HotSearch: searchser.GetHotSearchItem(c),
Advitise: configser.GetAdvitise(),
}
data.CompletePath = "/businessCooperation"
configser.RewriteImageCdn(c, &data)
common.JSONWriterCache(c, srvdef.Success, data)
}
// ServicesProjectApi 导航
// @Tags 导航
// @Summary 导航
// @Description 导航
// @Accept json
// @Produce json
// @Param param body string true "参数列表"
// @Success 200 {object} proto.HomeHtmlData "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /servicesProject [get]
func ServicesProjectApi(c *gin.Context) {
data := proto.DHHtmlData{
Path: c.Request.URL.Path,
Translations: translationser.GetTranslationData(),
BottonTranslations: translationser.GetTranslationBottomList(),
Config: configser.GetRequestConfig(c),
Announcement: configser.GetAnnouncement(),
HotSearch: searchser.GetHotSearchItem(c),
Advitise: configser.GetAdvitise(),
}
data.CompletePath = "/servicesProject"
configser.RewriteImageCdn(c, &data)
common.JSONWriterCache(c, srvdef.Success, data)
}
// ConsultingApi 招募
// @Tags 招募
// @Summary 招募
// @Description 招募
// @Accept json
// @Produce json
// @Param param body string true "参数列表"
// @Success 200 {object} proto.HomeHtmlData "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /consulting [get]
func ConsultingApi(c *gin.Context) {
data := proto.DHConsultingHtmlData{
Path: c.Request.URL.Path,
Translations: translationser.GetTranslationData(),
BottonTranslations: translationser.GetTranslationBottomList(),
Config: configser.GetRequestConfig(c),
}
data.CompletePath = "/consulting"
configser.RewriteImageCdn(c, &data)
common.JSONWriterCache(c, srvdef.Success, data)
}
// ConsultingInfoApi 招募详情
// @Tags 招募详情
// @Summary 招募详情
// @Description 招募详情
// @Accept json
// @Produce json
// @Param param body string true "参数列表"
// @Success 200 {object} proto.HomeHtmlData "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /consultinginfo/:id [get]
func ConsultingInfoApi(c *gin.Context) {
data := proto.DHConsultingInfoHtmlData{
Path: c.Request.URL.Path,
Translations: translationser.GetTranslationData(),
BottonTranslations: translationser.GetTranslationBottomList(),
Config: configser.GetRequestConfig(c),
Announcement: configser.GetAnnouncement(),
HotSearch: searchser.GetHotSearchItem(c),
Advitise: configser.GetAdvitise(),
}
idStr := c.Param("id")
id, err := strconv.ParseInt(idStr, 10, 64)
if err == nil && id > 0 {
data.CompletePath = fmt.Sprintf("/consultingInfo/%d", id)
}
configser.RewriteImageCdn(c, &data)
common.JSONWriterCache(c, srvdef.Success, data)
}
+42
View File
@@ -0,0 +1,42 @@
package healthapi
import (
"videoweb/app/api/proto"
"videoweb/app/service/healthser"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// HealthCheck 健康检查接口
func HealthCheck(ctx *gin.Context) {
req := &proto.HealthCheckRequest{}
if err := ctx.ShouldBindJSON(req); err != nil {
log.Warn("health check bind error", log.E(err))
respond(ctx, srvdef.ErrParamError, err.Error(), nil)
return
}
log.Info("health check request", log.Any("req", req))
data, serr := healthser.HealthCheck(ctx.Request.Context(), req)
if serr != nil {
log.Warn("health check failed", log.E(serr), log.Any("req", req))
respond(ctx, serr.Code, serr.GetMsg(), nil)
return
}
log.Info("health check response", log.Any("resp", data))
respond(ctx, srvdef.Success, "success", data)
}
func respond(ctx *gin.Context, code srvdef.CodeType, msg string, data interface{}) {
if msg == "" {
msg = code.Msg()
}
ctx.JSON(200, gin.H{
"code": code,
"msg": msg,
"data": data,
})
}
+53
View File
@@ -0,0 +1,53 @@
package home
import (
"videoweb/app/service/homeser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// Home 首页
// @Tags 首页
// @Summary 首页 --by 旺鸣
// @Description 首页分类数据
// @Accept json
// @Produce json
// @Success 200 {object} proto.DataResp "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/home [get]
func Home(c *gin.Context) {
data, err := homeser.HomeData(c)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.JSONWriterCache(c, srvdef.Success, data)
}
// HomeBase 首页公共数据
// @Tags 首页
// @Summary 首页公共数据 --by 旺鸣
// @Description 只返回翻译、配置、底部翻译、广告和公告
// @Accept json
// @Produce json
// @Success 200 {object} proto.HomeBaseResp "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/home/base [get]
func HomeBase(c *gin.Context) {
common.JSONWriterCache(c, srvdef.Success, homeser.HomeBaseData(c))
}
// HomeTags 首页标签数据
// @Tags 首页
// @Summary 首页标签数据 --by 旺鸣
// @Description 返回视频、短剧的标签信息,以及基础导航、配置、广告和公告
// @Accept json
// @Produce json
// @Success 200 {object} proto.HomeTagsResp "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/home/tags [get]
func HomeTags(c *gin.Context) {
common.JSONWriterCache(c, srvdef.Success, homeser.HomeTagsData(c))
}
+122
View File
@@ -0,0 +1,122 @@
package lawandtrust
import (
"videoweb/app/api/proto"
"videoweb/app/service/configser"
"videoweb/app/service/searchser"
"videoweb/app/service/translationser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// UserAgreementApi 用户协议
// @Tags 用户协议
// @Summary 用户协议
// @Description 用户协议
// @Accept json
// @Produce json
// @Param param body string true "参数列表"
// @Success 200 {object} proto.LawAndTrustHtmlData "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /useragreement [get]
func UserAgreementApi(c *gin.Context) {
data := proto.LawAndTrustHtmlData{
Path: c.Request.URL.Path,
Translations: translationser.GetTranslationData(),
BottonTranslations: translationser.GetTranslationBottomList(),
Config: configser.GetRequestConfig(c),
Announcement: configser.GetAnnouncement(),
Advitise: configser.GetAdvitise(),
HotSearch: searchser.GetHotSearchItem(c),
}
data.CompletePath = "/useragreement"
configser.RewriteImageCdn(c, &data)
common.JSONWriterCache(c, srvdef.Success, data)
}
// PrivacyPolicyApi 隐私策略
// @Tags 隐私策略
// @Summary 隐私策略
// @Description 隐私策略
// @Accept json
// @Produce json
// @Param param body string true "参数列表"
// @Success 200 {object} proto.LawAndTrustHtmlData "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /privacyPolicy [get]
func PrivacyPolicyApi(c *gin.Context) {
data := proto.LawAndTrustHtmlData{
Path: c.Request.URL.Path,
Translations: translationser.GetTranslationData(),
BottonTranslations: translationser.GetTranslationBottomList(),
Config: configser.GetRequestConfig(c),
Announcement: configser.GetAnnouncement(),
Advitise: configser.GetAdvitise(),
HotSearch: searchser.GetHotSearchItem(c),
}
data.CompletePath = "/useragreement"
configser.RewriteImageCdn(c, &data)
common.JSONWriterCache(c, srvdef.Success, data)
}
// DmcaApi dmca
// @Tags dmca
// @Summary dmca
// @Description dmca
// @Accept json
// @Produce json
// @Param param body string true "参数列表"
// @Success 200 {object} proto.LawAndTrustHtmlData "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /dmca [get]
func DmcaApi(c *gin.Context) {
data := proto.LawAndTrustHtmlData{
Path: c.Request.URL.Path,
Translations: translationser.GetTranslationData(),
BottonTranslations: translationser.GetTranslationBottomList(),
Config: configser.GetRequestConfig(c),
Announcement: configser.GetAnnouncement(),
Advitise: configser.GetAdvitise(),
HotSearch: searchser.GetHotSearchItem(c),
}
data.CompletePath = "/useragreement"
configser.RewriteImageCdn(c, &data)
common.JSONWriterCache(c, srvdef.Success, data)
}
// StatementApi 合规声明
// @Tags 合规声明
// @Summary 合规声明
// @Description 合规声明
// @Accept json
// @Produce json
// @Param param body string true "参数列表"
// @Success 200 {object} proto.LawAndTrustHtmlData "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /statement [get]
func StatementApi(c *gin.Context) {
data := proto.LawAndTrustHtmlData{
Path: c.Request.URL.Path,
Translations: translationser.GetTranslationData(),
BottonTranslations: translationser.GetTranslationBottomList(),
Config: configser.GetRequestConfig(c),
Announcement: configser.GetAnnouncement(),
Advitise: configser.GetAdvitise(),
HotSearch: searchser.GetHotSearchItem(c),
}
data.CompletePath = "/useragreement"
configser.RewriteImageCdn(c, &data)
common.JSONWriterCache(c, srvdef.Success, data)
}
+27
View File
@@ -0,0 +1,27 @@
package navigationapi
import (
"videoweb/app/service/navigationser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// HeaderNavigation 查询头部导航配置
// @Tags app导航相关接口
// @Summary 查询头部导航配置 -- by 王鸣
// @Description 查询导航类型为URL模式和二级导航的头部导航配置
// @Accept json
// @Produce json
// @Success 200 {object} proto.AppTranslationInfo "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/navigation/header [get]
func HeaderNavigation(ctx *gin.Context) {
resp, err := navigationser.HeaderNavigation(ctx)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.JSONWriterCache(ctx, srvdef.Success, resp)
}
+484
View File
@@ -0,0 +1,484 @@
package playletapi
import (
"videoweb/app/api/proto"
"videoweb/app/service/playletser"
"videoweb/app/service/slugser"
"videoweb/app/service/videoser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// HomePlaylet app端短剧首页
// @Tags app短剧相关接口
// @Summary app端短剧首页 -- by 王鸣
// @Description 返回短剧Banner、首页配置模块、公告、广告和SEO信息
// @Produce json
// @Success 200 {object} proto.HomePlayletResponse "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/playlet/home [get]
func HomePlaylet(ctx *gin.Context) {
resp, err := playletser.Home(ctx)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// HomeConfigList 按首页配置分页查询内容
// @Tags app短剧相关接口
// @Summary app端首页配置内容列表 -- by 王鸣
// @Description 按首页配置ID或slug分页查询内容,同时传入时优先使用slug
// @Produce json
// @Param params query proto.PlayletHomeConfigListReq true "首页配置内容分页请求"
// @Success 200 {object} proto.PlayletHomeConfigListResp "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/playlet/home-config/list [get]
func HomeConfigList(ctx *gin.Context) {
var req proto.PlayletHomeConfigListReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
resp, err := playletser.HomeConfigList(ctx, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// TopicDetail 查询短剧题材或视频分类专题详情
// @Tags app短剧相关接口
// @Summary app端专题详情 -- by 王鸣
// @Produce json
// @Param params query proto.PlayletTopicDetailReq true "专题详情请求"
// @Success 200 {object} proto.PlayletTopicDetailResp "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/playlet/topic/detail [get]
func TopicDetail(ctx *gin.Context) {
var req proto.PlayletTopicDetailReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
resp, err := playletser.TopicDetail(ctx, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// ThemeList 查询全部已启用短剧题材
// @Tags app短剧相关接口
// @Summary app端短剧题材列表
// @Produce json
// @Success 200 {object} proto.PlayletThemeListResp "成功"
// @Router /api/app/playlet/theme/list [get]
func ThemeList(ctx *gin.Context) {
resp, err := playletser.PlayletThemeList(ctx)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// List 分页查询已上架短剧并穿插广告
// @Tags app短剧相关接口
// @Summary app端短剧列表 -- by 王鸣
// @Description 按题材和排序筛选已上架短剧,最近更新按更新时间降序,每4部短剧穿插1条广告
// @Produce json
// @Param params query proto.PlayletListReq true "短剧列表请求"
// @Success 200 {object} proto.PlayletListResp{list=[]proto.PlayletRecommendListItem} "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/playlet/list [get]
func List(ctx *gin.Context) {
var req proto.PlayletListReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
resp, err := playletser.PlayletList(ctx, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// ContentList 分页查询上架短剧或视频并穿插广告
// @Tags app短剧相关接口
// @Summary app端短剧或视频全站排行榜列表 -- by 王鸣
// @Description 按观看量查询上架内容,dataType 为 1 时每 4 条短剧穿插 1 条广告,为 2 时每 5 条视频穿插 1 条广告,并返回广告配置
// @Produce json
// @Param params query proto.PlayletContentListReq true "短剧或视频列表请求"
// @Success 200 {object} proto.PlayletContentListResp{list=[]proto.PlayletContentListItem} "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/playlet/content/list [get]
func ContentList(ctx *gin.Context) {
var req proto.PlayletContentListReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
resp, err := playletser.ContentList(ctx, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// RecommendList app端推荐短剧列表
// @Tags app短剧相关接口
// @Summary app端推荐短剧列表 -- by 王鸣
// @Description 分页查询短剧列表,带穿插列表广告,每间隔8条短剧数据插入一个广告
// @Accept json
// @Produce json
// @Param params query proto.PlayletRecommendListReq true "推荐短剧列表请求"
// @Success 200 {object} proto.PlayletRecommendListResp{list=[]proto.PlayletRecommendListItem} "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/playlet/recommend/list [get]
func RecommendList(ctx *gin.Context) {
var req proto.PlayletRecommendListReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
resp, err := playletser.PlayletRecommendList(ctx, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// GuessList 分页查询猜你喜欢短剧
// @Tags app短剧相关接口
// @Summary 猜你喜欢短剧列表 -- by 王鸣
// @Description id可选,传入时排除当前短剧,按观看量降序查询上架短剧
// @Produce json
// @Param params query proto.PlayletGuessListReq true "猜你喜欢短剧请求"
// @Success 200 {object} proto.PlayletGuessListResp{list=[]proto.PlayletRecommendListItem} "成功"
// @Router /api/app/playlet/guess/list [get]
func GuessList(ctx *gin.Context) {
var req proto.PlayletGuessListReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
resp, err := playletser.PlayletGuessList(ctx, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// TagList app端根据标签ID查询短剧列表
// @Tags app短剧相关接口
// @Summary app端根据标签ID查询短剧列表 -- by 王鸣
// @Description 根据统一标签ID分页查询已上架短剧
// @Accept json
// @Produce json
// @Param id path int true "标签ID"
// @Param pageNum query int false "页码,默认1"
// @Param pageSize query int false "每页数量,默认20,最大100"
// @Success 200 {object} proto.PlayletRecommendListResp{list=[]proto.PlayletRecommendListItem} "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/playlet/tag/{id} [get]
func TagList(ctx *gin.Context) {
var req proto.ContentTagPageReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
pathID, pathSlug := slugser.ParseIDOrSlug(ctx.Param("id"))
if req.Id <= 0 {
req.Id = pathID
}
if req.Slug == "" {
req.Slug = pathSlug
}
resp, err := playletser.PlayletTagList(ctx, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// QueryPlayletInfo 短剧详情
// @Tags app短剧相关接口
// @Summary 短剧详情 -- by 王鸣
// @Description 查询短剧详情、剧集列表、点赞状态和收藏状态
// @Accept json
// @Produce json
// @Param params query proto.QueryPlayletInfoReq true "短剧详情查询请求"
// @Success 200 {object} proto.QueryPlayletInfoResp{playletInfo=proto.PlayletDetailInfo,chapterList=[]proto.PlayletChapterInfo} "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/playlet/info [get]
func QueryPlayletInfo(ctx *gin.Context) {
var req proto.QueryPlayletInfoReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
resp, err := playletser.QueryPlayletInfo(ctx, common.GetUserId(ctx), videoser.H5M3U8RequestIP(ctx), ctx.Request.UserAgent(), &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// QueryPlayletChapterInfo 短剧剧集详情
// @Tags app短剧相关接口
// @Summary app端短剧剧集详情 -- by 王鸣
// @Description 根据剧集ID查询短剧剧集详情、所属短剧、剧集列表、热门短剧列表和点赞状态
// @Accept json
// @Produce json
// @Param params query proto.QueryPlayletChapterInfoReq true "短剧剧集详情查询请求"
// @Success 200 {object} proto.QueryPlayletChapterInfoResp{chapterInfo=proto.PlayletChapterInfo,playletInfo=proto.PlayletData,chapterList=[]proto.PlayletChapterInfo,hotPlayletList=[]proto.PlayletData} "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/playlet/chapter/info [get]
func QueryPlayletChapterInfo(ctx *gin.Context) {
var req proto.QueryPlayletChapterInfoReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
resp, err := playletser.QueryPlayletChapterInfo(ctx, common.GetUserId(ctx), videoser.H5M3U8RequestIP(ctx), ctx.Request.UserAgent(), &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// LikePlaylet 点赞或取消点赞短剧
// @Tags app短剧相关接口
// @Summary 点赞或取消点赞短剧 -- by 王鸣
// @Description 当前登录用户点赞或取消点赞指定短剧,isLike=true表示点赞,isLike=false表示取消点赞
// @Accept json
// @Produce json
// @Param param body proto.LikePlayletReq true "点赞或取消点赞请求"
// @Success 200 {object} proto.LikePlayletResp "成功"
// @Failure 400 {string} string "失败"
// @Security ApiKeyAuth
// @Router /api/app/playlet/like [post]
func LikePlaylet(ctx *gin.Context) {
var req proto.LikePlayletReq
if err := ctx.ShouldBindJSON(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
userId := common.GetUserId(ctx)
if userId <= 0 {
common.ServerJSON(ctx, srvdef.InvalidToken, "")
return
}
ua, _ := common.GetUA(ctx)
if ua.UserAgent == "" {
ua.UserAgent = ctx.Request.UserAgent()
}
resp, err := playletser.LikePlaylet(ctx, userId, ctx.ClientIP(), ua, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// QueryLikePlayletList 当前用户点赞短剧分页列表
// @Tags app短剧相关接口
// @Summary 当前用户点赞短剧分页列表
// @Description 按点赞时间倒序返回当前用户点赞的上架短剧
// @Produce json
// @Param params query proto.QueryLikePlayletListReq true "点赞短剧分页请求"
// @Success 200 {object} proto.QueryLikePlayletListResp{list=[]proto.PlayletData} "成功"
// @Security ApiKeyAuth
// @Router /api/app/playlet/like/list [get]
func QueryLikePlayletList(ctx *gin.Context) {
var req proto.QueryLikePlayletListReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
userID := common.GetUserId(ctx)
if userID <= 0 {
common.ServerJSON(ctx, srvdef.InvalidToken, "")
return
}
resp, err := playletser.QueryLikePlayletList(ctx, userID, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// FavoritePlaylet 收藏或取消收藏短剧
// @Tags app短剧相关接口
// @Summary 收藏或取消收藏短剧
// @Description isFavorite=true 收藏 false 取消收藏
// @Accept json
// @Produce json
// @Param param body proto.FavoritePlayletReq true "短剧收藏请求"
// @Success 200 {object} proto.FavoritePlayletResp "成功"
// @Security ApiKeyAuth
// @Router /api/app/playlet/favorite [post]
func FavoritePlaylet(ctx *gin.Context) {
var req proto.FavoritePlayletReq
if err := ctx.ShouldBindJSON(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
userID := common.GetUserId(ctx)
if userID <= 0 {
common.ServerJSON(ctx, srvdef.InvalidToken, "")
return
}
ua, _ := common.GetUA(ctx)
if ua.UserAgent == "" {
ua.UserAgent = ctx.Request.UserAgent()
}
resp, err := playletser.FavoritePlaylet(ctx, userID, ctx.ClientIP(), ua, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// QueryFavoritePlayletList 当前用户收藏短剧分页列表
// @Tags app短剧相关接口
// @Summary 当前用户收藏短剧分页列表
// @Produce json
// @Param params query proto.QueryFavoritePlayletListReq true "收藏短剧分页请求"
// @Success 200 {object} proto.QueryFavoritePlayletListResp{list=[]proto.PlayletData} "成功"
// @Security ApiKeyAuth
// @Router /api/app/playlet/favorite/list [get]
func QueryFavoritePlayletList(ctx *gin.Context) {
var req proto.QueryFavoritePlayletListReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
userID := common.GetUserId(ctx)
if userID <= 0 {
common.ServerJSON(ctx, srvdef.InvalidToken, "")
return
}
resp, err := playletser.QueryFavoritePlayletList(ctx, userID, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// ReportPlayletHistory 播放成功后记录当前用户的短剧剧集
// @Tags app短剧相关接口
// @Summary 上报短剧观看历史
// @Accept json
// @Produce json
// @Param param body proto.PlayletHistoryReportReq true "当前播放短剧和剧集"
// @Success 200 {object} proto.PlayletHistoryReportResp "成功"
// @Security ApiKeyAuth
// @Router /api/app/playlet/history [post]
func ReportPlayletHistory(ctx *gin.Context) {
userID := common.GetUserId(ctx)
if userID <= 0 {
common.ServerJSON(ctx, srvdef.InvalidToken, "")
return
}
var req proto.PlayletHistoryReportReq
if err := ctx.ShouldBindJSON(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
resp, err := playletser.ReportPlayletHistory(ctx, userID, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// QueryPlayletHistoryList 当前用户短剧观看历史分页列表
// @Tags app短剧相关接口
// @Summary 短剧观看历史列表
// @Produce json
// @Param params query proto.PlayletHistoryListReq true "分页请求"
// @Success 200 {object} proto.PlayletHistoryListResp{list=[]proto.PlayletHistoryItem} "成功"
// @Security ApiKeyAuth
// @Router /api/app/playlet/history/list [get]
func QueryPlayletHistoryList(ctx *gin.Context) {
userID := common.GetUserId(ctx)
if userID <= 0 {
common.ServerJSON(ctx, srvdef.InvalidToken, "")
return
}
var req proto.PlayletHistoryListReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
resp, err := playletser.QueryPlayletHistoryList(ctx, userID, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// ClearPlayletHistory 清空当前用户短剧观看历史
// @Tags app短剧相关接口
// @Summary 清空短剧观看历史
// @Produce json
// @Success 200 {object} proto.PlayletHistoryClearResp "成功"
// @Security ApiKeyAuth
// @Router /api/app/playlet/history [delete]
func ClearPlayletHistory(ctx *gin.Context) {
userID := common.GetUserId(ctx)
if userID <= 0 {
common.ServerJSON(ctx, srvdef.InvalidToken, "")
return
}
resp, err := playletser.ClearPlayletHistory(ctx, userID)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
// QueryPlayletRankList 短剧排行榜分页列表
// @Tags app短剧相关接口
// @Summary 短剧排行榜分页列表 -- by 王鸣
// @Description 分页查询短剧排行榜,rankPeriod=0点赞榜(累计点赞)、1周榜/2月榜/3年榜(周期观看量),独立缓存10分钟,每榜最多50条,pageSize不是50时强制为50
// @Accept json
// @Produce json
// @Param params query proto.PlayletRankReq true "短剧排行榜分页请求"
// @Success 200 {object} proto.PlayletRankResp{list=[]proto.PlayletRankData} "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/playlet/rank/list [get]
func QueryPlayletRankList(ctx *gin.Context) {
var req proto.PlayletRankReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "")
return
}
resp, err := playletser.QueryPlayletRank(ctx, &req)
if err != nil {
common.ServerJSON(ctx, err, err.GetMsg())
return
}
common.ServerJSON(ctx, srvdef.Success, resp)
}
+96
View File
@@ -0,0 +1,96 @@
package proto
import (
"time"
"videoweb/pub/common/netutil"
"videoweb/pub/common/response"
"videoweb/pub/models/actress"
"videoweb/pub/pubdef"
)
// QueryActressWorkListReq 指定女优作品列表请求
type QueryActressWorkListReq struct {
pubdef.Page
// 女优ID
Id int64 `json:"id" form:"id"`
// 女优slug,非空时优先按slug解析女优ID
Slug string `json:"slug" form:"slug"`
// 上架时间升序/降序(1-升序 2降序)
AddedTimeSort int64 `json:"addedTimeSort" form:"addedTimeSort"`
// 按观看量升序/降序(1-升序 2降序)
WatchTimesSort int64 `json:"watchTimesSort" form:"watchTimesSort"`
// 按收藏(点赞)量升序/降序(1-升序 2降序)
LikesSort int64 `json:"likesSort" form:"likesSort"`
}
// QueryActressWorkListResp 指定女优详情和作品混排列表响应
type QueryActressWorkListResp struct {
// 分页信息;List 类型为 []*QueryVideoListItem,包含视频项(type=0)和广告项(type=2)
response.BasePageResp
// 导航
Translations AppTranslationInfo `json:"translations"`
// 底部翻译
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
// 女优信息
ActressInfo ActressInfoData `json:"actressInfo"`
}
// QueryActressListResp 女优榜单列表响应
type QueryActressListResp struct {
// 当前路径
Path string `json:"path"`
// 导航
Translations AppTranslationInfo `json:"translations"`
// 底部导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
// 广告
Advitise AdvitiseData `json:"advitise"`
// 女优列表
ActressInfoList []ActressInfoData `json:"actressInfoList"`
}
type ActressInfoData struct {
Id int64 `json:"id" bson:"_id"` // Id
Alias string `bson:"alias" json:"alias"` // 别名
Slug string `json:"slug"` // slug
Avatar string `bson:"avatar" json:"avatar"` // 头像
Cover string `bson:"cover" json:"cover"` // 封面大图
Desc string `bson:"desc" json:"desc"` // 详细描述
Meas actress.Meas `bson:"meas" json:"meas"` // 三围
MeasValue string `bson:"measValue" json:"measValue"` // 三围值
Office string `json:"office" bson:"office"` // 事务所
DebutDate time.Time `bson:"debutDate" json:"debutDate" ` // 出道日期
BornDate time.Time `bson:"bornDate" json:"bornDate"` // 出生日期
Region string `json:"region" bson:"region"` // 地区/国家
Score string `json:"score" bson:"score"` // 评分
Works int64 `json:"works" bson:"works"` // 作品数
HotValue int64 `json:"hotValue" bson:"hotValue"` // 热度值
WatchTimes int64 `json:"watchTimes" bson:"watchTimes"` // 观看次数
ShowTimes int64 `json:"showTimes" bson:"showTimes"` // 展示次数
Comments int64 `json:"comments" bson:"comments"` // 评论条数
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
}
func ActressInfoToData(actress2 actress.Actress, imageCdn string) ActressInfoData {
return ActressInfoData{
Id: actress2.Id,
Alias: actress2.Alias,
Slug: actress2.Slug,
Avatar: netutil.MergeURL(imageCdn, actress2.Avatar),
Cover: netutil.MergeURL(imageCdn, actress2.Cover),
Desc: actress2.Desc,
Meas: actress2.Meas,
Office: actress2.Office,
DebutDate: actress2.DebutDate,
BornDate: actress2.BornDate,
Region: actress2.Region,
Score: actress2.Score,
MeasValue: actress2.Meas.Measurements(),
Works: actress2.Works,
HotValue: actress2.HotValue,
WatchTimes: actress2.Real.WatchTimes*100 + 2273,
ShowTimes: actress2.Real.WatchTimes*100 + 3273,
Comments: actress2.Real.Comments,
SeoInfo: actress2.SeoInfo,
}
}
+38
View File
@@ -0,0 +1,38 @@
package proto
import "videoweb/pub/storage/proxy"
type AdsClickReq struct {
AdsId string `json:"adsId,omitempty" binding:"required"`
Location int64 `json:"location,omitempty" binding:"required"` // 位置ID
}
type AdsClickInfo struct {
AppId int64 `json:"appId,omitempty" binding:"required"` // appId
AdsId int64 `json:"adsId,omitempty" binding:"required"`
Location int64 `json:"location,omitempty" binding:"required"` // 位置ID
}
type AdvitiseData struct {
HomeList []proxy.AdvitiseInfo `json:"homeList" bson:"homeList"` // 首页列表
DetailTopList []proxy.AdvitiseInfo `json:"detailTopList" bson:"detailTopList"` // 详情页顶部广告
NineGridList []proxy.AdvitiseInfo `json:"nineGridList" bson:"nineGridList"` // 9宫格
DetailbannerList []proxy.AdvitiseInfo `json:"detailbannerList" bson:"detailbannerList"` // 详情banner
LaunchScreenList []proxy.AdvitiseInfo `json:"launchScreenList"` // 启动页广告
FloatingList []proxy.AdvitiseInfo `json:"floatingList" bson:"floatingList"` // 悬浮小方块
AList []proxy.AdvitiseInfo `json:"AList"` // 固定12广告位
BList []proxy.AdvitiseInfo `json:"BList"` // 固定13广告位
DialogList []proxy.AdvitiseInfo `json:"dialogList" bson:"dialogList"` // 弹窗广告
PostList []proxy.AdvitiseInfo `json:"postList" bson:"postList"` // 列表穿插广告(视频、短剧、女优列表使用)
MustAppList []proxy.AdvitiseInfo `json:"mustAppList" bson:"mustAppList"` // 必备精品
TitleAppList []proxy.AdvitiseInfo `json:"titleAppList" bson:"titleAppList"` // 标题广告(APP名称)
FriendList []proxy.AdvitiseInfo `json:"friendList" bson:"friendList"` // 友链
VideoList []proxy.AdvitiseInfo `json:"videoList" bson:"videoList"` // 视频列表
//VideoInfoList []proxy.AdvitiseInfo `json:"videoInfoList" bson:"videoInfoList"` // 视频详情
//DownList []proxy.AdvitiseInfo `json:"downList" bson:"downList"` // 底部广告
//HomeBanner []proxy.AdvitiseInfo `json:"homeBanner" bson:"homeBanner"` // 首页banner小广告
//PlayList []proxy.AdvitiseInfo `json:"playList" bson:"playList"` // 播放强制跳转
//PauseyList []proxy.AdvitiseInfo `json:"pauseyList" bson:"pauseyList"` // 暂停广告
}
+61
View File
@@ -0,0 +1,61 @@
package proto
// AppListResp 应用列表接口响应
type AppListResp struct {
// 当前路径
Path string `json:"path"`
// 导航
Translations AppTranslationInfo `json:"translations"`
// 配置信息
Config ConfigInfo `json:"config"`
// 底部导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
// 广告
Advitise AdvitiseData `json:"advitise"`
// 公告
Announcement AnnouncementInfo `json:"announcement"`
// 应用分类列表(含各分类下的应用列表)
CategoryList []AppCategoryInfo `json:"categoryList"`
// 当前分类(含应用列表)
Category AppCategoryInfo `json:"category"`
}
// AppCategoryInfo 应用分类信息
type AppCategoryInfo struct {
// 分类ID
Id int64 `json:"id"`
// 分类标题
Title string `json:"title"`
// 分类简介
Intro string `json:"intro"`
// 排序
Sort int64 `json:"sort"`
// 分类编码(特殊值:12=广告位A 13=广告位B)
Code int64 `json:"code"`
// 应用列表
AppList []AppInfoData `json:"appList"`
}
// AppInfoData 应用信息
type AppInfoData struct {
// 应用ID
Id int64 `json:"id"`
// 所属分类ID
CategoryId int64 `json:"categoryId"`
// 应用名称
Name string `json:"name"`
// 简介
Intro string `json:"intro"`
// 详细描述
Description string `json:"description"`
// Logo 图片地址
Logo string `json:"logo"`
// 跳转链接(已含渠道码)
Url string `json:"url"`
// 排序
Sort int64 `json:"sort"`
// 广告ID(广告条目时返回)
AdvitiseId string `json:"advitiseId"`
// 广告位置ID
Location int64 `json:"location"`
}
+64
View File
@@ -0,0 +1,64 @@
package proto
import (
"time"
"videoweb/pub/common/response"
"videoweb/pub/pubdef"
)
type CommentListReq struct {
ObjectId int64 `form:"objectId" json:"objectId"` // 对象ID
ObjectType pubdef.CommentObjectType `form:"objectType" json:"objectType"` // 对象类型 0=视频 4=短剧 11=短剧剧集
SortOrder int64 `form:"sortOrder" json:"sortOrder"` // 排序 1=热门 2=最新 默认最新
pubdef.Page
}
type CommentListResp struct {
response.BasePageResp
}
type GetCommentListReq struct {
ObjectId int64 `form:"objectId" json:"objectId"` // 对象ID
ParentsId int64 `json:"parentsId" bson:"parentsId"` // 上级评论ID
pubdef.Page
}
type GetCommentListResp struct {
ObjectId int64 `json:"objectId" bson:"objectId"`
Total int64 `json:"total" bson:"total"` // 总数量
List []CommentInfo `json:"list" bson:"list"` // 数据
}
type CommentSendReq struct {
ObjectId int64 `json:"objectId" bson:"objectId"` // 对象ID
ObjectType pubdef.CommentObjectType `json:"objectType" bson:"objectType"` // 对象类型 0=视频 4=短剧 11=短剧剧集
ParentsId int64 `json:"parentsId" bson:"parentsId"` // 上级评论ID
Text string `json:"text" bson:"text"` // 评论内容
}
type CommentInfo struct {
Id int64 `json:"id" bson:"_id,omitempty"` // 评论ID
ObjectId int64 `json:"objectId" bson:"objectId"` // 对象ID
UserName string `json:"userName" bson:"userName"` // 用户名称
Avatar string `json:"avatar" bson:"avatar"` // 用户头像
Level int64 `json:"level" bson:"level"` // 评论级别
ParentsId int64 `json:"parentsId" bson:"parentsId"` // 上级评论ID
ReplyUserName string `json:"replyUserName" bson:"replyUserName"` // 回复名称
Text string `json:"text" bson:"text"` // 评论内容
CommentCount int64 `json:"commentCount" bson:"commentCount"` // 该评论回复数量
CountLike int64 `json:"countLike" bson:"countLike"` // 点赞数
IsLike bool `json:"isLike" bson:"-"` // 当前用户是否点赞
SubComment []CommentInfo `json:"subComment" bson:"subComment"` // 子评论
CreatedAt time.Time `bson:"createdAt" json:"createdAt"` // 创建时间
}
type CommentLikeSetReq struct {
CommentId int64 `json:"commentId" binding:"required"` // 评论ID
IsLike *bool `json:"isLike" binding:"required"` // 是否点赞
}
type CommentLikeSetResp struct {
CommentId int64 `json:"commentId"` // 评论ID
IsLike bool `json:"isLike"` // 当前点赞状态
CountLike int64 `json:"countLike"` // 点赞数
}
+132
View File
@@ -0,0 +1,132 @@
package proto
import (
"videoweb/pub/models/contenttagmod"
"videoweb/pub/pubdef"
)
type ConfigInfo struct {
PdfAddr string `json:"pdfAddr" bson:"pdfAddr"` // 回家的路PDF
NewUrlAddr string `json:"newUrlAddr" bson:"newUrlAddr"` //最新地址
NewUrlAddr1 string `json:"newUrlAddr1" bson:"newUrlAddr1"` //最新地址(备用地址1)
NewUrlAddr2 string `json:"newUrlAddr2" bson:"newUrlAddr2"` //最新地址(备用地址2)
ForeverUrlAddr string `json:"foreverUrlAddr" bson:"foreverUrlAddr"` //永久地址
GmailAddr string `json:"gmailAddr" bson:"gmailAddr"` //邮箱地址
AppAddr string `json:"appAddr" bson:"appAddr"` //APP下载地址(落地页)
WeiChart string `json:"weiChart" bson:"weiChart"` //微信群
QQ string `json:"qq" bson:"qq"` //qq群
TgGroup string `json:"tgGroup" bson:"tgGroup"` //tg群
PotaoGroup string `json:"potaoGroup" bson:"potaoGroup"` //土豆群
GitAddr string `json:"gitAddr" bson:"gitAddr"` //git地址
TwitterAddr string `json:"twitterAddr" bson:"twitterAddr"` //推特地址
Telegram string `json:"telegram" bson:"telegram"` //商务tg
TelegramAdd string `json:"telegramAdd" bson:"telegramAdd"` //加入我们tg
TranslationAddr string `json:"translationAddr" bson:"translationAddr"` //应用导航
ImgCdn string `json:"imgCdn" bson:"imgCdn"` // 图片CDN
TsCdn string `json:"tsCdn" bson:"tsCdn"` // 视频CDN
ImgAppUsCdn string `json:"imgAppUsCdn" bson:"imgAppUsCdn"` // 图片CDN(海外app使用)
MediaAppUsCdn string `json:"mediaAppUsCdn" bson:"mediaAppUsCdn"` // 视频CDN(海外app使用)
WebTitle string `json:"webTitle" bson:"webTitle"` // 网站SEO标题
WebKeyworld []string `json:"webKeyworld" bson:"webKeyworld"` // 网站SEO关键字
WebDescription string `json:"webDescription" bson:"webDescription"` // 网站SEO描述
WebSiteName string `json:"webSiteName" bson:"webSiteName"` // 网站SEO网站名称
WebAddr string `json:"webAddr" bson:"webAddr"` // 网站SEO网站地址
DHNewUrlAddr1 string `json:"dhNewUrlAddr1" bson:"dhNewUrlAddr1"` // 导航页-线路1
DHNewUrlAddr2 string `json:"dhNewUrlAddr2" bson:"dhNewUrlAddr2"` // 导航页-线路2
DHNewUrlAddr3 string `json:"dhNewUrlAddr3" bson:"dhNewUrlAddr3"` // 导航页-线路3
FreeVPN string `json:"freeVPN" bson:"freeVPN"` // 免费vpn链接
UseIngAddress []string `json:"useIngAddress" bson:"useIngAddress"` // 所有使用中的域名
DHTitle string `json:"dhTitle" bson:"dhTitle"` // 导航SEO标题
DHKeyworld []string `json:"dhKeyworld" bson:"dhKeyworld"` // 导航SEO关键字
DHDescription string `json:"dhDescription" bson:"dhDescription"` // 导航SEO描述
DHSiteName string `json:"dhSiteName" bson:"dhSiteName"` // 导航SEO网站名称
ReportSDKConfig string `json:"reportSdkConfig"` // 数据上报SDK域名配置
ChannelCode string `json:"channelCode"` // 渠道码
EnableH265 bool `json:"enableH265" bson:"enableH265"` // 是否允许客户端使用 H265 地址播放
M3U8DayRateLimitMax int64 `json:"m3u8DayRateLimitMax" bson:"m3u8DayRateLimitMax"` // 每 IP 每天最多不同正片数
}
// AnnouncementInfo 公告数据
type AnnouncementInfo struct {
VideoInfo []VideoInfoData `json:"videoInfo" bson:"videoInfo"` // 热门信息
PdfAddr string `json:"pdfAddr" bson:"pdfAddr"` // 回家的路PDF
NewUrlAddr string `json:"newUrlAddr" bson:"newUrlAddr"` // 新国内地址
NewUrlAddr1 string `json:"newUrlAddr1" bson:"newUrlAddr1"` // 备用地址1
NewUrlAddr2 string `json:"newUrlAddr2" bson:"newUrlAddr2"` // 备用地址1
ForeverUrlAddr string `json:"foreverUrlAddr" bson:"foreverUrlAddr"` // 永久海外地址(翻墙访问 永不迷路)
AppAddr string `json:"appAddr" bson:"appAddr"` // 吃瓜app (免费吃瓜 每日更新)
TranslationAddr string `json:"translationAddr" bson:"translationAddr"` // 应用导航
}
type AdvitiseInfo struct {
Id int64 `json:"id" bson:"_id"` // 广告id
Title string `json:"title" bson:"title"` // 广告标题
Images string `json:"images" bson:"images"` // 视频banner
Link string `json:"link" bson:"link"` // 链接
}
// FooterInfoResp APP底部信息响应
type FooterInfoResp struct {
FooterInfo FooterInfo `json:"footerInfo"` // 底部信息
}
// FooterInfo APP底部信息
type FooterInfo struct {
Brand FooterBrand `json:"brand"` // 品牌信息
NavList []TranslationCategory `json:"navList"` // 底部导航
ContactList []FooterContact `json:"contactList"` // 联系方式
}
// FooterBrand APP底部品牌信息
type FooterBrand struct {
Title string `json:"title"` // 品牌标题
Content string `json:"content"` // 品牌标语
}
// FooterContact APP底部联系方式
type FooterContact struct {
Name string `json:"name"` // 联系方式名称
Value string `json:"value"` // 联系方式值
}
// AppContentTagListReq app端统一标签列表请求
type AppContentTagListReq struct {
ContentTagType *contenttagmod.ContentTagType `form:"contentTagType" json:"contentTagType"` // 内容类型 1-视频 5-短剧,不传返回全部有绑定数量的标签
}
// ContentTagPageReq 根据统一标签分页查询内容请求
type ContentTagPageReq struct {
pubdef.Page
Id int64 `json:"id" form:"id"` // 标签ID
Slug string `json:"slug" form:"slug"` // 标签slug,非空时优先按slug解析标签ID
}
// AppContentTagListResp app端统一标签列表响应
type AppContentTagListResp struct {
List []*AppContentTagItem `json:"list"` // 统一标签列表
}
// AppContentTagItem app端统一标签列表项
type AppContentTagItem struct {
Id int64 `json:"id" bson:"_id"` // 标签ID
Name string `json:"name" bson:"name"` // 标签名称
Slug string `json:"slug" bson:"slug"` // slug
Types []contenttagmod.ContentTagType `json:"types" bson:"types"` // 支持类型 1-视频 5-短剧
BindCount int64 `json:"bindCount" bson:"bindCount"` // 当前查询类型绑定数量,不传type时为各类型绑定数量合计
VideoCount int64 `json:"videoCount" bson:"videoCount"` // 绑定视频数量
PlayletCount int64 `json:"playletCount" bson:"playletCount"` // 绑定短剧数量
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
Rank int64 `json:"rank,omitempty" bson:"rank,omitempty"` // 排序
}
// type AdvitiseData struct {
// DialogList []AdvitiseInfo `json:"dialogList" bson:"dialogList"` // 弹窗广告
// HomeList []AdvitiseInfo `json:"homeList" bson:"homeList"` // 首页列表
// VideoTopList []AdvitiseInfo `json:"videoTopList" bson:"videoTopList"` // 帖子详情(上)
// VideoDownList []AdvitiseInfo `json:"videoDownList" bson:"videoDownList"` // 帖子详情(下)
// HotAppList []AdvitiseInfo `json:"hotAppList" bson:"hotAppList"` // 热门应用
// NewAppList []AdvitiseInfo `json:"newAppList" bson:"newAppList"` // 最新上架
// MustAppList []AdvitiseInfo `json:"mustAppList" bson:"mustAppList"` // 必备精品
// TitleAppList []AdvitiseInfo `json:"titleAppList" bson:"titleAppList"` // 标题广告(APP名称)
// }
+6
View File
@@ -0,0 +1,6 @@
package proto
type ContributeData struct {
Path string `json:"path"`
RichText []RichTextInfo `json:"richText" form:"richText"` // 富文本内容
}
+50
View File
@@ -0,0 +1,50 @@
package proto
// HotNavItem 热门导航
type HotNavItem struct {
Id int64 `json:"id"` // ID
Title string `json:"title"` // 标题
Intro string `json:"intro"` // 介绍
Url string `json:"url"` // 链接
Icon string `json:"icon"` // 图标
}
// DHHtmlData 导航数据
type DHHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
RichTextInfo RichTextInfo `json:"richTextInfo" form:"richTextInfo"` // 富文本
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
HotNavs []HotNavItem `json:"hotNavs"` // 热门导航
}
// DHConsultingHtmlData 招募
type DHConsultingHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
RichTextInfo RichTextInfo `json:"richTextInfo" form:"richTextInfo"` // 富文本
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
}
// DHConsultingInfoHtmlData 招募
type DHConsultingInfoHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
RichTextInfo RichTextInfo `json:"richTextInfo" form:"richTextInfo"` // 富文本
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
}
+5
View File
@@ -0,0 +1,5 @@
package proto
type FindVideoData struct {
RichText []RichTextInfo `json:"richText" form:"richText"` // 富文本内容
}
+37
View File
@@ -0,0 +1,37 @@
package proto
type HealthCheckRequest struct {
GroupID string `json:"groupId" binding:"required"`
Timestamp int64 `json:"timestamp" binding:"required"`
Sign string `json:"sign" binding:"required"`
}
type ComponentStatus struct {
Status string `json:"status"`
Msg string `json:"msg,omitempty"`
Master string `json:"master,omitempty"`
}
type HealthCPUMetrics struct {
Cores int `json:"cores"`
Used float64 `json:"used"`
}
type HealthMemoryMetrics struct {
Total int64 `json:"total"`
Used int64 `json:"used"`
}
type HealthCheckData struct {
ServerName string `json:"serverName,omitempty"`
ServerIP string `json:"serverIp,omitempty"`
CPU HealthCPUMetrics `json:"cpu"`
Memory HealthMemoryMetrics `json:"memory"`
Disk HealthMemoryMetrics `json:"disk"`
Mysql *ComponentStatus `json:"mysql,omitempty"`
Mongodb *ComponentStatus `json:"mongodb,omitempty"`
Redis *ComponentStatus `json:"redis,omitempty"`
Elasticsearch *ComponentStatus `json:"elasticsearch,omitempty"`
Kafka *ComponentStatus `json:"kafka,omitempty"`
Timestamp int64 `json:"timestamp"`
}
+171
View File
@@ -0,0 +1,171 @@
package proto
import (
"time"
"videoweb/pub/pubdef"
)
// DataResp 首页数据响应
type DataResp struct {
// 当前路径
Path string `json:"path"`
// 配置信息
Config ConfigInfo `json:"config"`
// 广告
Advitise AdvitiseData `json:"advitise"`
// 公告
Announcement AnnouncementInfo `json:"announcement"`
// 首页banner信息列表
HomeBannerList []HomeBannerInfo `json:"homeBannerList"`
// 首页短剧数据
PlayletData HomePlayletDataResp `json:"playletData"`
// 首页视频数据
VideoData HomeVideoDataResp `json:"videoData"`
// 女优信息
ActressInfoList []ActressInfo `json:"actressInfoList"`
}
// HomeBannerInfo 首页banner信息
type HomeBannerInfo struct {
Id int64 `json:"id"` // ID
Name string `json:"name"` // 名称
Image string `json:"image"` // 图片,已拼接图片域名
VerticalImage string `json:"verticalImage"` // 竖版图片,已拼接图片域名
Url string `json:"url"` // URL
Rank int64 `json:"rank"` // 排序
Status bool `json:"status"` // 状态 true-启用 false-停用
}
// HomePlayletDataResp 首页短剧数据响应
type HomePlayletDataResp struct {
RecommendList []PlayletData `json:"recommendList"` // 推荐短剧列表
NewestList []PlayletData `json:"newestList"` // 最新短剧列表
HotList []PlayletData `json:"hotList"` // 最热短剧列表
}
// HomeVideoDataResp 首页视频数据响应
type HomeVideoDataResp struct {
RecommendList []VideoInfo `json:"recommendList"` // 推荐视频列表
NewestList []VideoInfo `json:"newestList"` // 最新视频列表
HotList []VideoInfo `json:"hotList"` // 最热视频列表
}
// HomeBaseResp 首页公共数据响应
type HomeBaseResp struct {
// 导航
Translations AppTranslationInfo `json:"translations"`
// 配置信息
Config ConfigInfo `json:"config"`
// 底部翻译
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
// 广告
Advitise AdvitiseData `json:"advitise"`
// 公告
Announcement AnnouncementInfo `json:"announcement"`
}
// HomeTagsResp 首页标签数据响应
type HomeTagsResp struct {
HomeBaseResp
// 视频标签
VideoTagsList []TagsInfoData `json:"videoTagsList"`
// 短剧标签
PlayletTagsList []TagsInfoData `json:"playletTagsList"`
}
// VideoCategoryDataInfo 视频分类数据
type VideoCategoryDataInfo struct {
CommonData
// Seo相关信息
SeoInfo pubdef.SeoValue `json:"seoInfo"`
// 描述
Desc string `json:"desc"`
// 分类关联的视频标签
Tags []int64 `json:"tags"`
// 视频信息集合
VideoInfoList []VideoInfo `json:"videoInfoList"`
}
// CommonData 分类通用数据
type CommonData struct {
// Id
Id int64 `json:"id"`
// 分类名称
Name string `json:"name"`
// slug
Slug string `json:"slug"`
// APP显示
Title string `json:"title"`
// 显示位置 0=仅TAB 1=仅首页 2=两者都显示
DisplayPosition pubdef.CategoryDisplayPosition `json:"displayPosition"`
// 排序方式 0:上线时间降序 1:观看次数降序 2:点赞(收藏)次数降序 3:上线时间升序 4:观看次数升序 5:点赞(收藏)次数升序
SortType pubdef.CategorySortType `json:"sortType"`
// 展示方式
DisplayMode pubdef.DisplayMode `json:"displayMode"`
// URL地址
UrlValue string `json:"urlValue"`
}
// VideoInfo 视频信息
type VideoInfo struct {
ContentData
}
// ContentData 内容数据信息
type ContentData struct {
// id
Id int64 `json:"id"`
// 标题
Title string `json:"title"`
// slug
Slug string `json:"slug"`
// 上架时间
AddedTime time.Time `json:"addedTime"`
// 封面
CoverImg string `json:"coverImg"`
// 标签id
Tags []int64 `json:"tags"`
// 标签名称
TagsName []string `json:"tagsName"`
// 标签slug 与tagsName顺序一致
TagSlugs []string `json:"tagSlugs"`
// 观看展示数
WatchNum int64 `json:"watchNum"`
// 点赞展示数
LikeNum int64 `json:"likeNum"`
// 收藏展示数
CountCollect int64 `json:"countCollect,omitempty"`
// Seo相关信息
SeoInfo pubdef.SeoValue `json:"seoInfo"`
}
// RankResp 排行榜通用响应
type RankResp struct {
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
RankData HomeRankData `json:"rankData"`
}
// HomeRankData 首页排行榜数据(总榜/周榜/月榜/年榜)
type HomeRankData struct {
Total []ContentData `json:"total"` // 总榜
Week []ContentData `json:"week"` // 周榜
Month []ContentData `json:"month"` // 月榜
Year []ContentData `json:"year"` // 年榜
}
// ActressInfo 女优信息
type ActressInfo struct {
// Id
Id int64 `json:"id"`
// 别名
Alias string `json:"alias"`
// slug
Slug string `json:"slug"`
// 头像
Avatar string `json:"avatar"`
// 作品数
Works int64 `json:"works"`
// 热度值
HotValue int64 `json:"hotValue"`
}
+13
View File
@@ -0,0 +1,13 @@
package proto
// LawAndTrustHtmlData
type LawAndTrustHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
}
+380
View File
@@ -0,0 +1,380 @@
package proto
import (
"time"
"videoweb/pub/common/response"
"videoweb/pub/models/playletchaptermod"
"videoweb/pub/models/playletmod"
"videoweb/pub/pubdef"
"videoweb/pub/storage/proxy"
)
// PlayletRecommendListReq 推荐短剧分页请求
type PlayletRecommendListReq struct {
pubdef.Page
TagId int64 `form:"tagId" json:"tagId"` // 标签ID,不传查询全部标签
TagSlug string `form:"tagSlug" json:"tagSlug"` // 标签slug,非空时优先按slug解析标签ID
CategoryId int64 `form:"categoryId" json:"categoryId"` // 短剧分类ID,不传查询全部分类
CategorySlug string `form:"categorySlug" json:"categorySlug"` // 分类slug,非空时优先按slug解析分类ID
SortList int64 `form:"sortList" json:"sortList"` // 排序方式 1-推荐 2-最新 3-最热
}
// PlayletRecommendSort 推荐短剧排序方式
type PlayletRecommendSort int64
const (
PlayletRecommendSortRecommend PlayletRecommendSort = 1 // 推荐 后台配置 isRecommend=true
PlayletRecommendSortNewest PlayletRecommendSort = 2 // 最新 按短剧最后更新时间从近到远排序
PlayletRecommendSortHot PlayletRecommendSort = 3 // 最热 按短剧累计点击量从高到低排序
)
// PlayletRecommendItemType 推荐短剧列表项类型
type PlayletRecommendItemType int64
const (
PlayletRecommendItemTypePlaylet PlayletRecommendItemType = 0 // 短剧数据
PlayletRecommendItemTypeAdvertise PlayletRecommendItemType = 2 // 广告数据
)
// PlayletRecommendListResp 推荐短剧响应
type PlayletRecommendListResp struct {
response.BasePageResp
}
// PlayletThemeListResp 已启用短剧题材列表响应
type PlayletThemeListResp struct {
List []PlayletThemeItem `json:"list"` // 全部已启用题材
}
// PlayletThemeItem 短剧题材列表项
type PlayletThemeItem struct {
Id int64 `json:"id"` // 题材ID
Name string `json:"name"` // 题材名称
Slug string `json:"slug"` // 题材slug
Icon string `json:"icon"` // 题材图标完整地址
Rank int64 `json:"rank"` // 排序值,越大越靠前
SeoInfo pubdef.SeoValue `json:"seoInfo"` // SEO信息
}
// PlayletGuessListReq 猜你喜欢短剧分页请求
type PlayletGuessListReq struct {
pubdef.Page
Id int64 `form:"id" json:"id"` // 当前短剧ID,可选,传入时排除该短剧
}
// PlayletGuessListResp 猜你喜欢短剧分页响应
type PlayletGuessListResp struct {
response.BasePageResp
}
// PlayletListReq 短剧列表分页请求
type PlayletListReq struct {
pubdef.Page
ThemeId int64 `form:"themeId" json:"themeId"` // 题材 ID,不传查询全部题材
ThemeSlug string `form:"themeSlug" json:"themeSlug"` // 题材 slug,非空时优先于 themeId
SortType int64 `form:"sortType" json:"sortType"` // 排序方式,1 热度优先,2 最近更新,默认 1
}
// PlayletListResp 短剧与广告混排分页响应
type PlayletListResp struct {
response.BasePageResp
Advitise AdvitiseData `json:"advitise"` // 完整广告配置
}
// PlayletContentListReq 短剧或视频分页请求
type PlayletContentListReq struct {
pubdef.Page
DataType int64 `form:"dataType" json:"dataType"` // 数据类型,1 短剧,2 视频,必填
}
// PlayletContentListResp 短剧或视频与广告混排分页响应
type PlayletContentListResp struct {
response.BasePageResp
Advitise AdvitiseData `json:"advitise"` // 完整广告配置,postList 为列表广告
}
// PlayletContentListItem 短剧、视频或广告列表项
type PlayletContentListItem struct {
Type int64 `json:"type"` // 数据类型,0 内容,2 广告
Playlet *PlayletData `json:"playlet,omitempty"` // 短剧数据,dataType 为 1 且 type 为 0 时返回
Video *VideoInfo `json:"video,omitempty"` // 视频数据,dataType 为 2 且 type 为 0 时返回
Advertise *proxy.AdvitiseInfo `json:"advertise,omitempty"` // 广告数据,type 为 2 时返回
}
// PlayletRecommendListItem 推荐短剧列表项,type=0时返回短剧信息,type=2时返回广告信息
type PlayletRecommendListItem struct {
Type PlayletRecommendItemType `json:"type"` // 数据类型 0-短剧数据 2-广告
AdvertiseId string `json:"advertiseId"` // 广告ID,type=2时返回
Link string `json:"link"` // 广告跳转链接,type=2时返回
Location int64 `json:"location"` // 广告位置ID,type=2时返回
PlayletData
}
// LikePlayletReq 点赞或取消点赞短剧请求
type LikePlayletReq struct {
// ID
Id int64 `json:"id" binding:"required"`
// 是否点赞,true-点赞、false-取消点赞
IsLike *bool `json:"isLike" binding:"required"`
}
// LikePlayletResp 点赞或取消点赞短剧响应
type LikePlayletResp struct {
// ID
Id int64 `json:"id"`
// 是否点赞,true-点赞、false-取消点赞
IsLike bool `json:"isLike"`
// 点赞展示数
LikeNum int64 `json:"likeNum"`
}
// QueryLikePlayletListReq 当前用户点赞短剧分页请求
type QueryLikePlayletListReq struct {
pubdef.Page
}
// QueryLikePlayletListResp 当前用户点赞短剧分页响应
type QueryLikePlayletListResp struct {
response.BasePageResp
Translations AppTranslationInfo `json:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations"` // 底部翻译
}
// PlayletHistoryListReq 当前用户短剧观看历史分页请求
type PlayletHistoryListReq struct {
pubdef.Page
}
// PlayletHistoryReportReq 播放成功后上报短剧观看历史
type PlayletHistoryReportReq struct {
PlayletID int64 `json:"playletId" binding:"required,gt=0"` // 短剧 ID
ChapterID int64 `json:"chapterId" binding:"required,gt=0"` // 当前播放剧集 ID
}
// PlayletHistoryReportResp 短剧观看历史上报响应
type PlayletHistoryReportResp struct {
WatchedAt time.Time `json:"watchedAt"` // 最近观看时间
}
// PlayletHistoryListResp 当前用户短剧观看历史分页响应
type PlayletHistoryListResp struct {
response.BasePageResp
Translations AppTranslationInfo `json:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations"` // 底部翻译
}
// PlayletHistoryItem 短剧观看历史卡片
type PlayletHistoryItem struct {
PlayletData
ChapterID int64 `json:"chapterId"` // 最近观看剧集 ID
Episode int64 `json:"episode"` // 最近观看集数
WatchedAt time.Time `json:"watchedAt"` // 最近观看时间
}
// PlayletHistoryClearResp 清空短剧观看历史响应
type PlayletHistoryClearResp struct {
DeletedCount int64 `json:"deletedCount"` // 删除记录数
}
// FavoritePlayletReq 收藏或取消收藏短剧请求
type FavoritePlayletReq struct {
Id int64 `json:"id" binding:"required"` // 短剧ID
IsFavorite *bool `json:"isFavorite" binding:"required"` // true 收藏 false 取消收藏
}
// FavoritePlayletResp 收藏或取消收藏短剧响应
type FavoritePlayletResp struct {
Id int64 `json:"id"` // 短剧ID
IsFavorite bool `json:"isFavorite"` // 当前收藏状态
CountCollect int64 `json:"countCollect"` // 收藏展示数
}
// QueryFavoritePlayletListReq 当前用户收藏短剧分页请求
type QueryFavoritePlayletListReq struct {
pubdef.Page
}
// QueryFavoritePlayletListResp 当前用户收藏短剧分页响应
type QueryFavoritePlayletListResp struct {
response.BasePageResp
Translations AppTranslationInfo `json:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations"` // 底部翻译
}
// PlayletRankReq 短剧排行榜分页请求
type PlayletRankReq struct {
pubdef.Page
// 榜单类型 0-点赞榜 1-周榜 2-月榜 3-年榜
RankPeriod int64 `json:"rankPeriod" form:"rankPeriod"`
}
// PlayletRankPeriod 短剧排行榜类型
type PlayletRankPeriod int64
const (
PlayletRankPeriodLike PlayletRankPeriod = 0 // 点赞榜,按累计点赞量降序,最多50条,不足随机补位
PlayletRankPeriodWeek PlayletRankPeriod = 1 // 周榜,按本周观看量降序,最多50条,不足随机补位
PlayletRankPeriodMonth PlayletRankPeriod = 2 // 月榜,按本月观看量降序,最多50条,不足随机补位
PlayletRankPeriodYear PlayletRankPeriod = 3 // 年榜,按本年观看量降序,最多50条,不足随机补位
)
// PlayletRankResp 短剧排行榜分页响应
type PlayletRankResp struct {
response.BasePageResp
// 导航
Translations AppTranslationInfo `json:"translations"`
// 底部翻译
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
}
// PlayletRankData 短剧排行榜数据
type PlayletRankData struct {
PlayletData
// 榜单分数,点赞榜为累计展示点赞数,周/月/年榜为对应周期观看数
RankScore int64 `json:"rankScore"`
}
// QueryPlayletInfoReq 短剧详情请求
type QueryPlayletInfoReq struct {
// 短剧ID
Id int64 `json:"id" form:"id"`
// 短剧slug,非空时优先按slug解析短剧ID
Slug string `json:"slug" form:"slug"`
}
// QueryPlayletInfoResp 短剧详情响应
type QueryPlayletInfoResp struct {
FreeEpisodeCount int64 `json:"freeEpisodeCount"` // 官网开放集数 1至1000表示开放第1集到第N集 -1表示开放全集 未配置按2集返回
// 当前路径
Path string `json:"path"`
// 导航
Translations AppTranslationInfo `json:"translations"`
// 配置信息
Config ConfigInfo `json:"config"`
// 底部翻译
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
// 广告
Advitise AdvitiseData `json:"advitise"`
// 公告
Announcement AnnouncementInfo `json:"announcement"`
// 短剧详情数据
PlayletInfo PlayletDetailInfo `json:"playletInfo"`
// 剧集列表
ChapterList []PlayletChapterInfo `json:"chapterList"`
// 当前登录用户是否已点赞该短剧
IsLike bool `json:"isLike"`
// 当前登录用户是否已收藏该短剧
IsFavorite bool `json:"isFavorite"`
}
// QueryPlayletChapterInfoReq 短剧剧集详情请求
type QueryPlayletChapterInfoReq struct {
// 剧集ID
Id int64 `json:"id" form:"id" binding:"required"`
}
// QueryPlayletChapterInfoResp 短剧剧集详情响应
type QueryPlayletChapterInfoResp struct {
FreeEpisodeCount int64 `json:"freeEpisodeCount"` // 官网开放集数 1至1000表示开放第1集到第N集 -1表示开放全集 未配置按2集返回
// 当前路径
Path string `json:"path"`
// 导航
Translations AppTranslationInfo `json:"translations"`
// 配置信息
Config ConfigInfo `json:"config"`
// 底部翻译
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
// 广告
Advitise AdvitiseData `json:"advitise"`
// 公告
Announcement AnnouncementInfo `json:"announcement"`
// 当前剧集详情
ChapterInfo PlayletChapterInfo `json:"chapterInfo"`
// 所属短剧详情
PlayletInfo PlayletData `json:"playletInfo"`
// 剧集列表
ChapterList []PlayletChapterInfo `json:"chapterList"`
// 热门短剧列表
HotPlayletList []PlayletData `json:"hotPlayletList"`
// 当前登录用户是否已点赞该短剧
IsLike bool `json:"isLike"`
// 当前登录用户是否已收藏该短剧
IsFavorite bool `json:"isFavorite"`
}
// PlayletDetailInfo 短剧详情数据
type PlayletDetailInfo struct {
PlayletData
// 评论数量
CountComment int64 `json:"countComment"`
// 当前登录用户是否已点赞该短剧
IsLike bool `json:"isLike"`
// 当前登录用户是否已收藏该短剧
IsFavorite bool `json:"isFavorite"`
}
// PlayletChapterInfo 短剧剧集数据
type PlayletChapterInfo struct {
IsOfficialOpen *bool `json:"isOfficialOpen,omitempty"` // 本集是否在官网开放
Id int64 `json:"id"` // 剧集ID
PlayletId int64 `json:"playletId"` // 短剧ID
MediaContentId uint `json:"mediaContentId"` // 媒资中心章节ID
CurrentEpisode int64 `json:"currentEpisode"` // 第几集
Title string `json:"title"` // 章节名
Md5 string `json:"md5"` // 媒体md5
Hash string `json:"hash"` // 媒体hash
Height int64 `json:"height"` // 高
Width int64 `json:"width"` // 宽
Ratio float64 `json:"ratio"` // 宽高比
VideoUrl string `json:"videoUrl"` // 视频播放地址,优先返回水印地址
MediaSize int64 `json:"mediaSize"` // 资源大小
MediaTime int64 `json:"mediaTime"` // 影片长度(秒)
CountBrowse int64 `json:"countBrowse"` // 浏览数
CountCollect int64 `json:"countCollect"` // 收藏数
CountLike int64 `json:"countLike"` // 喜欢数
CountComment int64 `json:"countComment"` // 评论数
PayType playletchaptermod.PayType `json:"payType"` // 支付方式 0-免费 1-金币 2-VIP
SingleCoins int64 `json:"singleCoins"` // 单集金币
WatermarkStatus playletchaptermod.WatermarkStatus `json:"watermarkStatus"` // 水印状态 0-未处理 1-已登记 2-处理中 3-已完成
CreatedAt time.Time `json:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt"` // 修改时间
}
// PlayletData 短剧数据
type PlayletData struct {
Id int64 `json:"id"` // 短剧id
Status playletmod.Status `json:"status"` // 状态 0-下架 1-上架
IsRecommend bool `json:"isRecommend"` // 是否推荐 true-推荐 false-不推荐
IsNew bool `json:"isNew"` // 是否上新 本周内上架为true
IsFeatured bool `json:"isFeatured"` // 是否爆剧 后台设置
IsOriginal bool `json:"isOriginal"` // 是否原创 后台新增或无媒资中心ID
ShowOriginal bool `json:"showOriginal"` // 页面是否展示原创标识
OnlineAt time.Time `json:"onlineAt"` // 上架时间
MediaCreatedAt time.Time `json:"mediaCreatedAt"` // 媒资中心创建时间
MediaUpdatedAt time.Time `json:"mediaUpdatedAt"` // 媒资中心更新时间
Title string `json:"title"` // 标题
Slug string `json:"slug"` // slug
Desc string `json:"desc"` // 简介
Anchor string `json:"anchor"` // 作者或演员
Cover string `json:"cover"` // 封面,已拼接图片域名
Preview string `json:"preview"` // 预告,已拼接图片域名
TagIds []int64 `json:"tagIds"` // 标签ID集合
TagNames []string `json:"tagNames"` // 标签名称集合
TagSlugs []string `json:"tagSlugs"` // 标签slug集合 与tagNames顺序一致
ThemeIds []int64 `json:"themeIds"` // 题材ID集合
ThemeNames []string `json:"themeNames"` // 题材名称集合
ContentType playletmod.ContentType `json:"contentType"` // 内容类型 0-短剧 1-普通短剧影集 2-漫画短剧 3-动漫 4-漫画
PayType playletmod.PayType `json:"payType"` // 支付方式 0-免费 1-金币 2-VIP
SingleCoins int64 `json:"singleCoins"` // 单集金币,支付方式为金币时生效
TotalEpisode int64 `json:"totalEpisode"` // 总集数
UpdateStatus int `json:"updateStatus"` // 更新状态 1-连载中 2-已完结
CountBrowse int64 `json:"countBrowse"` // 观看展示数
HeatValue int64 `json:"heatValue"` // 热度值
CountCollect int64 `json:"countCollect"` // 收藏展示数
CountLike int64 `json:"countLike"` // 点赞展示数
VirtualCountLike int64 `json:"virtualCountLike"` // 后台虚拟点赞数
DisplayCountLike int64 `json:"displayCountLike"` // 点赞展示数
CreatedAt time.Time `json:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt"` // 修改时间
SeoInfo pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
}
+116
View File
@@ -0,0 +1,116 @@
package proto
import "videoweb/pub/pubdef"
// HomePlayletResponse 短剧首页数据。
type HomePlayletResponse struct {
HomeBannerData []*HomeBannerData `json:"homeBannerData"`
Modules []*HomeModuleData `json:"modules"`
Announcements []*AnnouncementItem `json:"announcements"`
Advitise AdvitiseData `json:"advitise"`
SeoInfo *pubdef.SeoValue `json:"seoInfo,omitempty"`
}
type HomeBannerData struct {
PlayletData
ShowOnBanner bool `json:"showOnBanner"`
Banner string `json:"banner"`
}
// HomeModuleData.List 根据 dataType 返回短剧或视频列表。
type HomeModuleData struct {
Id int64 `json:"id"`
Slug string `json:"slug"` // 页面路径标识
Title string `json:"title"`
Desc string `json:"desc"`
Label string `json:"label"`
Style string `json:"style"`
CardBackgroundImage string `json:"cardBackgroundImage"`
ModuleType int64 `json:"moduleType"`
DataType int64 `json:"dataType"`
RecommendType int64 `json:"recommendType"`
CategoryId int64 `json:"categoryId"`
Rank int64 `json:"rank"`
List any `json:"list"`
TopicList []*HomeTopicData `json:"topicList"`
}
type HomeTopicData struct {
Id int64 `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Icon string `json:"icon"`
Rank int64 `json:"rank"`
PlayletCount int64 `json:"playletCount"`
VideoCount int64 `json:"videoCount,omitempty"`
List any `json:"list"`
SeoInfo pubdef.SeoValue `json:"seoInfo"`
}
type HomeVideoData struct {
Id int64 `json:"id"`
Title string `json:"title"`
Slug string `json:"slug"`
Cover string `json:"cover"`
Desc string `json:"desc"`
Tags []int64 `json:"tags"`
WatchNum int64 `json:"watchNum"`
LikeNum int64 `json:"likeNum"`
SeoInfo pubdef.SeoValue `json:"seoInfo"`
}
type AnnouncementItem struct {
Id int64 `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
}
// PlayletHomeConfigListReq 首页配置内容分页请求
type PlayletHomeConfigListReq struct {
// pageNum 默认 1,pageSize 默认 20、最大 100
pubdef.Page
Id int64 `form:"id" json:"id"` // 首页配置 ID,与 slug 二选一
Slug string `form:"slug" json:"slug"` // 页面路径标识,和 ID 同时传时优先使用
}
// PlayletHomeConfigListResp 首页配置内容分页响应
type PlayletHomeConfigListResp struct {
Config *HomeModuleData `json:"config"` // 当前首页配置,不包含首页预览内容
TotalCount int64 `json:"totalCount"` // 符合配置条件的内容或专题总数
PageSize int `json:"pageSize"` // 每页条数
PageNum int `json:"pageNum"` // 当前页码
List any `json:"list"` // 普通模块内容,dataType 为 1 时是短剧,为 2 时是视频
TopicList []*HomeTopicData `json:"topicList"` // 专题模块内容,短剧按题材分组,视频按分类分组
Advitise AdvitiseData `json:"advitise"` // 广告配置
}
// PlayletTopicDetailReq 短剧题材或视频分类专题详情请求
type PlayletTopicDetailReq struct {
// pageNum 默认 1,pageSize 默认 12、最大 100
pubdef.Page
Id int64 `form:"id" json:"id"` // 专题 ID,dataType 为 1 时是题材 ID,为 2 时是视频分类 ID
TopicSlug string `form:"topicSlug" json:"topicSlug"` // 专题 slug,非空时优先于 id
DataType int64 `form:"dataType" json:"dataType"` // 数据类型,1 为短剧题材,2 为视频分类,默认 1
SortType int64 `form:"sortType" json:"sortType"` // 排序方式,1 编辑排序,2 最新,3 最热,默认 1
}
// PlayletTopicDetailResp 短剧题材或视频分类专题详情响应
type PlayletTopicDetailResp struct {
Id int64 `json:"id"` // 专题 ID
DataType int64 `json:"dataType"` // 数据类型,1 为短剧题材,2 为视频分类
Name string `json:"name"` // 专题名称
Slug string `json:"slug"` // 专题 slug
Desc string `json:"desc"` // 专题描述
Icon string `json:"icon"` // 题材图标地址,视频分类专题为空
Rank int64 `json:"rank"` // 专题排序值
PlayletCount int64 `json:"playletCount"` // 已上架短剧数量,视频专题为 0
VideoCount int64 `json:"videoCount,omitempty"` // 审核通过的视频数量,为 0 时省略
Covers []string `json:"covers"` // 顶部封面,最多 3 张
TotalCount int64 `json:"totalCount"` // 专题内符合条件的内容总数
PageSize int `json:"pageSize"` // 每页条数
PageNum int `json:"pageNum"` // 当前页码
List any `json:"list"` // 当前页内容,dataType 为 1 时是短剧,为 2 时是视频
MoreTopics []*HomeTopicData `json:"moreTopics"` // 同数据类型的其他专题,最多 3 个
SeoInfo *pubdef.SeoValue `json:"seoInfo"` // 专题 SEO 信息
Advitise AdvitiseData `json:"advitise"` // 广告配置
}
+19
View File
@@ -0,0 +1,19 @@
package proto
import "videoweb/pub/models/questionnairemod"
// QuestionnaireSubmitReq App端提交问卷请求
type QuestionnaireSubmitReq struct {
UserId int64 `json:"userId"` // 登录用户ID,0表示匿名(选填)
QuestionType string `json:"questionType" binding:"required"` // 问题类型:播放卡顿/缓冲、无法播放、画质模糊、音画不同步、加载失败、闪退/崩溃、登录异常、其他问题
Frequency string `json:"frequency" binding:"required"` // 出现频率:每次都会、经常出现、偶尔出现、仅现一次
Province string `json:"province" binding:"required"` // 所在省份(必填)
City string `json:"city"` // 所在城市(选填)
Operator string `json:"operator" binding:"required"` // 运营商:电信、联通、移动、广电
NetworkType string `json:"networkType" binding:"required"` // 网络类型:WI-FI、5G、4G、其他
DeviceType string `json:"deviceType" binding:"required"` // 设备类型:iPhone、Android、iPad、其他
DeviceModel string `json:"deviceModel"` // 设备型号(选填)
Description string `json:"description" binding:"required"` // 问题描述(必填)
Contact string `json:"contact"` // 联系方式(选填)
Attachments []questionnairemod.Attachment `json:"attachments"` // 附件列表,最多3个(选填)
}
+24
View File
@@ -0,0 +1,24 @@
package proto
import "videoweb/pub/pubdef"
type RichTextInfo struct {
Id int64 `json:"id" bson:"_id,omitempty"`
Title string `json:"title" bson:"title"` // 标题
Content string `json:"content" bson:"content"` // 内容
Desc string `json:"desc" bson:"desc"` // 标题(app)
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
}
// AppRichTextItemResp APP富文本内容列表项
type AppRichTextItemResp struct {
Id int64 `json:"id"` // 富文本ID
Title string `json:"title"` // 标题
Content string `json:"content"` // 内容
Desc string `json:"desc"` // 标题(app)
}
// AppRichTextListResp APP富文本内容列表响应
type AppRichTextListResp struct {
List []AppRichTextItemResp `json:"list"` // 富文本内容列表
}
+82
View File
@@ -0,0 +1,82 @@
package proto
type SearchSortType string
const (
SearchSortTypeDefault SearchSortType = "default" // 默认 相似度
SearchSortTypeHot SearchSortType = "hot" // 热度排序
SearchSortTypeNew SearchSortType = "new" // 最新排序
)
// RankType 排行榜类型
type RankType int64
const (
RankType_Video = 1 // 视频
RankType_Actress = 2 // 女优
RankType_Filmreview = 3 // 影评
)
// RankPeriod 排行榜周期
type RankPeriod int64
const (
RankPeriod_Week RankPeriod = 1
RankPeriod_Month RankPeriod = 2
RankPeriod_Year RankPeriod = 3
)
type SearchRankHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
VideoWeek SearchRankData `json:"videoWeek"`
ActressWeek SearchRankData `json:"actressWeek"`
FilmreviewWeek SearchRankData `json:"filmreviewWeek"`
VideoMonth SearchRankData `json:"videoMonth"`
ActressMonth SearchRankData `json:"actressMonth"`
FilmreviewMonth SearchRankData `json:"filmreviewMonth"`
VideoYear SearchRankData `json:"videoYear"`
ActressYear SearchRankData `json:"actressYear"`
FilmreviewYear SearchRankData `json:"filmreviewYear"`
}
type SearchRankData struct {
RankName string `json:"rankName" form:"rankName"` // 排行榜名字
RankType RankType `json:"rankType" form:"rankType"` // 排行榜类型 1视频, 2女优 ,3影评
RankPeriod RankPeriod `json:"rankPeriod" form:"rankPeriod"` // 排行榜周期 1=周 2=月 3=年
List []HotSearchItem `json:"list" form:"list"`
}
type HotSearchItem struct {
Id int64 `json:"id" form:"id"` // ID
Title string `json:"title" form:"title"` //标题
HotValue int64 `json:"hotValue" form:"hotValue"` // 热度值
}
type SearchResp struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
InTitle string `json:"inTitle"` //输入标题
InType int64 `json:"inType"` // 输入类型 -1=全部 0=视频 6=短剧
PageNum int64 `json:"pageNum" form:"pageNum"`
PageSize int64 `json:"pageSize" form:"pageSize"`
TotalSize int64 `json:"totalSize" form:"totalSize"`
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Sort []SearchSortItem `json:"sorts"` // 排序选项
SearchRecommend []string `json:"searchRecommend"` // 搜索推荐
Media []VideoInfoData `json:"media" form:"media"` // 视频资源
Playlets []PlayletData `json:"playlets" form:"playlets"` // 短剧资源
Config ConfigInfo `json:"config" form:"config"` // 配置文件
}
type SearchSortItem struct {
Key string `json:"key"` // 值
Title string `json:"title"` // 标题
}
+18
View File
@@ -0,0 +1,18 @@
package proto
import (
"encoding/xml"
"time"
)
type URL struct {
Loc string `xml:"loc"`
LastMod time.Time `xml:"lastmod"`
ChangeFreq string `xml:"changefreq"` // always/hourly/daily/weekly/monthly/yearly/never
Priority float32 `xml:"priority"` // 0.0 - 1.0
}
type Sitemap struct {
XMLName xml.Name `xml:"urlset"`
Xmlns string `xml:"xmlns,attr"`
URLs []URL `xml:"url"`
}
+25
View File
@@ -0,0 +1,25 @@
package proto
import "videoweb/pub/pubdef"
type AppTranslationInfo struct {
CategoryList []TranslationCategory `json:"categoryList" form:"categoryList"`
}
type TranslationCategory struct {
ID int64 `json:"id"`
Name string `json:"name" bson:"name"` // 名称
Icon string `json:"icon" bson:"icon"` // Icon
TranslationList []TranslationInfo `json:"translationList" form:"translationList"`
UrlValue string `json:"urlValue" bson:"urlValue"` // URl路径
CategoryType pubdef.TranslationType `json:"categoryType"` // 导航类型
}
type TranslationInfo struct {
ID int64 `json:"id"` // ID
Name string `json:"name" bson:"name"` // 名称
IsFriendAds bool `json:"isFriendAds"` // 是否是友链广告位
UrlValue string `json:"urlValue" bson:"urlValue"` // URl路径
TransCategoryId int64 `json:"-"` // 导航分类
DisplayMode pubdef.DisplayMode `json:"displayMode"` // 展示方式
}
+522
View File
@@ -0,0 +1,522 @@
package proto
import (
"time"
"videoweb/pub/common/netutil"
"videoweb/pub/common/response"
"videoweb/pub/models/videoinformationmod"
"videoweb/pub/pubdef"
)
// latestTime 返回两个时间中较大的那个
func latestTime(a, b time.Time) time.Time {
if b.After(a) {
return b
}
return a
}
type TagsInfoData struct {
Id int64 `json:"id" `
Name string `json:"name"` // 帖子标题
Slug string `json:"slug"` // slug
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
Works int64 `json:"works" bson:"works,omitempty"` // 作品数量
Images string `json:"images" bson:"images,omitempty"` // 背景
}
type CollectionInfoData struct {
Id int64 `json:"id" `
Name string `json:"name"` // 帖子标题
}
type VideoType int64
const (
VideoTypeVideo VideoType = 0 // 视频
VideoTypeCollection VideoType = 1 // 合集
VideoTypeAdvitise VideoType = 2 // 广告
VideoType_AV VideoType = 3 // AV视频
)
type VideoInfoData struct {
Id int64 `json:"id"`
Type VideoType `json:"type"` // 类型
Title string `json:"title"` // 帖子标题
Slug string `json:"slug"` // slug
Keyworld []string `json:"keyworld"` // 关键字
AddedTime time.Time `json:"addedTime"` // 帖子上架时间
CreateInfo PostCreateInfo `json:"createInfo"` // 作者信息
CoverImg string `json:"coverImg"` // 封面
// Nodes []videoinformationmod.Node `json:"nodes"` // 节点
Video videoinformationmod.VideoInfo `json:"video"` // 视频
Tags []TagsInfoData `json:"tags"` // 标签
IsHot bool `json:"isHot"` // 是否热门
AdvitiseId string `json:"advitiseId"` // 广告Id
CollectionInfo []VideoInfoData `json:"collectionInfo"` // 合集数据
Link string `json:"link"` // 跳转链接
WatchTimes int64 `json:"watchTimes" bson:"watchTimes"` // 观看次数
LikeNum int64 `json:"likeNum,omitempty"` // 点赞展示数
CountCollect int64 `json:"countCollect,omitempty"` // 收藏展示数
ShowTimes int64 `json:"showTimes" bson:"showTimes"` // 展示次数
Location int64 `json:"location" bson:"location"` // 广告位置id
ActressInfo []ActressInfoData `json:"actressInfo" bson:"actressInfo"` // 女优信息
IssuedAt time.Time `json:"issuedAt" bson:"issuedAt"` // 发行时间
IssuedBrand string `json:"issuedBrand" bson:"issuedBrand"` // 发行商
Desc string `bson:"desc,omitempty" json:"desc"` // 详细描述
Bango string `bson:"bango,omitempty" json:"bango"` // 番号,唯一
UpdatedAt time.Time `json:"updatedAt"` // 页面更新时间
PreviewVtt string `json:"previewVtt,omitempty"` // 雪碧图 vtt
}
// 面包屑
type BreadcrumbItem struct {
Name string `json:"name"` // 名称
Url string `json:"url"` // 跳转链接
}
// 详情页导航
type DetailNavItem struct {
Name string `json:"name"` // 导航名称
Url string `json:"url"` // 导航链接
}
type VideoHistoryInfo struct {
Id int64 `json:"id"`
Title string `json:"title"` // 帖子标题
AddedTime time.Time `json:"addedTime"` // 上架时间
}
type VideoCategoryInfo struct {
Id int64 `json:"id" `
Name string `json:"name"`
Slug string `json:"slug"` // slug
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
Title string `json:"title" bson:"title"` // APP显示
Desc string `json:"desc" bson:"desc"` // 描述
}
// VideoCategoryListResp 已启用视频分类列表响应
type VideoCategoryListResp struct {
List []VideoCategoryListItem `json:"list"` // 全部已启用视频分类
}
// VideoCategoryListItem 视频分类列表项
type VideoCategoryListItem struct {
Id int64 `json:"id"` // 分类ID
Name string `json:"name"` // 分类名称
Slug string `json:"slug"` // 分类slug
Title string `json:"title"` // APP展示标题
Desc string `json:"desc"` // 分类描述
Rank int64 `json:"rank"` // 排序值,越大越靠前
SeoInfo pubdef.SeoValue `json:"seoInfo"` // SEO信息
}
type VideoPlayReq struct {
VideoId int64 `json:"videoId" form:"videoId"` // 视频ID
}
type VideoPlayResp struct {
AuthKey string `json:"authKey"`
}
type VideoCreaterInfo struct {
Id int64 `json:"id" `
Name string `json:"name"`
Slug string `json:"slug"` // slug
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
}
// QueryVideoReq 根据分类id查询视频列表请求
type QueryVideoReq struct {
pubdef.Page
// 视频分类id
CategoryId int64 `json:"categoryId" form:"categoryId"`
// 分类slug,非空时优先按slug解析分类ID
CategorySlug string `json:"categorySlug" form:"categorySlug"`
}
// QueryVideoItemType 视频更多列表项类型
type QueryVideoItemType int64
const (
// QueryVideoItemTypeVideo 表示视频数据
QueryVideoItemTypeVideo QueryVideoItemType = 0
// QueryVideoItemTypeAdvertise 表示广告数据
QueryVideoItemTypeAdvertise QueryVideoItemType = 2
)
// QueryVideoResp 视频更多分页响应
type QueryVideoResp struct {
response.BasePageResp
// 当前分类信息(含 SEO)
CategoryInfo VideoCategoryInfo `json:"categoryInfo"`
// 导航
Translations AppTranslationInfo `json:"translations"`
// 底部翻译
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
}
// QueryVideoListItem 视频更多列表项,type=0时返回视频信息,type=2时返回广告信息。
type QueryVideoListItem struct {
// 数据类型:0-视频数据、2-广告
Type QueryVideoItemType `json:"type"`
// 广告ID,type=2时返回
AdvertiseId string `json:"advertiseId"`
// 广告跳转链接,type=2时返回
Link string `json:"link"`
// 广告位置ID,type=2时返回
Location int64 `json:"location"`
VideoInfo
}
// VideoRecommendListReq 推荐视频分页请求
type VideoRecommendListReq struct {
pubdef.Page
// 分类id,不传查询全部分类id
CategoryId int64 `form:"categoryId" json:"categoryId"`
// 分类slug,非空时优先按slug解析分类ID
CategorySlug string `form:"categorySlug" json:"categorySlug"`
// 标签ID,不传查询全部标签
TagId int64 `form:"tagId" json:"tagId"`
// 标签slug,非空时优先按slug解析标签ID
TagSlug string `form:"tagSlug" json:"tagSlug"`
// 排序方式 1-推荐 2-最新 3-最热
SortList int64 `form:"sortList" json:"sortList"`
}
// VideoListReq 上架视频分页请求
type VideoListReq struct {
pubdef.Page
CategoryId int64 `form:"categoryId" json:"categoryId"` // 视频分类 ID,不传查询全部分类
SortType int64 `form:"sortType" json:"sortType"` // 排序方式,1 热度优先,2 最近更新,默认 1
}
// VideoListResp 视频与广告混排分页响应
type VideoListResp struct {
response.BasePageResp
Advitise AdvitiseData `json:"advitise"` // 完整广告配置
}
// VideoRecommendSort 推荐视频排序方式
type VideoRecommendSort int64
const (
VideoRecommendSortRecommend VideoRecommendSort = 1 // 推荐 后台配置 isRecommend=true
VideoRecommendSortNewest VideoRecommendSort = 2 // 最新 按视频最后更新时间从近到远排序
VideoRecommendSortHot VideoRecommendSort = 3 // 最热 按视频累计播放量从高到低排序
)
// VideoRecommendItemType 推荐视频列表项类型
type VideoRecommendItemType int64
const (
VideoRecommendItemTypeVideo VideoRecommendItemType = 0 // 视频数据
VideoRecommendItemTypeAdvertise VideoRecommendItemType = 2 // 广告数据
)
// VideoRecommendListResp 推荐视频分页响应
type VideoRecommendListResp struct {
response.BasePageResp
}
// VideoGuessListReq 猜你喜欢视频分页请求
type VideoGuessListReq struct {
pubdef.Page
Id int64 `form:"id" json:"id"` // 当前视频ID,可选,传入时排除该视频
}
// VideoGuessListResp 猜你喜欢视频分页响应
type VideoGuessListResp struct {
response.BasePageResp
}
// VideoRecommendListItem 推荐视频列表项
type VideoRecommendListItem struct {
Type VideoRecommendItemType `json:"type"` // 数据类型 0-视频数据 2-广告
AdvertiseId string `json:"advertiseId"` // 广告ID,type=2时返回
Link string `json:"link"` // 广告跳转链接,type=2时返回
Location int64 `json:"location"` // 广告位置ID,type=2时返回
VideoInfo
}
// FavoriteVideoReq 收藏或取消收藏视频请求
type FavoriteVideoReq struct {
// ID
Id int64 `json:"id" binding:"required"`
// 是否收藏,true-收藏、false-取消收藏
IsFavorite *bool `json:"isFavorite" binding:"required"`
}
// FavoriteVideoResp 收藏或取消收藏视频响应
type FavoriteVideoResp struct {
// ID
Id int64 `json:"id"`
// 是否收藏,true-收藏、false-取消收藏
IsFavorite bool `json:"isFavorite"`
}
// LikeVideoReq 点赞或取消点赞视频请求
type LikeVideoReq struct {
// ID
Id int64 `json:"id" binding:"required"`
// 是否点赞,true-点赞、false-取消点赞
IsLike *bool `json:"isLike" binding:"required"`
}
// LikeVideoResp 点赞或取消点赞视频响应
type LikeVideoResp struct {
// ID
Id int64 `json:"id"`
// 是否点赞,true-点赞、false-取消点赞
IsLike bool `json:"isLike"`
// 点赞展示数
LikeNum int64 `json:"likeNum"`
}
// QueryLikeVideoListReq 当前用户点赞视频分页请求
type QueryLikeVideoListReq struct {
pubdef.Page
}
// QueryLikeVideoListResp 当前用户点赞视频分页响应
type QueryLikeVideoListResp struct {
response.BasePageResp
Translations AppTranslationInfo `json:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations"` // 底部翻译
}
// VideoHistoryListReq 当前用户视频观看历史分页请求
type VideoHistoryListReq struct {
pubdef.Page
}
// VideoHistoryReportReq 播放成功后上报视频观看历史
type VideoHistoryReportReq struct {
Id int64 `json:"id" binding:"required,gt=0"` // 视频 ID
}
// VideoHistoryReportResp 视频观看历史上报响应
type VideoHistoryReportResp struct {
WatchedAt time.Time `json:"watchedAt"` // 最近观看时间
}
// VideoHistoryListResp 当前用户视频观看历史分页响应
type VideoHistoryListResp struct {
response.BasePageResp
Translations AppTranslationInfo `json:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations"` // 底部翻译
}
// VideoHistoryItem 视频观看历史卡片
type VideoHistoryItem struct {
FavoriteVideoListItem
Desc string `json:"desc"` // 视频简介
WatchedAt time.Time `json:"watchedAt"` // 最近观看时间
}
// VideoHistoryClearResp 清空视频观看历史响应
type VideoHistoryClearResp struct {
DeletedCount int64 `json:"deletedCount"` // 删除记录数
}
// QueryFavoriteVideoListReq 当前登录用户收藏视频分页请求
type QueryFavoriteVideoListReq struct {
pubdef.Page
}
// QueryFavoriteVideoListResp 当前登录用户收藏视频分页响应
type QueryFavoriteVideoListResp struct {
response.BasePageResp
// 导航
Translations AppTranslationInfo `json:"translations"`
// 底部翻译
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
}
// FavoriteVideoListItem 当前登录用户收藏视频列表项
type FavoriteVideoListItem struct {
// id
Id int64 `json:"id"`
// 标题
Title string `json:"title"`
// slug
Slug string `json:"slug"`
// 上架时间
AddedTime time.Time `json:"addedTime"`
// 封面
CoverImg string `json:"coverImg"`
// 标签id
Tags []int64 `json:"tags"`
// 标签名称
TagsName []string `json:"tagsName"`
// 标签slug 与tagsName顺序一致
TagSlugs []string `json:"tagSlugs"`
// 观看展示数
WatchNum int64 `json:"watchNum"`
// 点赞展示数
LikeNum int64 `json:"likeNum"`
// 收藏展示数
CountCollect int64 `json:"countCollect"`
}
// VideoRankReq 视频排行榜分页请求
type VideoRankReq struct {
pubdef.Page
// 榜单类型 0-点赞榜 1-周榜 2-月榜 3-年榜
RankPeriod int64 `json:"rankPeriod" form:"rankPeriod"`
}
// VideoRankPeriod 视频排行榜类型
type VideoRankPeriod int64
const (
VideoRankPeriodLike VideoRankPeriod = 0 // 点赞榜,按累计点赞量降序,最多50条,不足随机补位
VideoRankPeriodWeek VideoRankPeriod = 1 // 周榜,按本周观看量降序,最多50条,不足随机补位
VideoRankPeriodMonth VideoRankPeriod = 2 // 月榜,按本月观看量降序,最多50条,不足随机补位
VideoRankPeriodYear VideoRankPeriod = 3 // 年榜,按本年观看量降序,最多50条,不足随机补位
)
// VideoRankResp 视频排行榜分页响应
type VideoRankResp struct {
response.BasePageResp
// 导航
Translations AppTranslationInfo `json:"translations"`
// 底部翻译
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
}
// QueryVideoInfoReq 视频详情请求
type QueryVideoInfoReq struct {
Id int64 `json:"id" form:"id"`
// 视频slug,非空时优先按slug解析视频ID
Slug string `json:"slug" form:"slug"`
}
// QueryVideoInfoResp 视频详情响应
type QueryVideoInfoResp struct {
// 当前路径
Path string `json:"path"`
// 导航
Translations AppTranslationInfo `json:"translations"`
// 配置信息
Config ConfigInfo `json:"config"`
// 底部翻译
BottonTranslations AppTranslationInfo `json:"bottonTranslations"`
// 广告
Advitise AdvitiseData `json:"advitise"`
// 公告
Announcement AnnouncementInfo `json:"announcement"`
// 视频详情数据
VideoInfo VideoDetailInfo `json:"videoInfo"`
// 当前登录用户是否已收藏该视频
IsFavorite bool `json:"isFavorite"`
// 当前登录用户是否已点赞该视频
IsLike bool `json:"isLike"`
}
// VideoDetailInfo 视频详情数据
type VideoDetailInfo struct {
// id
Id int64 `json:"id"`
// 标题
Title string `json:"title"`
// slug
Slug string `json:"slug"`
// 封面
CoverImg string `json:"coverImg"`
// 视频播放信息
Video videoinformationmod.VideoInfo `json:"video"`
// 标签
Tags []TagsInfoData `json:"tags"`
// 观看展示数
WatchNum int64 `json:"watchNum"`
// 点赞展示数
LikeNum int64 `json:"likeNum"`
// 收藏展示数
CountCollect int64 `json:"countCollect"`
// 上架时间
AddedTime time.Time `json:"addedTime"`
// 作品简介
Desc string `json:"desc"`
// 当前登录用户是否已收藏该视频
IsFavorite bool `json:"isFavorite"`
// 当前登录用户是否已点赞该视频
IsLike bool `json:"isLike"`
}
func VideoInfoToData(videoInfo *videoinformationmod.VideoInformation, imgCdn string, creatorInfo PostCreateInfo) VideoInfoData {
t := VideoTypeVideo
switch videoInfo.MediaType {
case videoinformationmod.MediaType_Video:
t = VideoTypeVideo
case videoinformationmod.MediaType_Collection:
t = VideoTypeCollection
case videoinformationmod.MediaType_Advitise:
t = VideoTypeAdvitise
case videoinformationmod.MediaType_AV:
t = VideoType_AV
}
videotemp := VideoInfoData{
Id: videoInfo.Id,
Type: t,
Title: videoInfo.Title,
Slug: videoInfo.Slug,
Keyworld: videoInfo.Keyworld,
AddedTime: videoInfo.AddedTime,
CreateInfo: creatorInfo,
CoverImg: netutil.MergeURL(imgCdn, videoInfo.CoverImg),
// Nodes: make([]videoinformationmod.Node, 0),
Video: videoInfo.Video,
IsHot: videoInfo.IsHot,
Tags: make([]TagsInfoData, 0),
ShowTimes: videoInfo.Real.ShowTimes*100 + 6241,
WatchTimes: videoInfo.Real.WatchTimes*100 + 3152,
ActressInfo: make([]ActressInfoData, 0),
Desc: videoInfo.Desc,
Bango: videoInfo.Bango,
IssuedBrand: videoInfo.IssuedBrand,
IssuedAt: videoInfo.IssuedAt,
UpdatedAt: latestTime(videoInfo.UpdatedAt, videoInfo.PageUpdatedAt),
PreviewVtt: videoInfo.PreviewVtt,
}
if videoInfo.Video.Cover != "" {
videotemp.Video.Cover = netutil.MergeURL(imgCdn, videotemp.Video.Cover)
}
//for _, nodeInfo := range videoInfo.Nodes {
// nodeTmp := videoinformationmod.Node{
// Images: make([]string, 0),
// Url: nodeInfo.Url,
// Text: nodeInfo.Text,
// Videos: make([]videoinformationmod.VideoInfo, 0),
// Title: nodeInfo.Title,
// }
// for _, image := range nodeInfo.Images {
// nodeTmp.Images = append(nodeTmp.Images, netutil.MergeURL(imgCdn, image))
// }
// if nodeInfo.Videos != nil && len(nodeInfo.Videos) > 0 {
// for _, video := range nodeInfo.Videos {
// videoTmp := videoinformationmod.VideoInfo{
// TaskId: video.TaskId,
// FileId: video.FileId,
// Url: netutil.MergeURL(imgCdn, video.Url),
// Cover: video.Cover,
// Height: video.Height,
// Width: video.Width,
// VideoTime: video.VideoTime,
// PreMp4FileNameFs: video.PreMp4FileNameFs,
// }
// nodeTmp.Videos = append(nodeTmp.Videos, videoTmp)
// }
// }
// videotemp. = append(videotemp.Nodes, nodeTmp)
//}
return videotemp
}
// StripH265Url 清空主视频 H265 地址。
func StripH265Url(data *VideoInfoData) {
if data == nil {
return
}
data.Video.H265Url = ""
}
+212
View File
@@ -0,0 +1,212 @@
package proto
import (
"time"
"videoweb/pub/models/videoinformationmod"
"videoweb/pub/pubdef"
)
// HomeHtmlData 首页
type HomeHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"` // 请求路径
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
}
type VideoCategoryData struct {
Id int64 `json:"id" form:"id"`
Name string `json:"name" form:"name"`
Slug string `json:"slug"`
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"`
}
type VideoCategoryHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
VideoCategory VideoCategoryData `json:"videoCategory" form:"videoCategory"` // 当前分类数据
}
type CategoryVideoListHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Translation TranslationInfo `json:"translation" form:"translation"` // 当前导航数据
CategoryList []VideoCategoryData `json:"categoryList" form:"categoryList"`
}
type VideoCategoryListHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Translation TranslationInfo `json:"translation" form:"translation"` // 当前导航数据
CategoryList []VideoCategoryInfo `json:"categoryList" form:"categoryList"`
PageNum int64 `json:"pageNum" form:"pageNum"`
PageSize int64 `json:"pageSize" form:"pageSize"`
TotalSize int64 `json:"totalSize" form:"totalSize"`
}
type VideoDetailsHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Video VideoInfoData `json:"video" form:"video"` // 视频详情
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
CommentList GetCommentListResp `json:"commentList" form:"commentList"` // 评论
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜标签
RecommendVideos []VideoInfoData `json:"recommendVideos" form:"recommendVideos"` // 推荐视频
ChoiceVideos []VideoInfoData `json:"choiceVideos" form:"choiceVideos"` // 精选视频
Breadcrumbs []BreadcrumbItem `json:"breadcrumbs" form:"breadcrumbs"` // 面包屑
DetailNavs []DetailNavItem `json:"detailNavs" form:"detailNavs"` // 详情页导航
}
// CreateVideoListHtmlData 创作者视频列表
type CreateVideoListHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
CreateInfo PostCreateInfo `json:"createInfo" bson:"createInfo"` // 创作者信息
VideoList []VideoInfoData `json:"videoList" form:"videoList"`
PageNum int64 `json:"pageNum" form:"pageNum"`
PageSize int64 `json:"pageSize" form:"pageSize"`
TotalSize int64 `json:"totalSize" form:"totalSize"`
}
type PostCreateInfo struct {
Id int64 `json:"id" form:"id"`
Name string `json:"name" form:"name"`
Slug string `json:"slug"` // slug
Image string `json:"image" form:"image"` //头像
Works int64 `json:"works" form:"works"`
CreateType int64 `json:"createType"` // 创作者类型 0=普通 1=官方
Desc string `json:"desc" form:"desc"` // 作者描述
Background string `json:"background"` // 背景
CreatedAt time.Time `json:"createdAt"` // 创建时间
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
}
// TagHtmlData 首页
type TagHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Media []VideoInfoData `json:"media" form:"media"` // 视频资源
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Tag TagsInfoData `json:"tag" form:"tag"` // 标签
SortItem []videoinformationmod.VideoSortItem `json:"sortItem" form:"sortItem"` // 排序项
SortValue videoinformationmod.VideoSortItem `json:"sortValue" form:"sortValue"` // 当前排序项
PageNum int64 `json:"pageNum" form:"pageNum"`
PageSize int64 `json:"pageSize" form:"pageSize"`
TotalSize int64 `json:"totalSize" form:"totalSize"`
}
type VideoTagHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Tags []TagsInfoData `json:"tags" form:"tags"`
PageNum int64 `json:"pageNum" form:"pageNum"`
PageSize int64 `json:"pageSize" form:"pageSize"`
TotalSize int64 `json:"totalSize" form:"totalSize"`
}
type VideoHistoryHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
Tags []TagsInfoData `json:"tags" form:"tags"` // 标签
Media []VideoHistoryInfo `json:"media" form:"media"` // 视频
PageNum int64 `json:"pageNum" form:"pageNum"`
PageSize int64 `json:"pageSize" form:"pageSize"`
TotalSize int64 `json:"totalSize" form:"totalSize"`
}
type RichTextHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
RichTextInfo RichTextInfo `json:"richTextInfo" form:"richTextInfo"` // 富文本
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
}
type NotFoundHtmlData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
RichTextInfo RichTextInfo `json:"richTextInfo" form:"richTextInfo"` // 富文本
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
}
type UrlRedirectData struct {
Path string `json:"path"`
CompletePath string `json:"completePath" form:"completePath"`
Translations AppTranslationInfo `json:"translations" form:"translations"` // 导航
BottonTranslations AppTranslationInfo `json:"bottonTranslations" form:"bottonTranslations"` // 底部导航
Config ConfigInfo `json:"config" form:"config"` // 配置文件
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"` // 公告
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"` // 热搜
Category VideoCategoryInfo `json:"category" form:"category"` // 分类
UrlRedirect string `json:"urlRedirect" form:"urlRedirect"`
}
type ContactUsReq struct {
Name string `json:"name" form:"name"` // 姓名
Email string `json:"email" form:"email"` // 邮件
Content string `json:"content" form:"content"` // 内容
CategoryName string `json:"categoryName" form:"categoryName"` // 主旨分类
}
// QuestionnaireHtmlData 问卷调查页
type QuestionnaireHtmlData struct {
Path string `json:"path"`
Translation AppTranslationInfo `json:"translation" form:"translation"`
Config ConfigInfo `json:"config" form:"config"`
Advitise AdvitiseData `json:"advitise" form:"advitise"` // 广告
Announcement AnnouncementInfo `json:"announcement" form:"announcement"`
HotSearch []*HotSearchItem `json:"hotSearch" form:"hotSearch"`
}
+27
View File
@@ -0,0 +1,27 @@
package questionnaireapi
import (
"videoweb/app/api/proto"
"videoweb/app/service/configser"
"videoweb/app/service/searchser"
"videoweb/app/service/translationser"
"github.com/gin-gonic/gin"
)
// Page 问卷调查页
func Page(c *gin.Context) {
hotSearch := searchser.GetHotSearchItem(c)
data := proto.QuestionnaireHtmlData{
Path: c.Request.URL.Path,
Translation: translationser.GetTranslationData(),
Config: configser.GetRequestConfig(c),
Advitise: configser.GetAdvitise(),
Announcement: configser.GetAnnouncement(),
HotSearch: hotSearch,
}
configser.RewriteImageCdn(c, &data)
c.HTML(200, "questionnaire", gin.H{
"data": data,
})
}
+34
View File
@@ -0,0 +1,34 @@
package questionnaireapi
import (
"videoweb/app/api/proto"
"videoweb/app/service/questionnaireser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// Submit 提交问卷
// @Tags 问卷调查APP
// @Summary 提交问卷
// @Description 用户提交问题反馈问卷
// @Accept json
// @Produce json
// @Param param body proto.QuestionnaireSubmitReq true "提交参数"
// @Success 200 {string} string "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/questionnaire/submit [post]
func Submit(ctx *gin.Context) {
var req proto.QuestionnaireSubmitReq
if err := ctx.ShouldBindJSON(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
serr := questionnaireser.Submit(ctx, ctx.ClientIP(), &req)
if serr != nil {
common.ServerJSON(ctx, serr, serr.Tips)
return
}
common.ServerJSON(ctx, srvdef.Success, nil)
}
+36
View File
@@ -0,0 +1,36 @@
package richtextapi
import (
"videoweb/app/service/richtextser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
type getByTitleReq struct {
Title string `form:"title" binding:"required"`
}
// GetByTitle 按 title 查询富文本
// @Tags 富文本
// @Summary 按 title 查询富文本
// @Description 从缓存中查询启用状态的富文本信息
// @Produce json
// @Param title query string true "富文本内部标题"
// @Success 200 {object} proto.RichTextInfo "成功"
// @Failure 400 {string} string "失败"
// @Router /api/app/richtext [get]
func GetByTitle(ctx *gin.Context) {
var req getByTitleReq
if err := ctx.ShouldBindQuery(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
data, serr := richtextser.GetByTitle(req.Title)
if serr != nil {
common.ServerJSON(ctx, serr.Code, serr.Tips)
return
}
common.ServerJSON(ctx, srvdef.Success, data)
}
+53
View File
@@ -0,0 +1,53 @@
package searchapi
import (
"fmt"
"strconv"
"videoweb/app/api/proto"
"videoweb/app/service/configser"
"videoweb/app/service/searchser"
"videoweb/app/service/translationser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// SearchApi 搜索
// @Tags 搜索
// @Summary 搜索
// @Description 搜索视频和短剧,省略 type 查询全部,type 为 0 查询视频,为 6 查询短剧,sort 支持 default/hot/new
// @Accept json
// @Produce json
// @Param title query string false "搜索关键词"
// @Param page query int false "页码,默认1"
// @Param type query int false "媒体类型,不传=全部,0=视频,6=短剧"
// @Param sort query string false "排序方式 default/hot/new,默认default"
// @Success 200 {object} proto.SearchResp "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /search [get]
func SearchApi(c *gin.Context) {
title := c.Query("title")
pageStr := c.DefaultQuery("page", "1")
sort := c.DefaultQuery("sort", string(proto.SearchSortTypeDefault))
mediaType := int64(-1)
if typeStr, ok := c.GetQuery("type"); ok {
var err error
mediaType, err = strconv.ParseInt(typeStr, 10, 64)
if err != nil || (mediaType != 0 && mediaType != 6) {
common.ServerJSON(c, srvdef.ErrParamError, "type 只支持 0 或 6")
return
}
}
page, err := strconv.ParseInt(pageStr, 10, 64)
if err != nil || page < 1 {
page = 1
}
data := searchser.Search(c, title, mediaType, page, sort)
data.Path = c.Request.URL.Path
data.CompletePath = fmt.Sprintf("/search")
data.Advitise = configser.GetAdvitise()
data.BottonTranslations = translationser.GetTranslationBottomList()
data.Translations = translationser.GetTranslationData()
common.JSONWriterCache(c, srvdef.Success, data)
}
+29
View File
@@ -0,0 +1,29 @@
package searchapi
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
func TestSearchApiRejectsUnsupportedTypes(t *testing.T) {
for _, query := range []string{"type=1", "type=3", "type=2", "type=-1", "type=abc", "type="} {
writer := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(writer)
ctx.Request = httptest.NewRequest(http.MethodGet, "/search/?"+query, nil)
SearchApi(ctx)
var resp struct {
Code int64 `json:"code"`
}
if err := json.Unmarshal(writer.Body.Bytes(), &resp); err != nil {
t.Fatalf("参数 %s 的响应无法解析: %v", query, err)
}
if resp.Code != int64(srvdef.ErrParamError) {
t.Errorf("参数 %s 返回 code %d, want %d", query, resp.Code, srvdef.ErrParamError)
}
}
}
+128
View File
@@ -0,0 +1,128 @@
package uploadapi
import (
"net/http"
"videoweb/app/service/uploadser"
"videoweb/pub/common"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// VideoBody 分片上传视频
// @Tags 上传
// @Summary 视频分片上传
// @Description 将视频分片转发至存储服务 /media/web/autopublish/videoBody
// @Accept multipart/form-data
// @Produce json
// @Param taskId formData string true "视频任务ID"
// @Param pos formData string true "当前分片序号,从0开始"
// @Param uploadUserName formData string false "上传用户名,为空默认 questionnaires"
// @Param file formData file true "分片文件数据"
// @Success 200 {object} uploadser.VideoBodyResp "成功"
// @Failure 400 {string} string "参数错误"
// @Router /api/app/upload/videoBody [post]
func VideoBody(ctx *gin.Context) {
form, err := ctx.MultipartForm()
if err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
taskIds := form.Value["taskId"]
posList := form.Value["pos"]
uploadUserNames := form.Value["uploadUserName"]
fileList := form.File["file"]
if len(taskIds) == 0 || taskIds[0] == "" {
common.ServerJSON(ctx, srvdef.ErrParamError, "taskId 不能为空")
return
}
if len(posList) == 0 || posList[0] == "" {
common.ServerJSON(ctx, srvdef.ErrParamError, "pos 不能为空")
return
}
if len(fileList) == 0 {
common.ServerJSON(ctx, srvdef.ErrParamError, "file 不能为空")
return
}
param := &uploadser.VideoBodyParam{
TaskId: taskIds[0],
Pos: posList[0],
FileHeader: fileList[0],
}
if len(uploadUserNames) > 0 {
param.UploadUserName = uploadUserNames[0]
}
respBytes, err := uploadser.ForwardVideoBody(param)
if err != nil {
log.Error("VideoBody forward failed", log.E(err))
common.ServerJSON(ctx, srvdef.ServerError, nil)
return
}
ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBytes)
}
// VideoOk 通知视频分片上传完成
// @Tags 上传
// @Summary 视频分片上传完成通知
// @Description 所有分片上传完毕后调用,转发至存储服务 /media/web/autopublish/videoOk
// @Accept json
// @Produce json
// @Param param body object true "{ \"taskId\": \"...\" }"
// @Success 200 {object} uploadser.VideoOkResp "成功"
// @Failure 400 {string} string "参数错误"
// @Router /api/app/upload/videoOk [post]
func VideoOk(ctx *gin.Context) {
var req struct {
TaskId string `json:"taskId" binding:"required"`
}
if err := ctx.ShouldBindJSON(&req); err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
return
}
respBytes, err := uploadser.ForwardVideoOk(req.TaskId)
if err != nil {
log.Error("VideoOk forward failed", log.E(err))
common.ServerJSON(ctx, srvdef.ServerError, nil)
return
}
ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBytes)
}
// UploadImage 上传图片
// @Tags 上传
// @Summary 图片上传
// @Description 将图片转发至存储服务 /media/web/autopublish/image
// @Accept multipart/form-data
// @Produce json
// @Param file formData file true "图片文件"
// @Success 200 {object} uploadser.ImageUploadResp "成功"
// @Failure 400 {string} string "参数错误"
// @Router /api/app/upload/image [post]
func UploadImage(ctx *gin.Context) {
f, err := ctx.FormFile("file")
if err != nil {
common.ServerJSON(ctx, srvdef.ErrParamError, "file 不能为空")
return
}
param := &uploadser.ImageParam{
FileHeader: f,
}
respBytes, err := uploadser.ForwardImage(param)
if err != nil {
log.Error("UploadImage forward failed", log.E(err))
common.ServerJSON(ctx, srvdef.ServerError, nil)
return
}
ctx.Data(http.StatusOK, "application/json; charset=utf-8", respBytes)
}
+428
View File
@@ -0,0 +1,428 @@
package videoapi
import (
"videoweb/app/api/proto"
"videoweb/app/service/configser"
"videoweb/app/service/slugser"
"videoweb/app/service/translationser"
"videoweb/app/service/videoser"
"videoweb/pub/common"
"videoweb/pub/common/srvdef"
"github.com/gin-gonic/gin"
)
// List app端上架视频列表
// @Tags 视频相关接口
// @Summary app端上架视频列表 -- by 王鸣
// @Description 按分类和排序分页查询上架视频,最近更新按更新时间降序,每五条视频后穿插一条广告
// @Accept json
// @Produce json
// @Param params query proto.VideoListReq true "视频列表请求"
// @Success 200 {object} proto.VideoListResp{list=[]proto.VideoRecommendListItem} "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/video/list [get]
func List(c *gin.Context) {
var req proto.VideoListReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
data, err := videoser.VideoList(c, &req)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// CategoryList 查询全部已启用视频分类
// @Tags 视频相关接口
// @Summary app端视频分类列表
// @Produce json
// @Success 200 {object} proto.VideoCategoryListResp "成功"
// @Router /api/app/video/category/list [get]
func CategoryList(c *gin.Context) {
resp, err := videoser.VideoCategoryList(c)
if err != nil {
common.ServerJSON(c, err, err.GetMsg())
return
}
common.ServerJSON(c, srvdef.Success, resp)
}
// RecommendList app端推荐视频列表
// @Tags 视频相关接口
// @Summary app端推荐视频列表 -- by 王鸣
// @Description 分页查询视频列表,带穿插列表广告,每间隔8条视频数据插入一个广告
// @Accept json
// @Produce json
// @Param params query proto.VideoRecommendListReq true "推荐视频列表请求"
// @Success 200 {object} proto.VideoRecommendListResp{list=[]proto.VideoRecommendListItem} "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/video/recommend/list [get]
func RecommendList(c *gin.Context) {
var req proto.VideoRecommendListReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
data, err := videoser.VideoRecommendList(c, &req)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// GuessList 分页查询猜你喜欢视频
// @Tags 视频相关接口
// @Summary 猜你喜欢视频列表 -- by 王鸣
// @Description id可选,传入时排除当前视频,按展示观看量降序查询上架视频
// @Produce json
// @Param params query proto.VideoGuessListReq true "猜你喜欢视频请求"
// @Success 200 {object} proto.VideoGuessListResp{list=[]proto.VideoRecommendListItem} "成功"
// @Router /api/app/video/guess/list [get]
func GuessList(c *gin.Context) {
var req proto.VideoGuessListReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
data, err := videoser.VideoGuessList(c, &req)
if err != nil {
common.ServerJSON(c, err, err.GetMsg())
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// TagList app端根据标签ID查询视频列表
// @Tags 视频相关接口
// @Summary app端根据标签ID查询视频列表 -- by 王鸣
// @Description 根据统一标签ID分页查询视频列表,带穿插列表广告,每间隔8条视频数据插入一个广告
// @Accept json
// @Produce json
// @Param id path int true "标签ID"
// @Param pageNum query int false "页码,默认1"
// @Param pageSize query int false "每页数量,默认20,最大100"
// @Success 200 {object} proto.VideoRecommendListResp{list=[]proto.VideoRecommendListItem} "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/video/tag/{id} [get]
func TagList(c *gin.Context) {
var req proto.ContentTagPageReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
pathID, pathSlug := slugser.ParseIDOrSlug(c.Param("id"))
if req.Id <= 0 {
req.Id = pathID
}
if req.Slug == "" {
req.Slug = pathSlug
}
data, err := videoser.VideoTagList(c, &req)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// QueryVideoMore
// @Tags 视频相关接口
// @Summary 根据分类id查询视频列表 --by 王鸣
// @Description 根据分类id查询视频列表,带穿插列表广告,每间隔8条视频数据插入一个广告
// @Accept json
// @Produce json
// @Param params query proto.QueryVideoReq true "视频更多查询请求"
// @Success 200 {object} proto.QueryVideoResp{list=[]proto.QueryVideoListItem{VideoInfo=proto.VideoInfo}} "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/video/more [get]
func QueryVideoMore(c *gin.Context) {
var req proto.QueryVideoReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
data, err := videoser.QueryVideoMore(c, &req)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// QueryVideoInfo 视频详情
// @Tags 视频相关接口
// @Summary 视频详情 -- by 王鸣
// @Description 查询视频详情、收藏状态和点赞状态
// @Accept json
// @Produce json
// @Param params query proto.QueryVideoInfoReq true "视频详情查询请求"
// @Success 200 {object} proto.QueryVideoInfoResp{videoInfo=proto.VideoDetailInfo} "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/video/info [get]
func QueryVideoInfo(c *gin.Context) {
var req proto.QueryVideoInfoReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
data, err := videoser.QueryVideoInfo(c, common.GetUserId(c), videoser.H5M3U8RequestIP(c), c.Request.UserAgent(), &req)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// FavoriteVideo 收藏或取消收藏视频
// @Tags 视频相关接口
// @Summary 收藏或取消收藏视频 --by 旺鸣
// @Description 当前登录用户收藏或取消收藏指定视频,isFavorite=true表示收藏,isFavorite=false表示取消收藏
// @Accept json
// @Produce json
// @Param param body proto.FavoriteVideoReq true "收藏或取消收藏请求"
// @Success 200 {object} proto.FavoriteVideoResp "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /api/app/video/favorite [post]
func FavoriteVideo(c *gin.Context) {
var req proto.FavoriteVideoReq
if err := c.ShouldBindJSON(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
userId := common.GetUserId(c)
if userId <= 0 {
common.ServerJSON(c, srvdef.InvalidToken, "")
return
}
ua, _ := common.GetUA(c)
if ua.UserAgent == "" {
ua.UserAgent = c.Request.UserAgent()
}
data, err := videoser.FavoriteVideo(c, userId, c.ClientIP(), ua, &req)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// LikeVideo 点赞或取消点赞视频
// @Tags 视频相关接口
// @Summary 点赞或取消点赞视频 -- by 王鸣
// @Description 当前登录用户点赞或取消点赞指定视频,isLike=true表示点赞,isLike=false表示取消点赞
// @Accept json
// @Produce json
// @Param param body proto.LikeVideoReq true "点赞或取消点赞请求"
// @Success 200 {object} proto.LikeVideoResp "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /api/app/video/like [post]
func LikeVideo(c *gin.Context) {
var req proto.LikeVideoReq
if err := c.ShouldBindJSON(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
userId := common.GetUserId(c)
if userId <= 0 {
common.ServerJSON(c, srvdef.InvalidToken, "")
return
}
ua, _ := common.GetUA(c)
if ua.UserAgent == "" {
ua.UserAgent = c.Request.UserAgent()
}
data, err := videoser.LikeVideo(c, userId, c.ClientIP(), ua, &req)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// QueryVideoRank 视频收藏排行榜
// @Tags 视频相关接口
// @Summary 视频收藏排行榜
// @Description 视频收藏排行榜
// @Accept json
// @Produce json
// @Success 200 {object} proto.RankResp "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/video/rank [get]
func QueryVideoRank(c *gin.Context) {
rank := proto.HomeRankData{
Total: configser.GetVideoRankList(configser.RankPeriodTotal, 0),
Week: configser.GetVideoRankList(configser.RankPeriodWeek, 0),
Month: configser.GetVideoRankList(configser.RankPeriodMonth, 0),
Year: configser.GetVideoRankList(configser.RankPeriodYear, 0),
}
common.ServerJSON(c, srvdef.Success, proto.RankResp{
RankData: rank,
Translations: translationser.GetTranslationData(),
BottonTranslations: translationser.GetTranslationBottomList(),
})
}
// QueryVideoRankList 视频排行榜分页列表
// @Tags 视频相关接口
// @Summary 视频排行榜分页列表 -- by 王鸣
// @Description 分页查询视频排行榜,rankPeriod=0点赞榜(累计点赞)、1周榜/2月榜/3年榜(周期观看量),独立缓存10分钟,每榜最多50条,pageSize不是50时强制为50
// @Accept json
// @Produce json
// @Param params query proto.VideoRankReq true "视频排行榜分页请求"
// @Success 200 {object} proto.VideoRankResp{list=[]proto.ContentData} "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Router /api/app/video/rank/list [get]
func QueryVideoRankList(c *gin.Context) {
var req proto.VideoRankReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
data, err := videoser.QueryVideoRank(c, &req)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// QueryFavoriteVideoList 当前登录用户收藏视频分页列表
// @Tags 视频相关接口
// @Summary 当前登录用户收藏视频分页列表 --by 旺鸣
// @Description 当前登录用户收藏视频分页列表,按收藏时间倒序排序
// @Accept json
// @Produce json
// @Param params query proto.QueryFavoriteVideoListReq true "收藏视频分页请求"
// @Success 200 {object} proto.QueryFavoriteVideoListResp{list=[]proto.FavoriteVideoListItem} "成功"
// @Failure 400 {string} string "获取失败的返回结果"
// @Security ApiKeyAuth
// @Router /api/app/video/favorite/list [get]
func QueryFavoriteVideoList(c *gin.Context) {
var req proto.QueryFavoriteVideoListReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
userId := common.GetUserId(c)
if userId <= 0 {
common.ServerJSON(c, srvdef.InvalidToken, "")
return
}
data, err := videoser.QueryFavoriteVideoList(c, userId, &req)
if err != nil {
common.ServerJSON(c, err, "")
return
}
common.ServerJSON(c, srvdef.Success, data)
}
// QueryLikeVideoList 当前用户点赞视频分页列表
// @Tags 视频相关接口
// @Summary 当前用户点赞视频分页列表
// @Description 按点赞时间倒序返回当前用户点赞的上架视频
// @Produce json
// @Param params query proto.QueryLikeVideoListReq true "点赞视频分页请求"
// @Success 200 {object} proto.QueryLikeVideoListResp{list=[]proto.FavoriteVideoListItem} "成功"
// @Security ApiKeyAuth
// @Router /api/app/video/like/list [get]
func QueryLikeVideoList(c *gin.Context) {
var req proto.QueryLikeVideoListReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
userID := common.GetUserId(c)
if userID <= 0 {
common.ServerJSON(c, srvdef.InvalidToken, "")
return
}
resp, err := videoser.QueryLikeVideoList(c, userID, &req)
if err != nil {
common.ServerJSON(c, err, err.GetMsg())
return
}
common.ServerJSON(c, srvdef.Success, resp)
}
// ReportVideoHistory 播放成功后记录当前用户的视频
// @Tags 视频相关接口
// @Summary 上报视频观看历史
// @Accept json
// @Produce json
// @Param param body proto.VideoHistoryReportReq true "当前播放视频"
// @Success 200 {object} proto.VideoHistoryReportResp "成功"
// @Security ApiKeyAuth
// @Router /api/app/video/history [post]
func ReportVideoHistory(c *gin.Context) {
userID := common.GetUserId(c)
if userID <= 0 {
common.ServerJSON(c, srvdef.InvalidToken, "")
return
}
var req proto.VideoHistoryReportReq
if err := c.ShouldBindJSON(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
resp, err := videoser.ReportVideoHistory(c, userID, &req)
if err != nil {
common.ServerJSON(c, err, err.GetMsg())
return
}
common.ServerJSON(c, srvdef.Success, resp)
}
// QueryVideoHistoryList 当前用户视频观看历史分页列表
// @Tags 视频相关接口
// @Summary 视频观看历史列表
// @Produce json
// @Param params query proto.VideoHistoryListReq true "分页请求"
// @Success 200 {object} proto.VideoHistoryListResp{list=[]proto.VideoHistoryItem} "成功"
// @Security ApiKeyAuth
// @Router /api/app/video/history/list [get]
func QueryVideoHistoryList(c *gin.Context) {
userID := common.GetUserId(c)
if userID <= 0 {
common.ServerJSON(c, srvdef.InvalidToken, "")
return
}
var req proto.VideoHistoryListReq
if err := c.ShouldBindQuery(&req); err != nil {
common.ServerJSON(c, srvdef.ErrParamError, "")
return
}
resp, err := videoser.QueryVideoHistoryList(c, userID, &req)
if err != nil {
common.ServerJSON(c, err, err.GetMsg())
return
}
common.ServerJSON(c, srvdef.Success, resp)
}
// ClearVideoHistory 清空当前用户视频观看历史
// @Tags 视频相关接口
// @Summary 清空视频观看历史
// @Produce json
// @Success 200 {object} proto.VideoHistoryClearResp "成功"
// @Security ApiKeyAuth
// @Router /api/app/video/history [delete]
func ClearVideoHistory(c *gin.Context) {
userID := common.GetUserId(c)
if userID <= 0 {
common.ServerJSON(c, srvdef.InvalidToken, "")
return
}
resp, err := videoser.ClearVideoHistory(c, userID)
if err != nil {
common.ServerJSON(c, err, err.GetMsg())
return
}
common.ServerJSON(c, srvdef.Success, resp)
}