package fqapi
import (
"fanqie/internal/common"
"fanqie/internal/config"
"regexp"
"strings"
"github.com/PuerkitoBio/goquery"
)
// imgSrcRe 匹配 img 标签的 src 属性
var imgSrcRe = regexp.MustCompile(`(?i)(]*\ssrc=")([^"]*)(")`)
// permanentizeImgSrc 将正文插图链接替换为永久 CDN 链接(原链接带临时参数会过期)
func permanentizeImgSrc(html string) string {
return imgSrcRe.ReplaceAllStringFunc(html, func(m string) string {
parts := imgSrcRe.FindStringSubmatch(m)
if len(parts) < 3 || parts[2] == "" {
return m
}
return parts[1] + NormalizeNovelImageURL(parts[2]) + parts[3]
})
}
var (
parserLogger = common.NewLogger("content_parser", "INFO", "")
)
// ContentParser 内容解析器
type ContentParser struct {
cfg config.ContentConfig
}
// NewContentParser 创建内容解析器
func NewContentParser() *ContentParser {
return &ContentParser{
cfg: getContentConfig(),
}
}
// Parse 解析内容(URL参数优先于配置)
func (p *ContentParser) Parse(content string, textMode bool, imageMode bool) string {
// 1. 清理XML声明和DOCTYPE
content = p.cleanXMLDeclaration(content)
// 2. 根据配置移除章节标题
if p.cfg.RemoveChapterTitle {
content = p.removeChapterTitle(content)
}
// 3. 根据配置处理图片描述
if p.cfg.RemoveImageDesc {
content = p.removeImageDesc(content)
}
// 4. 根据参数移除图片
// imageMode=false 时移除(URL 参数与配置 remove_images 已在调用方合成:URL 优先)
if !imageMode {
content = p.removeImages(content)
}
// 5. 根据参数处理内容模式
// textMode=true 时提取纯文本(URL 参数与配置 remove_html_tags 已在调用方合成:URL 优先)
if textMode {
return p.extractText(content)
}
// 6. HTML模式处理
return p.processHTMLMode(content)
}
// cleanXMLDeclaration 清理XML声明
func (p *ContentParser) cleanXMLDeclaration(content string) string {
content = regexp.MustCompile(`<\?xml[^>]*\?>`).ReplaceAllString(content, "")
content = regexp.MustCompile(`]*>`).ReplaceAllString(content, "")
return strings.TrimSpace(content)
}
// removeChapterTitle 移除章节标题
func (p *ContentParser) removeChapterTitle(content string) string {
// 移除 h1 和 h2 标签中的章节标题
content = regexp.MustCompile(`(?si)
]*class="pictureDesc"[^>]*>.*?
`).ReplaceAllString(content, "") } // removeImages 移除图片 func (p *ContentParser) removeImages(content string) string { return regexp.MustCompile(`(?s)标签 content = regexp.MustCompile(`(?s)
]*>\s*
`).ReplaceAllString(content, "") // 移除多余的空白 content = regexp.MustCompile(`\n\s*\n\s*\n`).ReplaceAllString(content, "\n\n") } return content }