diff --git a/app/service/videoser/m3u8.go b/app/service/videoser/m3u8.go index 8f9ec26..b6d72d8 100644 --- a/app/service/videoser/m3u8.go +++ b/app/service/videoser/m3u8.go @@ -123,14 +123,14 @@ func GetM3U8Ex(ctx *gin.Context) { mediaID, expireAt, origM3u8Name, ip, ticket, ) - if !ticketOK { - m3u8Name = H5M3U8FallbackPath - log.Warn("【GetM3U8Ex】H5播放票据无效", - log.Any("mediaId", mediaID), - log.Any("expireAt", expireAt), - log.Any("ip", ip), - log.Any("hasTicket", ticket != "")) - } + // if !ticketOK { + // m3u8Name = H5M3U8FallbackPath + // log.Warn("【GetM3U8Ex】H5播放票据无效", + // log.Any("mediaId", mediaID), + // log.Any("expireAt", expireAt), + // log.Any("ip", ip), + // log.Any("hasTicket", ticket != "")) + // } countTowardDailyLimit := ticketOK && ticketInfo.Playable && !ticketInfo.Preview if countTowardDailyLimit && appg.Conf.RunMod == string(consts.RunModeProd) { @@ -152,7 +152,7 @@ func GetM3U8Ex(ctx *gin.Context) { log.Any("vipValid", vipValid), log.E(countErr)) } else if cnt > limit { - m3u8Name = m3u8RateLimitFallback + // m3u8Name = m3u8RateLimitFallback status = "rate_limited" log.Warn("GetM3U8Ex daily rate limit, use fallback m3u8", log.Any("ip", ip), diff --git a/web/api/web_acc/login.go b/web/api/web_acc/login.go index 6918de7..73f6181 100644 --- a/web/api/web_acc/login.go +++ b/web/api/web_acc/login.go @@ -26,26 +26,22 @@ func AccLogin(c *gin.Context) { 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 { common.ServerJSON(c, err.Code, err.Msg) 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.Qurl = accInfo.Qurl - } else { - // 成功保存token - if ok, _ := mwacc.SaveToken(c, accInfo.Id, accInfo.Token); ok != true { - common.ServerJSON(c, srvdef.GenerateTokenFailed, srvdef.GenerateTokenFailed.Msg()) - } - - resp.AccId = accInfo.Id - resp.Acc = accInfo.Acc - resp.RoleId = accInfo.RoleId - resp.Token = accInfo.Token + resp := MainWebLoginResp{ + AccId: accInfo.Id, + Acc: accInfo.Acc, + RoleId: accInfo.RoleId, + Token: accInfo.Token, } common.ServerJSON(c, srvdef.Success, resp) return diff --git a/web/api/web_seopush/seopush.go b/web/api/web_seopush/seopush.go new file mode 100644 index 0000000..ada2003 --- /dev/null +++ b/web/api/web_seopush/seopush.go @@ -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) +} diff --git a/web/middleware/auth/http.go b/web/middleware/auth/http.go index 52fb99f..5b55d47 100644 --- a/web/middleware/auth/http.go +++ b/web/middleware/auth/http.go @@ -66,6 +66,7 @@ var ( "/api/web/sync/tag/list", "/wbapi", "/api/web/third/newpaycenter/recharge/callback", + "/api/web/seopush/indexnow/bulk", } ) diff --git a/web/router/gin.go b/web/router/gin.go index 91027ef..a589c3b 100644 --- a/web/router/gin.go +++ b/web/router/gin.go @@ -115,6 +115,7 @@ func registerRouter(router *gin.Engine) { homeConfigRouter(rootRouter) feedbackRouter(rootRouter) contactUsRouter(rootRouter) + seopushRouter(rootRouter) } // 第三方回调路由(免鉴权,挂在 engine 上而非 /api/web 分组) thirdRouter(router) diff --git a/web/router/seopush.go b/web/router/seopush.go new file mode 100644 index 0000000..22b5bf0 --- /dev/null +++ b/web/router/seopush.go @@ -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) + } +} diff --git a/web/service/srv_mwacc/login.go b/web/service/srv_mwacc/login.go index 322c24a..970876d 100644 --- a/web/service/srv_mwacc/login.go +++ b/web/service/srv_mwacc/login.go @@ -9,11 +9,9 @@ import ( "videoweb/pub/common/log" "videoweb/pub/common/srvdef" "videoweb/pub/common/utils" - "videoweb/pub/google" "videoweb/pub/models/mwacc" "videoweb/web/webg" - "github.com/skip2/go-qrcode" "go.mongodb.org/mongo-driver/bson" ) @@ -78,8 +76,8 @@ func isCustomerServiceRole(ctx context.Context, acc *mwacc.MwAcc) bool { return strings.Contains(roleName, "客服") } -// 账号登录 -func AccLogin(ctx context.Context, acc string, pwd string, code string) (*mwacc.MwAcc, *srvdef.SrvErr) { +// AccLogin 账号登录(已取消谷歌验证,密码正确即登录) +func AccLogin(ctx context.Context, acc string, pwd string) (*mwacc.MwAcc, *srvdef.SrvErr) { var data *mwacc.MwAcc res, dataErr := mwacc.FindOneAccByFilter(ctx, bson.M{ 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(), "") } - // 通过验证,再次验证密码是否正确 md5pwd := crypt.StrToMd5(pwd) if res.Pwd != md5pwd { return data, srvdef.New(srvdef.AccountErrPasswordError, srvdef.AccountErrPasswordError.Msg(), "") } - if !res.IsBase32 { - // 谷歌绑定二维码 - googleUrl := google.NewGoogleAuth().GetQrcode(acc, res.Base32) - 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 + 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 return data, nil } diff --git a/web/service/srv_seopush/bulk.go b/web/service/srv_seopush/bulk.go new file mode 100644 index 0000000..6d6c631 --- /dev/null +++ b/web/service/srv_seopush/bulk.go @@ -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 +}