增加更多分辨率图像的拉取

This commit is contained in:
2026-01-27 15:34:38 +08:00
parent 9c2a5d5cd8
commit d757dbd39d
16 changed files with 587 additions and 97 deletions

View File

@@ -157,7 +157,7 @@ func Init(configPath string) error {
v.SetDefault("api.mode", "local")
v.SetDefault("cron.enabled", true)
v.SetDefault("cron.daily_spec", "0 10 * * *")
v.SetDefault("retention.days", 30)
v.SetDefault("retention.days", 0)
v.SetDefault("db.type", "sqlite")
v.SetDefault("db.dsn", "data/bing_paper.db")
v.SetDefault("storage.type", "local")

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"io"
"net/http"
"strconv"
"BingPaper/internal/config"
"BingPaper/internal/model"
@@ -40,7 +41,7 @@ type ImageMetaResp struct {
// @Summary 获取今日图片
// @Description 根据参数返回今日必应图片流或重定向
// @Tags image
// @Param variant query string false "分辨率 (UHD, 1920x1080, 1366x768)" default(UHD)
// @Param variant query string false "分辨率 (UHD, 1920x1080, 1366x768, 1280x720, 1024x768, 800x600, 800x480, 640x480, 640x360, 480x360, 400x240, 320x240)" default(UHD)
// @Param format query string false "格式 (jpg)" default(jpg)
// @Produce image/jpeg
// @Success 200 {file} binary
@@ -144,19 +145,53 @@ func GetByDateMeta(c *gin.Context) {
// ListImages 获取图片列表
// @Summary 获取图片列表
// @Description 分页获取已抓取的图片元数据列表
// @Description 分页获取已抓取的图片元数据列表。支持分页(page, page_size)、限制数量(limit)和按月份过滤(month, 格式: YYYY-MM)。
// @Tags image
// @Param limit query int false "限制数量" default(30)
// @Param limit query int false "限制数量 (如果不使用分页)" default(30)
// @Param page query int false "页码 (从1开始)"
// @Param page_size query int false "每页数量"
// @Param month query string false "按月份过滤 (格式: YYYY-MM)"
// @Produce json
// @Success 200 {array} ImageMetaResp
// @Router /images [get]
func ListImages(c *gin.Context) {
limitStr := c.DefaultQuery("limit", "30")
var limit int
fmt.Sscanf(limitStr, "%d", &limit)
limitStr := c.Query("limit")
pageStr := c.Query("page")
pageSizeStr := c.Query("page_size")
month := c.Query("month")
images, err := image.GetImageList(limit)
// 记录请求参数,便于排查过滤失效问题
util.Logger.Debug("ListImages parameters",
zap.String("month", month),
zap.String("page", pageStr),
zap.String("page_size", pageSizeStr),
zap.String("limit", limitStr))
var limit, offset int
if pageStr != "" && pageSizeStr != "" {
page, _ := strconv.Atoi(pageStr)
pageSize, _ := strconv.Atoi(pageSizeStr)
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 30
}
limit = pageSize
offset = (page - 1) * pageSize
} else {
if limitStr == "" {
limit = 30
} else {
limit, _ = strconv.Atoi(limitStr)
}
offset = 0
}
images, err := image.GetImageList(limit, offset, month)
if err != nil {
util.Logger.Error("ListImages service call failed", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

View File

@@ -142,36 +142,47 @@ func (f *Fetcher) processImage(ctx context.Context, bingImg BingImage) error {
}
// 保存各种分辨率
variants := []struct {
targetVariants := []struct {
name string
width int
height int
}{
{variantName, 0, 0}, // 原图 (UHD 或 1080p)
{"1920x1080", 1920, 1080},
{"1366x768", 1366, 768},
{"1280x720", 1280, 720},
{"1024x768", 1024, 768},
{"800x600", 800, 600},
{"800x480", 800, 480},
{"640x480", 640, 480},
{"640x360", 640, 360},
{"480x360", 480, 360},
{"400x240", 400, 240},
{"320x240", 320, 240},
}
for _, v := range variants {
// 如果是探测到的最高清版本,且我们已经有了数据,直接使用
var currentImgData []byte
if v.width == 0 {
currentImgData = imgData
} else {
resized := imaging.Fill(srcImg, v.width, v.height, imaging.Center, imaging.Lanczos)
buf := new(bytes.Buffer)
if err := jpeg.Encode(buf, resized, &jpeg.Options{Quality: 90}); err != nil {
util.Logger.Warn("Failed to encode jpeg", zap.String("variant", v.name), zap.Error(err))
continue
}
currentImgData = buf.Bytes()
// 首先保存原图 (UHD 或 1080p)
if err := f.saveVariant(ctx, &dbImg, variantName, "jpg", imgData); err != nil {
util.Logger.Error("Failed to save original variant", zap.String("variant", variantName), zap.Error(err))
}
for _, v := range targetVariants {
// 如果目标分辨率就是原图分辨率,则跳过(已经保存过了)
if v.name == variantName {
continue
}
resized := imaging.Fill(srcImg, v.width, v.height, imaging.Center, imaging.Lanczos)
buf := new(bytes.Buffer)
if err := jpeg.Encode(buf, resized, &jpeg.Options{Quality: 100}); err != nil {
util.Logger.Warn("Failed to encode jpeg", zap.String("variant", v.name), zap.Error(err))
continue
}
currentImgData := buf.Bytes()
// 保存 JPG
if err := f.saveVariant(ctx, &dbImg, v.name, "jpg", currentImgData); err != nil {
util.Logger.Error("Failed to save variant", zap.String("variant", v.name), zap.Error(err))
}
}
// 保存今日额外文件
@@ -241,13 +252,13 @@ func (f *Fetcher) saveDailyFiles(srcImg image.Image, originalData []byte) {
return
}
// daily.jpeg (quality 95)
// daily.jpeg (quality 100)
jpegPath := filepath.Join(localRoot, "daily.jpeg")
fJpeg, err := os.Create(jpegPath)
if err != nil {
util.Logger.Error("Failed to create daily.jpeg", zap.Error(err))
} else {
jpeg.Encode(fJpeg, srcImg, &jpeg.Options{Quality: 95})
jpeg.Encode(fJpeg, srcImg, &jpeg.Options{Quality: 100})
fJpeg.Close()
}

View File

@@ -86,12 +86,29 @@ func GetImageByDate(date string) (*model.Image, error) {
return &img, err
}
func GetImageList(limit int) ([]model.Image, error) {
func GetImageList(limit int, offset int, month string) ([]model.Image, error) {
var images []model.Image
db := repo.DB.Order("date desc").Preload("Variants")
if limit > 0 {
db = db.Limit(limit)
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+"%")
}
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))
}
err := db.Find(&images).Error
return images, err
}