package fqapi import ( "encoding/hex" "fmt" "time" ) // HandleMangaImageProxy 处理漫画图片代理请求 func HandleMangaImageProxy(itemID string, index int) ([]byte, string, error) { // 从缓存获取图片信息 cacheKey := fmt.Sprintf("%s_%d", itemID, index) mangaCacheMutex.RLock() imageInfo, exists := mangaImageCache[cacheKey] mangaCacheMutex.RUnlock() if !exists { return nil, "", fmt.Errorf("图片信息不存在,请先调用 /manga 接口") } // 检查缓存是否过期(5分钟) if time.Since(imageInfo.CachedAt) > 5*time.Minute { // 清理过期缓存 mangaCacheMutex.Lock() delete(mangaImageCache, cacheKey) mangaCacheMutex.Unlock() return nil, "", fmt.Errorf("图片信息已过期,请重新调用 /manga 接口") } // 下载加密图片 encryptedData, err := downloadImageWithRetry(imageInfo.PicURL, 2) if err != nil { return nil, "", fmt.Errorf("下载图片失败: %w", err) } // 解密图片 keyBytes, err := hex.DecodeString(imageInfo.EncryptKey) if err != nil { return nil, "", fmt.Errorf("密钥解码失败: %w", err) } decryptedData, err := decryptImage(encryptedData, keyBytes) if err != nil { return nil, "", fmt.Errorf("解密失败: %w", err) } // 识别格式 format := getImageFormat(decryptedData, imageInfo.PicURL) // 返回图片数据和MIME类型 mimeType := fmt.Sprintf("image/%s", format) if format == "jpg" { mimeType = "image/jpeg" } return decryptedData, mimeType, nil } // CleanExpiredMangaCache 清理过期的漫画图片缓存 func CleanExpiredMangaCache() { mangaCacheMutex.Lock() defer mangaCacheMutex.Unlock() now := time.Now() for key, info := range mangaImageCache { if now.Sub(info.CachedAt) > 5*time.Minute { delete(mangaImageCache, key) } } }