mirror of
https://git.fightbot.fun/hxuanyu/BingPaper.git
synced 2026-02-15 05:59:32 +08:00
173 lines
4.6 KiB
Go
173 lines
4.6 KiB
Go
package image
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"BingPaper/internal/config"
|
|
"BingPaper/internal/model"
|
|
"BingPaper/internal/repo"
|
|
"BingPaper/internal/storage"
|
|
"BingPaper/internal/util"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func CleanupOldImages(ctx context.Context) error {
|
|
days := config.GetConfig().Retention.Days
|
|
if days <= 0 {
|
|
return nil
|
|
}
|
|
|
|
threshold := time.Now().AddDate(0, 0, -days).Format("2006-01-02")
|
|
util.Logger.Info("Starting cleanup task", zap.Int("retention_days", days), zap.String("threshold", threshold))
|
|
|
|
var images []model.Image
|
|
if err := repo.DB.Where("date < ?", threshold).Preload("Variants").Find(&images).Error; err != nil {
|
|
util.Logger.Error("Failed to query old images for cleanup", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
for _, img := range images {
|
|
util.Logger.Info("Deleting old image", zap.String("date", img.Date))
|
|
for _, v := range img.Variants {
|
|
if err := storage.GlobalStorage.Delete(ctx, v.StorageKey); err != nil {
|
|
util.Logger.Warn("Failed to delete storage object", zap.String("key", v.StorageKey), zap.Error(err))
|
|
}
|
|
}
|
|
// 删除关联记录(逻辑外键控制)
|
|
if err := repo.DB.Where("image_id = ?", img.ID).Delete(&model.ImageVariant{}).Error; err != nil {
|
|
util.Logger.Error("Failed to delete variants", zap.Uint("image_id", img.ID), zap.Error(err))
|
|
}
|
|
// 删除主表记录
|
|
if err := repo.DB.Delete(&img).Error; err != nil {
|
|
util.Logger.Error("Failed to delete image", zap.Uint("id", img.ID), zap.Error(err))
|
|
}
|
|
}
|
|
|
|
util.Logger.Info("Cleanup task completed", zap.Int("deleted_count", len(images)))
|
|
return nil
|
|
}
|
|
|
|
func GetTodayImage(mkt string) (*model.Image, error) {
|
|
today := time.Now().Format("2006-01-02")
|
|
var img model.Image
|
|
tx := repo.DB.Where("date = ?", today)
|
|
if mkt != "" {
|
|
tx = tx.Where("mkt = ?", mkt)
|
|
}
|
|
err := tx.Preload("Variants").First(&img).Error
|
|
if err != nil {
|
|
// 如果今天没有,尝试获取最近的一张
|
|
tx = repo.DB.Order("date desc")
|
|
if mkt != "" {
|
|
tx = tx.Where("mkt = ?", mkt)
|
|
}
|
|
err = tx.Preload("Variants").First(&img).Error
|
|
}
|
|
|
|
// 兜底逻辑:如果指定地区没找到,且开启了兜底开关,则尝试获取默认地区的图片
|
|
if err != nil && mkt != "" && config.GetConfig().API.EnableMktFallback {
|
|
defaultMkt := config.GetConfig().GetDefaultMkt()
|
|
if mkt != defaultMkt {
|
|
return GetTodayImage(defaultMkt)
|
|
}
|
|
return GetTodayImage("")
|
|
}
|
|
|
|
return &img, err
|
|
}
|
|
|
|
func GetRandomImage(mkt string) (*model.Image, error) {
|
|
var img model.Image
|
|
// SQLite 使用 RANDOM(), MySQL/Postgres 使用 RANDOM() 或 RAND()
|
|
// 简单起见,先查总数再 Offset
|
|
var count int64
|
|
tx := repo.DB.Model(&model.Image{})
|
|
if mkt != "" {
|
|
tx = tx.Where("mkt = ?", mkt)
|
|
}
|
|
tx.Count(&count)
|
|
if count == 0 {
|
|
return nil, fmt.Errorf("no images found")
|
|
}
|
|
|
|
// 这种方法不适合海量数据,但对于 30 天的数据没问题
|
|
tx = repo.DB.Order("RANDOM()")
|
|
if mkt != "" {
|
|
tx = tx.Where("mkt = ?", mkt)
|
|
}
|
|
err := tx.Preload("Variants").First(&img).Error
|
|
if err != nil {
|
|
// 适配 MySQL
|
|
tx = repo.DB.Order("RAND()")
|
|
if mkt != "" {
|
|
tx = tx.Where("mkt = ?", mkt)
|
|
}
|
|
err = tx.Preload("Variants").First(&img).Error
|
|
}
|
|
|
|
// 兜底逻辑
|
|
if err != nil && mkt != "" && config.GetConfig().API.EnableMktFallback {
|
|
defaultMkt := config.GetConfig().GetDefaultMkt()
|
|
if mkt != defaultMkt {
|
|
return GetRandomImage(defaultMkt)
|
|
}
|
|
return GetRandomImage("")
|
|
}
|
|
|
|
return &img, err
|
|
}
|
|
|
|
func GetImageByDate(date string, mkt string) (*model.Image, error) {
|
|
var img model.Image
|
|
tx := repo.DB.Where("date = ?", date)
|
|
if mkt != "" {
|
|
tx = tx.Where("mkt = ?", mkt)
|
|
}
|
|
err := tx.Preload("Variants").First(&img).Error
|
|
|
|
// 兜底逻辑
|
|
if err != nil && mkt != "" && config.GetConfig().API.EnableMktFallback {
|
|
defaultMkt := config.GetConfig().GetDefaultMkt()
|
|
if mkt != defaultMkt {
|
|
return GetImageByDate(date, defaultMkt)
|
|
}
|
|
return GetImageByDate(date, "")
|
|
}
|
|
|
|
return &img, err
|
|
}
|
|
|
|
func GetImageList(limit int, offset int, month string, mkt string) ([]model.Image, error) {
|
|
var images []model.Image
|
|
tx := repo.DB.Model(&model.Image{})
|
|
|
|
if month != "" {
|
|
// 增强过滤:确保只处理 YYYY-MM 格式,防止注入或非法字符
|
|
// 这里简单处理:只要不为空就增加 LIKE 过滤
|
|
util.Logger.Debug("Filtering images by month", zap.String("month", month))
|
|
tx = tx.Where("date LIKE ?", month+"%")
|
|
}
|
|
|
|
if mkt != "" {
|
|
tx = tx.Where("mkt = ?", mkt)
|
|
}
|
|
|
|
tx = tx.Order("date desc").Preload("Variants")
|
|
|
|
if limit > 0 {
|
|
tx = tx.Limit(limit)
|
|
}
|
|
if offset > 0 {
|
|
tx = tx.Offset(offset)
|
|
}
|
|
|
|
err := tx.Find(&images).Error
|
|
if err != nil {
|
|
util.Logger.Error("Failed to get image list", zap.Error(err), zap.String("month", month))
|
|
}
|
|
return images, err
|
|
}
|