mirror of
https://github.com/ctwj/urldb.git
synced 2025-11-25 03:15:04 +08:00
fix: 修复迅雷天翼自动处理不识别问题
This commit is contained in:
@@ -17,6 +17,9 @@ const (
|
||||
UC
|
||||
NotFound
|
||||
Xunlei
|
||||
Tianyi
|
||||
Pan123
|
||||
Pan115
|
||||
)
|
||||
|
||||
// String 返回服务类型的字符串表示
|
||||
@@ -136,13 +139,17 @@ func (f *PanFactory) CreatePanServiceByType(serviceType ServiceType, config *Pan
|
||||
return NewBaiduPanService(config), nil
|
||||
case UC:
|
||||
return NewUCService(config), nil
|
||||
// case Xunlei:
|
||||
// return NewXunleiService(config), nil
|
||||
// case Tianyi:
|
||||
// return NewTianyiService(config), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("不支持的服务类型: %d", serviceType)
|
||||
}
|
||||
}
|
||||
|
||||
// GetQuarkService 获取夸克网盘服务单例
|
||||
func (f *PanFactory) GetQuarkService(config *PanConfig) PanService {
|
||||
func (f *PanFactory)/ GetQuarkService(config *PanConfig) PanService {
|
||||
service := NewQuarkPanService(config)
|
||||
return service
|
||||
}
|
||||
@@ -169,6 +176,11 @@ func (f *PanFactory) GetUCService(config *PanConfig) PanService {
|
||||
func ExtractServiceType(url string) ServiceType {
|
||||
url = strings.ToLower(url)
|
||||
|
||||
// "https://www.123pan.com/s/i4uaTd-WHn0", // 公开分享
|
||||
// "https://www.123912.com/s/U8f2Td-ZeOX",
|
||||
// "https://www.123684.coms/u9izjv-k3uWv",
|
||||
// "https://www.123pan.com/s/A6cA-AKH11", // 外链不存在
|
||||
|
||||
patterns := map[string]ServiceType{
|
||||
"pan.quark.cn": Quark,
|
||||
"www.alipan.com": Alipan,
|
||||
@@ -177,6 +189,14 @@ func ExtractServiceType(url string) ServiceType {
|
||||
"drive.uc.cn": UC,
|
||||
"fast.uc.cn": UC,
|
||||
"pan.xunlei.com": Xunlei,
|
||||
"cloud.189.cn": Tianyi,
|
||||
"www.123pan.com": Pan123,
|
||||
"www.123912.com": Pan123,
|
||||
"www.123684.com": Pan123,
|
||||
"115cdn.com": Pan115,
|
||||
"anxia.com": Pan115,
|
||||
"115.com/": Pan115,
|
||||
|
||||
}
|
||||
|
||||
for pattern, serviceType := range patterns {
|
||||
@@ -196,13 +216,24 @@ func ExtractShareId(url string) (string, ServiceType) {
|
||||
}
|
||||
|
||||
// 提取分享ID
|
||||
shareID := ""
|
||||
substring := strings.Index(url, "/s/")
|
||||
if substring == -1 {
|
||||
substring = strings.Index(url, "/t/") // 天翼云 是 t
|
||||
shareID = url[substring+3:]
|
||||
}
|
||||
if substring == -1 {
|
||||
substring = strings.Index(url, "/web/share?code=") // 天翼云 带密码
|
||||
shareID = url[substring+11:]
|
||||
}
|
||||
if substring == -1 {
|
||||
substring = strings.Index(url, "/p/") // 天翼云 是 p
|
||||
shareID = url[substring+3:]
|
||||
}
|
||||
if substring == -1 {
|
||||
return "", NotFound
|
||||
}
|
||||
|
||||
shareID := url[substring+3:] // 去除 '/s/' 部分
|
||||
|
||||
// 去除可能的锚点
|
||||
if hashIndex := strings.Index(shareID, "#"); hashIndex != -1 {
|
||||
shareID = shareID[:hashIndex]
|
||||
|
||||
@@ -63,26 +63,34 @@ func InitDB() error {
|
||||
sqlDB.SetMaxOpenConns(100) // 最大打开连接数
|
||||
sqlDB.SetConnMaxLifetime(time.Hour) // 连接最大生命周期
|
||||
|
||||
// 自动迁移数据库表结构
|
||||
err = DB.AutoMigrate(
|
||||
&entity.User{},
|
||||
&entity.Category{},
|
||||
&entity.Pan{},
|
||||
&entity.Cks{},
|
||||
&entity.Tag{},
|
||||
&entity.Resource{},
|
||||
&entity.ResourceTag{},
|
||||
&entity.ReadyResource{},
|
||||
&entity.SearchStat{},
|
||||
&entity.SystemConfig{},
|
||||
&entity.HotDrama{},
|
||||
)
|
||||
if err != nil {
|
||||
utils.Fatal("数据库迁移失败: %v", err)
|
||||
// 检查是否需要迁移(只在开发环境或首次启动时)
|
||||
if shouldRunMigration() {
|
||||
utils.Info("开始数据库迁移...")
|
||||
err = DB.AutoMigrate(
|
||||
&entity.User{},
|
||||
&entity.Category{},
|
||||
&entity.Pan{},
|
||||
&entity.Cks{},
|
||||
&entity.Tag{},
|
||||
&entity.Resource{},
|
||||
&entity.ResourceTag{},
|
||||
&entity.ReadyResource{},
|
||||
&entity.SearchStat{},
|
||||
&entity.SystemConfig{},
|
||||
&entity.HotDrama{},
|
||||
)
|
||||
if err != nil {
|
||||
utils.Fatal("数据库迁移失败: %v", err)
|
||||
}
|
||||
utils.Info("数据库迁移完成")
|
||||
} else {
|
||||
utils.Info("跳过数据库迁移(表结构已是最新)")
|
||||
}
|
||||
|
||||
// 创建索引以提高查询性能
|
||||
createIndexes(DB)
|
||||
// 创建索引以提高查询性能(只在需要迁移时)
|
||||
if shouldRunMigration() {
|
||||
createIndexes(DB)
|
||||
}
|
||||
|
||||
// 插入默认数据(只在数据库为空时)
|
||||
if err := insertDefaultDataIfEmpty(); err != nil {
|
||||
@@ -93,6 +101,32 @@ func InitDB() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// shouldRunMigration 检查是否需要运行数据库迁移
|
||||
func shouldRunMigration() bool {
|
||||
// 通过环境变量控制是否运行迁移
|
||||
skipMigration := os.Getenv("SKIP_MIGRATION")
|
||||
if skipMigration == "true" {
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查环境变量
|
||||
env := os.Getenv("ENV")
|
||||
if env == "production" {
|
||||
// 生产环境:检查是否有迁移标记
|
||||
var count int64
|
||||
DB.Raw("SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'schema_migrations'").Count(&count)
|
||||
if count == 0 {
|
||||
// 没有迁移表,说明是首次部署
|
||||
return true
|
||||
}
|
||||
// 有迁移表,检查是否需要迁移(这里可以添加更复杂的逻辑)
|
||||
return false
|
||||
}
|
||||
|
||||
// 开发环境:总是运行迁移
|
||||
return true
|
||||
}
|
||||
|
||||
// autoMigrate 自动迁移表结构
|
||||
func autoMigrate() error {
|
||||
return DB.AutoMigrate(
|
||||
@@ -112,9 +146,7 @@ func autoMigrate() error {
|
||||
|
||||
// createIndexes 创建数据库索引以提高查询性能
|
||||
func createIndexes(db *gorm.DB) {
|
||||
// 资源表索引
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resources_title ON resources USING gin(to_tsvector('chinese', title))")
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resources_description ON resources USING gin(to_tsvector('chinese', description))")
|
||||
// 资源表索引(移除全文搜索索引,使用Meilisearch替代)
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resources_category_id ON resources(category_id)")
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resources_pan_id ON resources(pan_id)")
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resources_created_at ON resources(created_at DESC)")
|
||||
@@ -122,13 +154,17 @@ func createIndexes(db *gorm.DB) {
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resources_is_valid ON resources(is_valid)")
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resources_is_public ON resources(is_public)")
|
||||
|
||||
// 为Meilisearch准备的基础文本索引(用于精确匹配)
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resources_title ON resources(title)")
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resources_description ON resources(description)")
|
||||
|
||||
// 待处理资源表索引
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_ready_resource_key ON ready_resource(key)")
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_ready_resource_url ON ready_resource(url)")
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_ready_resource_create_time ON ready_resource(create_time DESC)")
|
||||
|
||||
// 搜索统计表索引
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_search_stats_query ON search_stats(query)")
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_search_stats_keyword ON search_stats(keyword)")
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_search_stats_created_at ON search_stats(created_at DESC)")
|
||||
|
||||
// 热播剧表索引
|
||||
@@ -140,7 +176,7 @@ func createIndexes(db *gorm.DB) {
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resource_tags_resource_id ON resource_tags(resource_id)")
|
||||
db.Exec("CREATE INDEX IF NOT EXISTS idx_resource_tags_tag_id ON resource_tags(tag_id)")
|
||||
|
||||
utils.Info("数据库索引创建完成")
|
||||
utils.Info("数据库索引创建完成(已移除全文搜索索引,准备使用Meilisearch)")
|
||||
}
|
||||
|
||||
// insertDefaultDataIfEmpty 只在数据库为空时插入默认数据
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/ctwj/urldb/db/dto"
|
||||
"github.com/ctwj/urldb/db/entity"
|
||||
"github.com/ctwj/urldb/utils"
|
||||
)
|
||||
|
||||
// SystemConfigToResponse 将系统配置实体列表转换为响应DTO
|
||||
@@ -105,8 +106,8 @@ func RequestToSystemConfig(req *dto.SystemConfigRequest) []entity.SystemConfig {
|
||||
func SystemConfigToPublicResponse(configs []entity.SystemConfig) map[string]interface{} {
|
||||
response := map[string]interface{}{
|
||||
entity.ConfigResponseFieldID: 0,
|
||||
entity.ConfigResponseFieldCreatedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
entity.ConfigResponseFieldUpdatedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
entity.ConfigResponseFieldCreatedAt: utils.GetCurrentTimeString(),
|
||||
entity.ConfigResponseFieldUpdatedAt: utils.GetCurrentTimeString(),
|
||||
entity.ConfigResponseFieldSiteTitle: entity.ConfigDefaultSiteTitle,
|
||||
entity.ConfigResponseFieldSiteDescription: entity.ConfigDefaultSiteDescription,
|
||||
entity.ConfigResponseFieldKeywords: entity.ConfigDefaultKeywords,
|
||||
|
||||
@@ -2,6 +2,7 @@ package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/ctwj/urldb/db/entity"
|
||||
|
||||
@@ -18,17 +19,25 @@ type SystemConfigRepository interface {
|
||||
GetConfigValue(key string) (string, error)
|
||||
GetConfigBool(key string) (bool, error)
|
||||
GetConfigInt(key string) (int, error)
|
||||
GetCachedConfigs() map[string]string
|
||||
ClearConfigCache()
|
||||
}
|
||||
|
||||
// SystemConfigRepositoryImpl 系统配置Repository实现
|
||||
type SystemConfigRepositoryImpl struct {
|
||||
BaseRepositoryImpl[entity.SystemConfig]
|
||||
|
||||
// 配置缓存
|
||||
configCache map[string]string // key -> value
|
||||
configCacheOnce sync.Once
|
||||
configCacheMutex sync.RWMutex
|
||||
}
|
||||
|
||||
// NewSystemConfigRepository 创建系统配置Repository
|
||||
func NewSystemConfigRepository(db *gorm.DB) SystemConfigRepository {
|
||||
return &SystemConfigRepositoryImpl{
|
||||
BaseRepositoryImpl: BaseRepositoryImpl[entity.SystemConfig]{db: db},
|
||||
configCache: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +77,9 @@ func (r *SystemConfigRepositoryImpl) UpsertConfigs(configs []entity.SystemConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新配置后刷新缓存
|
||||
r.refreshConfigCache()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -108,12 +120,68 @@ func (r *SystemConfigRepositoryImpl) GetOrCreateDefault() ([]entity.SystemConfig
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
// initConfigCache 初始化配置缓存
|
||||
func (r *SystemConfigRepositoryImpl) initConfigCache() {
|
||||
r.configCacheOnce.Do(func() {
|
||||
// 获取所有配置
|
||||
configs, err := r.FindAll()
|
||||
if err != nil {
|
||||
// 如果获取失败,尝试创建默认配置
|
||||
configs, err = r.GetOrCreateDefault()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化缓存
|
||||
r.configCacheMutex.Lock()
|
||||
defer r.configCacheMutex.Unlock()
|
||||
|
||||
for _, config := range configs {
|
||||
r.configCache[config.Key] = config.Value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// refreshConfigCache 刷新配置缓存
|
||||
func (r *SystemConfigRepositoryImpl) refreshConfigCache() {
|
||||
// 重置Once,允许重新初始化
|
||||
r.configCacheOnce = sync.Once{}
|
||||
|
||||
// 清空缓存
|
||||
r.configCacheMutex.Lock()
|
||||
r.configCache = make(map[string]string)
|
||||
r.configCacheMutex.Unlock()
|
||||
|
||||
// 重新初始化缓存
|
||||
r.initConfigCache()
|
||||
}
|
||||
|
||||
// GetConfigValue 获取配置值(字符串)
|
||||
func (r *SystemConfigRepositoryImpl) GetConfigValue(key string) (string, error) {
|
||||
// 初始化缓存
|
||||
r.initConfigCache()
|
||||
|
||||
// 从缓存中读取
|
||||
r.configCacheMutex.RLock()
|
||||
value, exists := r.configCache[key]
|
||||
r.configCacheMutex.RUnlock()
|
||||
|
||||
if exists {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// 如果缓存中没有,尝试从数据库获取(可能是新添加的配置)
|
||||
config, err := r.FindByKey(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 更新缓存
|
||||
r.configCacheMutex.Lock()
|
||||
r.configCache[key] = config.Value
|
||||
r.configCacheMutex.Unlock()
|
||||
|
||||
return config.Value, nil
|
||||
}
|
||||
|
||||
@@ -146,3 +214,29 @@ func (r *SystemConfigRepositoryImpl) GetConfigInt(key string) (int, error) {
|
||||
_, err = fmt.Sscanf(value, "%d", &result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// GetCachedConfigs 获取所有缓存的配置(用于调试)
|
||||
func (r *SystemConfigRepositoryImpl) GetCachedConfigs() map[string]string {
|
||||
r.initConfigCache()
|
||||
|
||||
r.configCacheMutex.RLock()
|
||||
defer r.configCacheMutex.RUnlock()
|
||||
|
||||
// 返回缓存的副本
|
||||
result := make(map[string]string)
|
||||
for k, v := range r.configCache {
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ClearConfigCache 清空配置缓存(用于测试或手动刷新)
|
||||
func (r *SystemConfigRepositoryImpl) ClearConfigCache() {
|
||||
r.configCacheMutex.Lock()
|
||||
r.configCache = make(map[string]string)
|
||||
r.configCacheMutex.Unlock()
|
||||
|
||||
// 重置Once,允许重新初始化
|
||||
r.configCacheOnce = sync.Once{}
|
||||
}
|
||||
|
||||
8
main.go
8
main.go
@@ -81,6 +81,14 @@ func main() {
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
|
||||
// 确保默认配置存在
|
||||
_, err := repoManager.SystemConfigRepository.GetOrCreateDefault()
|
||||
if err != nil {
|
||||
utils.Error("初始化默认配置失败: %v", err)
|
||||
} else {
|
||||
utils.Info("默认配置初始化完成")
|
||||
}
|
||||
|
||||
// 检查系统配置,决定是否启动各种自动任务
|
||||
autoProcessReadyResources, err := repoManager.SystemConfigRepository.GetConfigBool(entity.ConfigKeyAutoProcessReadyResources)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user