Files
web_huangguo2_h5/app/service/seoser/indexable.go
T
谢宇宁andClaude Opus 5.5 0fbdba5ccf Initial commit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 11:47:47 +07:00

181 lines
4.8 KiB
Go

package seoser
import (
"net/url"
"strconv"
"strings"
)
// IsIndexablePath 是否为需要收录的公开页。
// 采用白名单策略:新增页面只有明确归类后才允许进入索引,避免搜索、账户、
// 排序变体和工具页因遗漏配置被搜索引擎收录。
func IsIndexablePath(raw string) bool {
path := normalizedPath(raw)
if path == "/" {
return true
}
switch path {
case "/about", "/help", "/terms", "/privacy", "/2257", "/dmca":
return true
}
segments := splitPath(path)
if len(segments) == 0 {
return false
}
switch segments[0] {
case "list":
return isIndexablePlayletList(segments)
case "series":
return isIndexableSeriesList(segments)
case "topic":
return isIndexableSimplePagination(segments, "topic")
case "topic-detail", "tags":
return isIndexableNamedCollection(segments)
case "rank", "popular-recommend":
return isIndexableRanking(segments)
case "more-list", "more-series-list":
return isIndexableCuratedCollection(segments)
case "recently-added":
return isIndexableSimplePagination(segments, "recently-added")
case "play":
return isIndexablePlayletPlayback(segments)
case "series-play":
return len(segments) == 2 && segments[1] != ""
default:
return false
}
}
// IsPrivatePath 标记不应跟踪链接的账户、认证和交易页面。
func IsPrivatePath(raw string) bool {
path := normalizedPath(raw)
for _, prefix := range []string{
"/login", "/register", "/profile", "/history", "/favorites",
"/purchased", "/setting", "/settings", "/recharge", "/feedback",
} {
if path == prefix || strings.HasPrefix(path, prefix+"/") {
return true
}
}
return false
}
func normalizedPath(raw string) string {
path := strings.TrimSpace(raw)
if u, err := url.Parse(path); err == nil && u.Path != "" {
path = u.Path
}
path = "/" + strings.Trim(strings.TrimSpace(path), "/")
if path == "/" {
return path
}
return strings.TrimSuffix(path, "/")
}
func splitPath(path string) []string {
path = strings.Trim(path, "/")
if path == "" {
return nil
}
return strings.Split(path, "/")
}
func positiveInt(raw string) bool {
n, err := strconv.Atoi(raw)
return err == nil && n > 0
}
func pageNumber(raw string) bool {
n, err := strconv.Atoi(raw)
return err == nil && n > 1
}
func isIndexableSimplePagination(segments []string, root string) bool {
if len(segments) == 1 && segments[0] == root {
return true
}
return len(segments) == 3 && segments[0] == root && segments[1] == "page" && pageNumber(segments[2])
}
func isIndexablePlayletList(segments []string) bool {
if len(segments) == 1 {
return true
}
if len(segments) == 2 {
return segments[1] != "" && segments[1] != "all"
}
base, hasPage := withoutPageSuffix(segments)
if len(base) != 4 || base[1] == "" {
return false
}
updateStatus, updateErr := strconv.Atoi(base[2])
sortType, sortErr := strconv.Atoi(base[3])
if updateErr != nil || sortErr != nil || updateStatus < 0 || updateStatus > 2 || sortType != 1 {
return false
}
// 默认第一页已有更短规范地址 /list 或 /list/:theme。
return hasPage || updateStatus != 0
}
func isIndexableSeriesList(segments []string) bool {
if len(segments) == 1 {
return true
}
base, hasPage := withoutPageSuffix(segments)
if len(base) != 4 {
return false
}
media, topic, sortType := base[1], base[2], base[3]
if media != "all" && media != "film" && media != "anime" {
return false
}
if topic != "all" && !positiveInt(topic) {
return false
}
if sortType != "1" {
return false
}
// 默认第一页已有更短规范地址 /series。
return hasPage || media != "all" || topic != "all"
}
func isIndexableNamedCollection(segments []string) bool {
if len(segments) == 2 && segments[1] != "" {
return true
}
return len(segments) == 4 && segments[1] != "" && segments[2] == "page" && pageNumber(segments[3])
}
func isIndexableRanking(segments []string) bool {
if len(segments) == 1 {
return true
}
if len(segments) == 2 {
return segments[1] == "2" || segments[1] == "3"
}
if len(segments) == 3 {
return segments[1] == "page" && pageNumber(segments[2])
}
return len(segments) == 4 && (segments[1] == "2" || segments[1] == "3") && segments[2] == "page" && pageNumber(segments[3])
}
func isIndexableCuratedCollection(segments []string) bool {
if len(segments) == 2 {
return segments[1] != ""
}
return len(segments) == 4 && segments[1] != "" && segments[2] == "page" && pageNumber(segments[3])
}
func isIndexablePlayletPlayback(segments []string) bool {
// 规范入口是 /play/{slug};各集 /play/{slug}/{ep} 近重复且多为薄播放页,不收录。
return len(segments) == 2 && segments[1] != ""
}
func withoutPageSuffix(segments []string) ([]string, bool) {
if len(segments) < 3 || segments[len(segments)-2] != "page" || !pageNumber(segments[len(segments)-1]) {
return segments, false
}
return segments[:len(segments)-2], true
}