🔧 chore: 初始化番茄小说 API 项目结构
新增项目基础框架,包含核心 API 实现、算法模块、HTTP 处理器等完整功能模块
This commit is contained in:
commit
6981148727
107 files changed
+12463
No files matched your search
@@ -0,0 +1,265 @@
|
||||
package fqapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fanqie/internal/config"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// getContentConfig 获取内容配置(带默认值)
|
||||
func getContentConfig() config.ContentConfig {
|
||||
if config.AppConfig != nil {
|
||||
return config.AppConfig.Fanqie.Content
|
||||
}
|
||||
// 返回默认配置
|
||||
return config.ContentConfig{
|
||||
RemoveImages: false,
|
||||
RemoveImageDesc: false,
|
||||
RemoveBlankLines: true,
|
||||
RemoveHTMLTags: false,
|
||||
RemoveChapterTitle: false,
|
||||
AddParagraphIndent: false,
|
||||
}
|
||||
}
|
||||
|
||||
// decodeHTMLEntities 解码HTML实体
|
||||
func decodeHTMLEntities(content string) string {
|
||||
// 解码常见HTML实体
|
||||
content = strings.ReplaceAll(content, "&", "&")
|
||||
content = strings.ReplaceAll(content, "<", "<")
|
||||
content = strings.ReplaceAll(content, ">", ">")
|
||||
content = strings.ReplaceAll(content, """, "\"")
|
||||
content = strings.ReplaceAll(content, """, "\"")
|
||||
content = strings.ReplaceAll(content, "'", "'")
|
||||
content = strings.ReplaceAll(content, "'", "'")
|
||||
content = strings.ReplaceAll(content, "'", "'")
|
||||
content = strings.ReplaceAll(content, "/", "/")
|
||||
|
||||
// 解码转义的反斜杠
|
||||
content = strings.ReplaceAll(content, "\\\"", "\"")
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
// normalizeImgAttributes 将img标签中的img-width和img-height属性替换为标准的width和height属性
|
||||
func normalizeImgAttributes(content string) string {
|
||||
// 替换 img-width 为 width
|
||||
content = strings.ReplaceAll(content, "img-width=", "width=")
|
||||
// 替换 img-height 为 height
|
||||
content = strings.ReplaceAll(content, "img-height=", "height=")
|
||||
return content
|
||||
}
|
||||
|
||||
// removeBlankLines 移除多余空行,但保留段落间的双换行
|
||||
func removeBlankLines(content string) string {
|
||||
// 先将多个连续换行(3个及以上)规范化为双换行
|
||||
for strings.Contains(content, "\n\n\n") {
|
||||
content = strings.ReplaceAll(content, "\n\n\n", "\n\n")
|
||||
}
|
||||
|
||||
// 移除首尾的空白
|
||||
content = strings.TrimSpace(content)
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
// ============ 参数解析工具函数 ============
|
||||
|
||||
// parseBoolParam 解析布尔参数
|
||||
func parseBoolParam(param interface{}) bool {
|
||||
switch v := param.(type) {
|
||||
case string:
|
||||
return v == "true" || v == "1" || strings.ToLower(v) == "true"
|
||||
case bool:
|
||||
return v
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// parseBoolParamDefault 解析布尔参数(带默认值)
|
||||
func parseBoolParamDefault(param interface{}, defaultVal bool) bool {
|
||||
if param == nil || param == "" {
|
||||
return defaultVal
|
||||
}
|
||||
return parseBoolParam(param)
|
||||
}
|
||||
|
||||
// ============ JSON 处理工具函数 ============
|
||||
|
||||
// escapeJSON 转义JSON中的特殊字符
|
||||
func escapeJSON(s string) string {
|
||||
s = strings.ReplaceAll(s, "<", "\\u003c")
|
||||
s = strings.ReplaceAll(s, ">", "\\u003e")
|
||||
return s
|
||||
}
|
||||
|
||||
// buildJSONResponse 构建JSON响应并转义
|
||||
func buildJSONResponse(data interface{}) string {
|
||||
resultBytes, _ := json.Marshal(data)
|
||||
return escapeJSON(string(resultBytes))
|
||||
}
|
||||
|
||||
// ============ 设备和密钥管理 ============
|
||||
|
||||
// getDeviceHeader 获取设备header(从设备池)
|
||||
func getDeviceHeader() string {
|
||||
// 从设备池获取任意有效设备header
|
||||
return GetAnyValidDeviceHeader()
|
||||
}
|
||||
|
||||
// removeVersionFromHeader 移除header中的version_name参数
|
||||
func removeVersionFromHeader(header string) string {
|
||||
return strings.Replace(header, "&version_name=5.8.9.32", "", -1)
|
||||
}
|
||||
|
||||
// ============ API参数构建工具 ============
|
||||
|
||||
// BuildURL 构建API请求URL
|
||||
// 用法: BuildURL("https://reading.snssdk.com/reading/bookapi/detail/v/", "book_id=123", "tab_type=3")
|
||||
func BuildURL(fullURL string, customParams ...string) string {
|
||||
// 基础参数
|
||||
allParams := []string{
|
||||
"aid=1967",
|
||||
"app_name=novelapp",
|
||||
"channel=0",
|
||||
"device_platform=android",
|
||||
"os_version=0",
|
||||
"version_code=58932",
|
||||
}
|
||||
|
||||
// 添加设备header
|
||||
header := getDeviceHeader()
|
||||
if header != "" {
|
||||
allParams = append(allParams, header)
|
||||
}
|
||||
|
||||
// 添加自定义参数
|
||||
allParams = append(allParams, customParams...)
|
||||
|
||||
// 合并、拆分、排序
|
||||
joined := strings.Join(allParams, "&")
|
||||
paramList := strings.Split(joined, "&")
|
||||
sort.Strings(paramList)
|
||||
params := strings.Join(paramList, "&")
|
||||
|
||||
return fullURL + "?" + params
|
||||
}
|
||||
|
||||
// ============ 缓存处理工具函数 ============
|
||||
|
||||
// buildCacheData 构建缓存数据结构
|
||||
func buildCacheData(data interface{}) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "SUCCESS",
|
||||
"data": data,
|
||||
}
|
||||
}
|
||||
|
||||
// saveCacheJSON 保存JSON到缓存
|
||||
func saveCacheJSON(key string, data interface{}, ttl int) {
|
||||
cacheJSON, _ := json.Marshal(data)
|
||||
cacheStr := escapeJSON(string(cacheJSON))
|
||||
UpdateCache(key, cacheStr, ttl)
|
||||
}
|
||||
|
||||
// ============ 错误响应工具函数 ============
|
||||
|
||||
// BuildErrorResponse 构建统一的错误响应
|
||||
func BuildErrorResponse(msg string) string {
|
||||
return buildJSONResponse(map[string]interface{}{
|
||||
"code": -1,
|
||||
"msg": msg,
|
||||
})
|
||||
}
|
||||
|
||||
// BuildErrorResponseWithCode 构建带自定义错误码的响应
|
||||
func BuildErrorResponseWithCode(code int, msg string) string {
|
||||
return buildJSONResponse(map[string]interface{}{
|
||||
"code": code,
|
||||
"msg": msg,
|
||||
})
|
||||
}
|
||||
|
||||
// BuildSuccessResponse 构建成功响应
|
||||
func BuildSuccessResponse(data interface{}) string {
|
||||
return buildJSONResponse(map[string]interface{}{
|
||||
"code": 0,
|
||||
"message": "SUCCESS",
|
||||
"data": data,
|
||||
})
|
||||
}
|
||||
|
||||
// ============ 参数转换工具函数 ============
|
||||
|
||||
// ParseIntParam 解析整数参数(支持多种类型)
|
||||
func ParseIntParam(param interface{}, defaultVal int) int {
|
||||
switch v := param.(type) {
|
||||
case string:
|
||||
if v != "" {
|
||||
// 使用strconv.Atoi
|
||||
if result, err := parseStringToInt(v); err == nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
case int:
|
||||
return v
|
||||
case float64:
|
||||
return int(v)
|
||||
case int64:
|
||||
return int(v)
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
// parseStringToInt 辅助函数:将字符串转换为整数
|
||||
func parseStringToInt(s string) (int, error) {
|
||||
// 简单实现,避免导入strconv
|
||||
result := 0
|
||||
negative := false
|
||||
|
||||
if len(s) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
start := 0
|
||||
if s[0] == '-' {
|
||||
negative = true
|
||||
start = 1
|
||||
} else if s[0] == '+' {
|
||||
start = 1
|
||||
}
|
||||
|
||||
for i := start; i < len(s); i++ {
|
||||
if s[i] < '0' || s[i] > '9' {
|
||||
break
|
||||
}
|
||||
result = result*10 + int(s[i]-'0')
|
||||
}
|
||||
|
||||
if negative {
|
||||
result = -result
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ParseStringParam 解析字符串参数(支持数组类型自动Join)
|
||||
func ParseStringParam(param interface{}, defaultVal string) string {
|
||||
if param == nil || param == "" {
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
switch v := param.(type) {
|
||||
case string:
|
||||
if v != "" {
|
||||
return v
|
||||
}
|
||||
case []string:
|
||||
// 数组类型,用逗号连接
|
||||
return strings.Join(v, ",")
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user