feat: Add low resolution resource images retrieval and update functionality

This commit is contained in:
2025-11-17 20:54:04 +08:00
parent 43273fece2
commit b811ca25c4
4 changed files with 239 additions and 0 deletions

View File

@@ -400,6 +400,108 @@ func handleGetLowResolutionCharacters(c fiber.Ctx) error {
})
}
func handleGetLowResolutionResourceImages(c fiber.Ctx) error {
pageStr := c.Query("page")
if pageStr == "" {
pageStr = "1"
}
page, err := strconv.Atoi(pageStr)
if err != nil {
return model.NewRequestError("Invalid page number")
}
// 支持自定义页面大小默认50最大1000
pageSizeStr := c.Query("page_size")
if pageSizeStr == "" {
pageSizeStr = "50"
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil {
return model.NewRequestError("Invalid page_size parameter")
}
if pageSize > 1000 {
pageSize = 1000 // 限制最大页面大小
}
if pageSize < 1 {
pageSize = 1
}
maxWidthStr := c.Query("max_width")
if maxWidthStr == "" {
maxWidthStr = "800" // 默认最大宽度800px
}
maxWidth, err := strconv.Atoi(maxWidthStr)
if err != nil {
return model.NewRequestError("Invalid max_width parameter")
}
maxHeightStr := c.Query("max_height")
if maxHeightStr == "" {
maxHeightStr = "800" // 默认最大高度800px
}
maxHeight, err := strconv.Atoi(maxHeightStr)
if err != nil {
return model.NewRequestError("Invalid max_height parameter")
}
images, totalPages, err := service.GetLowResolutionResourceImages(page, pageSize, maxWidth, maxHeight)
if err != nil {
return err
}
if images == nil {
images = []model.LowResResourceImageView{}
}
return c.Status(fiber.StatusOK).JSON(model.PageResponse[model.LowResResourceImageView]{
Success: true,
Data: images,
TotalPages: totalPages,
Message: "Low resolution resource images retrieved successfully",
})
}
func handleUpdateResourceImage(c fiber.Ctx) error {
resourceIdStr := c.Params("resourceId")
oldImageIdStr := c.Params("oldImageId")
if resourceIdStr == "" || oldImageIdStr == "" {
return model.NewRequestError("Resource ID and Old Image ID are required")
}
resourceId, err := strconv.Atoi(resourceIdStr)
if err != nil {
return model.NewRequestError("Invalid resource ID")
}
oldImageId, err := strconv.Atoi(oldImageIdStr)
if err != nil {
return model.NewRequestError("Invalid old image ID")
}
var params struct {
NewImageID uint `json:"new_image_id"`
}
body := c.Body()
err = json.Unmarshal(body, &params)
if err != nil {
return model.NewRequestError("Invalid request body")
}
uid, ok := c.Locals("uid").(uint)
if !ok {
return model.NewUnAuthorizedError("You must be logged in to update a resource image")
}
err = service.UpdateResourceImage(uid, uint(resourceId), uint(oldImageId), params.NewImageID)
if err != nil {
return err
}
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
Success: true,
Data: nil,
Message: "Resource image updated successfully",
})
}
func AddResourceRoutes(api fiber.Router) {
resource := api.Group("/resource")
{
@@ -410,11 +512,13 @@ func AddResourceRoutes(api fiber.Router) {
resource.Get("/pinned", handleGetPinnedResources)
resource.Get("/vndb/characters", handleGetCharactersFromVndb)
resource.Get("/characters/low-resolution", handleGetLowResolutionCharacters)
resource.Get("/images/low-resolution", handleGetLowResolutionResourceImages)
resource.Get("/:id", handleGetResource)
resource.Delete("/:id", handleDeleteResource)
resource.Get("/tag/:tag", handleListResourcesWithTag)
resource.Get("/user/:username", handleGetResourcesWithUser)
resource.Post("/:id", handleUpdateResource)
resource.Put("/:resourceId/character/:characterId/image", handleUpdateCharacterImage)
resource.Put("/:resourceId/image/:oldImageId", handleUpdateResourceImage)
}
}

View File

@@ -2,6 +2,7 @@ package dao
import (
"errors"
"fmt"
"math/rand"
"nysoure/server/model"
"sync"
@@ -593,3 +594,81 @@ func GetLowResolutionCharactersCount(maxWidth, maxHeight int) (int64, error) {
return count, nil
}
// GetLowResolutionResourceImages 获取低清晰度的资源图片
// maxWidth和maxHeight定义了低清晰度的阈值
func GetLowResolutionResourceImages(maxWidth, maxHeight int, limit int, offset int) ([]model.LowResResourceImageView, error) {
var results []model.LowResResourceImageView
query := `
SELECT DISTINCT
r.id as resource_id,
r.title as title,
i.id as image_id,
i.width as image_width,
i.height as image_height
FROM resources r
INNER JOIN resource_images ri ON r.id = ri.resource_id
INNER JOIN images i ON ri.image_id = i.id
WHERE (i.width <= ? OR i.height <= ?)
ORDER BY r.id, i.id
LIMIT ? OFFSET ?
`
err := db.Raw(query, maxWidth, maxHeight, limit, offset).Scan(&results).Error
if err != nil {
return nil, err
}
return results, nil
}
// GetLowResolutionResourceImagesCount 获取低清晰度资源图片的总数
func GetLowResolutionResourceImagesCount(maxWidth, maxHeight int) (int64, error) {
var count int64
query := `
SELECT COUNT(DISTINCT ri.resource_id, ri.image_id)
FROM resources r
INNER JOIN resource_images ri ON r.id = ri.resource_id
INNER JOIN images i ON ri.image_id = i.id
WHERE (i.width <= ? OR i.height <= ?)
`
err := db.Raw(query, maxWidth, maxHeight).Scan(&count).Error
if err != nil {
return 0, err
}
return count, nil
}
// UpdateResourceImage 更新资源中特定的图片ID
func UpdateResourceImage(resourceID, oldImageID, newImageID uint) error {
return db.Transaction(func(tx *gorm.DB) error {
// 首先检查关联是否存在
var exists bool
err := tx.Raw("SELECT EXISTS(SELECT 1 FROM resource_images WHERE resource_id = ? AND image_id = ?)",
resourceID, oldImageID).Scan(&exists).Error
if err != nil {
return err
}
if !exists {
return fmt.Errorf("resource %d does not have image %d", resourceID, oldImageID)
}
// 更新resource_images表中的image_id
result := tx.Exec("UPDATE resource_images SET image_id = ? WHERE resource_id = ? AND image_id = ?",
newImageID, resourceID, oldImageID)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return fmt.Errorf("no resource image association updated")
}
return nil
})
}

View File

@@ -60,6 +60,14 @@ type ResourceDetailView struct {
Characters []CharacterView `json:"characters"`
}
type LowResResourceImageView struct {
ResourceID uint `json:"resource_id"`
Title string `json:"title"`
ImageID uint `json:"image_id"`
ImageWidth int `json:"image_width"`
ImageHeight int `json:"image_height"`
}
func (r *Resource) ToView() ResourceView {
tags := make([]TagView, len(r.Tags))
for i, tag := range r.Tags {

View File

@@ -832,3 +832,51 @@ func GetLowResolutionCharacters(page int, pageSize int, maxWidth, maxHeight int)
return characters, totalPages, nil
}
// GetLowResolutionResourceImages 获取低清晰度的资源图片
func GetLowResolutionResourceImages(page int, pageSize int, maxWidth, maxHeight int) ([]model.LowResResourceImageView, int, error) {
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 50 // 默认每页50个图片
}
if pageSize > 1000 {
pageSize = 1000 // 限制最大页面大小
}
offset := (page - 1) * pageSize
// 获取资源图片列表
images, err := dao.GetLowResolutionResourceImages(maxWidth, maxHeight, pageSize, offset)
if err != nil {
return nil, 0, err
}
// 获取总数
totalCount, err := dao.GetLowResolutionResourceImagesCount(maxWidth, maxHeight)
if err != nil {
return nil, 0, err
}
totalPages := int((totalCount + int64(pageSize) - 1) / int64(pageSize))
return images, totalPages, nil
}
// UpdateResourceImage 更新资源图片
func UpdateResourceImage(uid, resourceID, oldImageID, newImageID uint) error {
// 首先检查用户权限 - 确保用户是资源的所有者或管理员
resource, err := dao.GetResourceByID(resourceID)
if err != nil {
return err
}
if resource.UserID != uid {
// 可以在这里添加管理员权限检查
return model.NewUnAuthorizedError("You don't have permission to update this resource")
}
// 更新资源图片
return dao.UpdateResourceImage(resourceID, oldImageID, newImageID)
}