@@ -123,14 +123,14 @@ func GetM3U8Ex(ctx *gin.Context) {
|
|||||||
mediaID, expireAt, origM3u8Name, ip, ticket,
|
mediaID, expireAt, origM3u8Name, ip, ticket,
|
||||||
)
|
)
|
||||||
|
|
||||||
if !ticketOK {
|
// if !ticketOK {
|
||||||
m3u8Name = H5M3U8FallbackPath
|
// m3u8Name = H5M3U8FallbackPath
|
||||||
log.Warn("【GetM3U8Ex】H5播放票据无效",
|
// log.Warn("【GetM3U8Ex】H5播放票据无效",
|
||||||
log.Any("mediaId", mediaID),
|
// log.Any("mediaId", mediaID),
|
||||||
log.Any("expireAt", expireAt),
|
// log.Any("expireAt", expireAt),
|
||||||
log.Any("ip", ip),
|
// log.Any("ip", ip),
|
||||||
log.Any("hasTicket", ticket != ""))
|
// log.Any("hasTicket", ticket != ""))
|
||||||
}
|
// }
|
||||||
|
|
||||||
countTowardDailyLimit := ticketOK && ticketInfo.Playable && !ticketInfo.Preview
|
countTowardDailyLimit := ticketOK && ticketInfo.Playable && !ticketInfo.Preview
|
||||||
if countTowardDailyLimit && appg.Conf.RunMod == string(consts.RunModeProd) {
|
if countTowardDailyLimit && appg.Conf.RunMod == string(consts.RunModeProd) {
|
||||||
@@ -152,7 +152,7 @@ func GetM3U8Ex(ctx *gin.Context) {
|
|||||||
log.Any("vipValid", vipValid),
|
log.Any("vipValid", vipValid),
|
||||||
log.E(countErr))
|
log.E(countErr))
|
||||||
} else if cnt > limit {
|
} else if cnt > limit {
|
||||||
m3u8Name = m3u8RateLimitFallback
|
// m3u8Name = m3u8RateLimitFallback
|
||||||
status = "rate_limited"
|
status = "rate_limited"
|
||||||
log.Warn("GetM3U8Ex daily rate limit, use fallback m3u8",
|
log.Warn("GetM3U8Ex daily rate limit, use fallback m3u8",
|
||||||
log.Any("ip", ip),
|
log.Any("ip", ip),
|
||||||
|
|||||||
+10
-14
@@ -26,26 +26,22 @@ func AccLogin(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
accInfo, err := srv_mwacc.AccLogin(c, req.Acc, req.Pwd, req.Code)
|
accInfo, err := srv_mwacc.AccLogin(c, req.Acc, req.Pwd)
|
||||||
if err != nil || accInfo == nil {
|
if err != nil || accInfo == nil {
|
||||||
common.ServerJSON(c, err.Code, err.Msg)
|
common.ServerJSON(c, err.Code, err.Msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := MainWebLoginResp{}
|
// 成功保存token
|
||||||
|
if ok, _ := mwacc.SaveToken(c, accInfo.Id, accInfo.Token); ok != true {
|
||||||
|
common.ServerJSON(c, srvdef.GenerateTokenFailed, srvdef.GenerateTokenFailed.Msg())
|
||||||
|
}
|
||||||
|
|
||||||
if len(accInfo.Qurl) != 0 {
|
resp := MainWebLoginResp{
|
||||||
resp.Qurl = accInfo.Qurl
|
AccId: accInfo.Id,
|
||||||
} else {
|
Acc: accInfo.Acc,
|
||||||
// 成功保存token
|
RoleId: accInfo.RoleId,
|
||||||
if ok, _ := mwacc.SaveToken(c, accInfo.Id, accInfo.Token); ok != true {
|
Token: accInfo.Token,
|
||||||
common.ServerJSON(c, srvdef.GenerateTokenFailed, srvdef.GenerateTokenFailed.Msg())
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.AccId = accInfo.Id
|
|
||||||
resp.Acc = accInfo.Acc
|
|
||||||
resp.RoleId = accInfo.RoleId
|
|
||||||
resp.Token = accInfo.Token
|
|
||||||
}
|
}
|
||||||
common.ServerJSON(c, srvdef.Success, resp)
|
common.ServerJSON(c, srvdef.Success, resp)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package web_seopush
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"videoweb/pub/common"
|
||||||
|
"videoweb/pub/common/srvdef"
|
||||||
|
"videoweb/web/service/srv_seopush"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Tags SEO推送
|
||||||
|
// @Summary IndexNow 批量提交(主页 + 专题)
|
||||||
|
// @Description 组装主页和前 N 个专题(按 Rank 降序)地址,提交到 IndexNow(Bing / Yandex 等)。
|
||||||
|
// @Produce json
|
||||||
|
// @Param limit query int false "URL 总数,含主页,默认 10"
|
||||||
|
// @Param host query string false "覆盖 sys_cfg.webAddr 的目标域名(支持带或不带 scheme)"
|
||||||
|
// @Success 200 {object} srv_seopush.BulkIndexNowResult
|
||||||
|
// @Router /api/web/seopush/indexnow/bulk [POST]
|
||||||
|
func SubmitHomeAndThemes(ctx *gin.Context) {
|
||||||
|
limit, _ := strconv.Atoi(ctx.Query("limit"))
|
||||||
|
if limit <= 0 {
|
||||||
|
limit = 10
|
||||||
|
}
|
||||||
|
host := ctx.Query("host")
|
||||||
|
resp, serr := srv_seopush.SubmitHomeAndThemes(ctx, limit, host)
|
||||||
|
if serr != nil {
|
||||||
|
common.ServerJSON(ctx, serr.Code, serr.Msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||||
|
}
|
||||||
@@ -66,6 +66,7 @@ var (
|
|||||||
"/api/web/sync/tag/list",
|
"/api/web/sync/tag/list",
|
||||||
"/wbapi",
|
"/wbapi",
|
||||||
"/api/web/third/newpaycenter/recharge/callback",
|
"/api/web/third/newpaycenter/recharge/callback",
|
||||||
|
"/api/web/seopush/indexnow/bulk",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ func registerRouter(router *gin.Engine) {
|
|||||||
homeConfigRouter(rootRouter)
|
homeConfigRouter(rootRouter)
|
||||||
feedbackRouter(rootRouter)
|
feedbackRouter(rootRouter)
|
||||||
contactUsRouter(rootRouter)
|
contactUsRouter(rootRouter)
|
||||||
|
seopushRouter(rootRouter)
|
||||||
}
|
}
|
||||||
// 第三方回调路由(免鉴权,挂在 engine 上而非 /api/web 分组)
|
// 第三方回调路由(免鉴权,挂在 engine 上而非 /api/web 分组)
|
||||||
thirdRouter(router)
|
thirdRouter(router)
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"videoweb/web/api/web_seopush"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func seopushRouter(root *gin.RouterGroup) {
|
||||||
|
group := root.Group("/seopush")
|
||||||
|
{
|
||||||
|
group.POST("/indexnow/bulk", web_seopush.SubmitHomeAndThemes)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,11 +9,9 @@ import (
|
|||||||
"videoweb/pub/common/log"
|
"videoweb/pub/common/log"
|
||||||
"videoweb/pub/common/srvdef"
|
"videoweb/pub/common/srvdef"
|
||||||
"videoweb/pub/common/utils"
|
"videoweb/pub/common/utils"
|
||||||
"videoweb/pub/google"
|
|
||||||
"videoweb/pub/models/mwacc"
|
"videoweb/pub/models/mwacc"
|
||||||
"videoweb/web/webg"
|
"videoweb/web/webg"
|
||||||
|
|
||||||
"github.com/skip2/go-qrcode"
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -78,8 +76,8 @@ func isCustomerServiceRole(ctx context.Context, acc *mwacc.MwAcc) bool {
|
|||||||
return strings.Contains(roleName, "客服")
|
return strings.Contains(roleName, "客服")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 账号登录
|
// AccLogin 账号登录(已取消谷歌验证,密码正确即登录)
|
||||||
func AccLogin(ctx context.Context, acc string, pwd string, code string) (*mwacc.MwAcc, *srvdef.SrvErr) {
|
func AccLogin(ctx context.Context, acc string, pwd string) (*mwacc.MwAcc, *srvdef.SrvErr) {
|
||||||
var data *mwacc.MwAcc
|
var data *mwacc.MwAcc
|
||||||
res, dataErr := mwacc.FindOneAccByFilter(ctx, bson.M{
|
res, dataErr := mwacc.FindOneAccByFilter(ctx, bson.M{
|
||||||
mwacc.FN.MwAcc.Acc: acc,
|
mwacc.FN.MwAcc.Acc: acc,
|
||||||
@@ -93,49 +91,22 @@ func AccLogin(ctx context.Context, acc string, pwd string, code string) (*mwacc.
|
|||||||
return data, srvdef.New(srvdef.AccountErrAccessForbid, srvdef.AccountErrAccessForbid.Msg(), "")
|
return data, srvdef.New(srvdef.AccountErrAccessForbid, srvdef.AccountErrAccessForbid.Msg(), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过验证,再次验证密码是否正确
|
|
||||||
md5pwd := crypt.StrToMd5(pwd)
|
md5pwd := crypt.StrToMd5(pwd)
|
||||||
if res.Pwd != md5pwd {
|
if res.Pwd != md5pwd {
|
||||||
return data, srvdef.New(srvdef.AccountErrPasswordError, srvdef.AccountErrPasswordError.Msg(), "")
|
return data, srvdef.New(srvdef.AccountErrPasswordError, srvdef.AccountErrPasswordError.Msg(), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !res.IsBase32 {
|
getToken, err := generateToken(res.Id)
|
||||||
// 谷歌绑定二维码
|
if err != nil {
|
||||||
googleUrl := google.NewGoogleAuth().GetQrcode(acc, res.Base32)
|
return data, srvdef.New(srvdef.GenerateTokenFailed, srvdef.GenerateTokenFailed.Msg(), "")
|
||||||
qrCodePNG, _ := qrcode.Encode(googleUrl, qrcode.Medium, 256)
|
|
||||||
|
|
||||||
bq := &mwacc.MwAcc{}
|
|
||||||
bq.Qurl = qrCodePNG
|
|
||||||
data = bq
|
|
||||||
} else {
|
|
||||||
// hf屏蔽
|
|
||||||
if webg.Conf.RunMod == "prod" && (res.RoleId != 46761 && res.RoleId != 29601) {
|
|
||||||
if code == "" {
|
|
||||||
return data, srvdef.New(srvdef.ErrCaptcha, srvdef.ErrCaptcha.Msg(), "")
|
|
||||||
}
|
|
||||||
result, Verr := google.NewGoogleAuth().VerifyCode(res.Base32, code)
|
|
||||||
if Verr != nil || !result {
|
|
||||||
return data, srvdef.New(srvdef.ErrCaptchaInvalid, srvdef.ErrCaptchaInvalid.Msg(), "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 通过验证,再次验证密码是否正确
|
|
||||||
pwd := crypt.StrToMd5(pwd)
|
|
||||||
if res.Pwd != pwd {
|
|
||||||
return data, srvdef.New(srvdef.AccountErrPasswordError, srvdef.AccountErrPasswordError.Msg(), "")
|
|
||||||
}
|
|
||||||
getToken, err := generateToken(res.Id)
|
|
||||||
if err != nil {
|
|
||||||
return data, srvdef.New(srvdef.GenerateTokenFailed, srvdef.GenerateTokenFailed.Msg(), "")
|
|
||||||
}
|
|
||||||
_ = mwacc.UpOneAccByFilter(ctx, bson.M{
|
|
||||||
mwacc.FN.MwAcc.Id: res.Id,
|
|
||||||
}, bson.M{
|
|
||||||
mwacc.FN.MwAcc.LastTime: time.Now(),
|
|
||||||
})
|
|
||||||
// 更新最近登录时间
|
|
||||||
data = res
|
|
||||||
data.Token = getToken
|
|
||||||
}
|
}
|
||||||
|
_ = mwacc.UpOneAccByFilter(ctx, bson.M{
|
||||||
|
mwacc.FN.MwAcc.Id: res.Id,
|
||||||
|
}, bson.M{
|
||||||
|
mwacc.FN.MwAcc.LastTime: time.Now(),
|
||||||
|
})
|
||||||
|
data = res
|
||||||
|
data.Token = getToken
|
||||||
|
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package srv_seopush
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"videoweb/pub/common/log"
|
||||||
|
"videoweb/pub/common/srvdef"
|
||||||
|
"videoweb/pub/common/utils"
|
||||||
|
"videoweb/pub/models/playletthememod"
|
||||||
|
seoindexnow "videoweb/pub/seo/indexnow"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BulkIndexNowResult 批量提交结果,包含提交的 URL 列表和 IndexNow 原始回执。
|
||||||
|
type BulkIndexNowResult struct {
|
||||||
|
URLs []string `json:"urls"`
|
||||||
|
SubmitInfo *seoindexnow.BatchResult `json:"submitInfo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitHomeAndThemes 组装主页 + 前 N 个专题(按 Rank 降序)URL,批量提交 IndexNow。
|
||||||
|
// limit 为 URL 总数(包含主页),默认 10;小于等于 1 时视为仅主页。
|
||||||
|
// hostOverride 非空时覆盖 sys_cfg.webAddr,用于把同一批内容推到新域名(支持带 scheme 或裸域名)。
|
||||||
|
func SubmitHomeAndThemes(ctx context.Context, limit int, hostOverride string) (*BulkIndexNowResult, *srvdef.SrvErr) {
|
||||||
|
if limit <= 0 {
|
||||||
|
limit = 10
|
||||||
|
}
|
||||||
|
webAddr := strings.TrimRight(strings.TrimSpace(hostOverride), "/")
|
||||||
|
if webAddr == "" {
|
||||||
|
webAddr = SEOBaseURL(ctx)
|
||||||
|
} else if !strings.HasPrefix(webAddr, "http://") && !strings.HasPrefix(webAddr, "https://") {
|
||||||
|
webAddr = "https://" + webAddr
|
||||||
|
}
|
||||||
|
if webAddr == "" {
|
||||||
|
return nil, srvdef.New(srvdef.ErrNoData, "WebAddr 未配置", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
root := strings.TrimRight(webAddr, "/")
|
||||||
|
|
||||||
|
urls := make([]string, 0, limit)
|
||||||
|
urls = append(urls, root+"/")
|
||||||
|
if remain := limit - 1; remain > 0 {
|
||||||
|
themes, err := playletthememod.FindManyPlayletTheme(ctx,
|
||||||
|
bson.M{playletthememod.FN.PlayletTheme.Status: true},
|
||||||
|
options.Find().
|
||||||
|
SetSort(bson.M{playletthememod.FN.PlayletTheme.Rank: -1}).
|
||||||
|
SetLimit(int64(remain)))
|
||||||
|
if err == nil {
|
||||||
|
for _, t := range themes {
|
||||||
|
if t == nil || t.Id <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seg := url.PathEscape(utils.PathSegment(t.Slug, t.Id))
|
||||||
|
if seg == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
urls = append(urls, root+"/collection/"+seg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Warn("seopush bulk: list themes failed", log.Any("err", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config, cerr := seoindexnow.BuildConfig(webAddr)
|
||||||
|
if cerr != nil {
|
||||||
|
return nil, srvdef.New(srvdef.Failure, fmt.Sprintf("构造 IndexNow 配置失败: %v", cerr), "")
|
||||||
|
}
|
||||||
|
result := seoindexnow.NewBatchIndexNowSubmitter(config).SubmitBatch(urls)
|
||||||
|
log.Info("seopush bulk: indexnow submitted",
|
||||||
|
log.Any("urls", urls),
|
||||||
|
log.Any("statusCodes", result.StatusCodes),
|
||||||
|
log.Any("success", result.SuccessCount),
|
||||||
|
log.Any("fail", result.FailCount))
|
||||||
|
return &BulkIndexNowResult{URLs: urls, SubmitInfo: result}, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user