service.xpcool.com/internal/model/dto/wallpaper.go
夏犀麟 582485ba2b feat(wallpaper): 壁纸模块后端(开源平台插件 + 自建图库 + 前后台接口)
需求:前台壁纸站支持切换到开源壁纸平台,并能展示后台上传的自家图库,
保留原有「浏览器实时生成」能力(扩展而非替换),PC / 移动双端一致。

设计要点(受服务器 5M 出口带宽约束):
- 开源平台图片一律走官方 CDN 直链,后端只代理元数据,零带宽消耗。
- 自建图库落盘到 /data/www/wallpaper,由 nginx 的 /wallpaper/ 直出,
  Go 服务不参与传图;三档尺寸(480 缩略 / 1920 预览 / 原图仅供下载)。
- 内存缓存平台响应(Bing 1h、搜索类 10min),避免撞第三方配额。

内容:
- 平台插件:Bing 每日一图、Picsum、Unsplash、Pexels、Wallhaven。
  新增平台 = 写一个 provider_xxx.go 并在 allProviders() 加一行,
  刻意不用 init() 自注册,避免隐式副作用。所有适配器支持 config.baseUrl
  覆盖,用于绕开 DNS 污染(实测 wallhaven.cc 解析到境外无关 IP)。
- 自建图库:上传(MD5 秒传去重 / 尺寸前置校验 / 失败清理孤儿文件)、
  元信息编辑、删除、统计;随机取图用「数总数 → 随机偏移」而非 ORDER BY RAND()。
- 接口:open 组 4 个(sources / list / random / download-track),
  admin 组 8 个(list / upload / save / delete / stats / source.list|save|test)。
  全部 POST 且 URL 无参数,符合工作空间接口规范;上传走 multipart 例外。
- 安全:purity 默认锁死 SFW;apiKey 只回传布尔不回传明文;
  保存时留空表示保留旧值;open 组错误信息对外脱敏。
- 配置:clientMaxBodySize 提到 64M(gf 默认 8M 会截断 20MB 原图);
  wallpaper.root / baseUrl 支持环境变量注入并在占位符未替换时兜底。

依赖:golang.org/x/image@v0.23.0(仅用于缩略图缩放,保持 go 1.23.0 不变)。
2026-09-14 01:39:09 +08:00

122 lines
5.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package dto 壁纸模块的数据传输对象。
//
// 设计要点:**把「开源平台」和「自建图库」两种来源统一成同一个输出形状
// WallpaperItem**,前端拿到的东西长得一模一样 —— 分页、渲染、下载、
// 全屏都只需要一套代码。来源差异只在后端消化。
package dto
// WallpaperItem 是壁纸模块对外的统一输出条目。
//
// 无论图片来自开源平台还是自建图库,都填这个结构:
// - FromOpen=true 时 Id 为平台内 id用于下载上报Url 指向平台 CDN
// - FromOpen=false 时 Id 为库内主键Url 指向本站 nginx 直出的原图。
type WallpaperItem struct {
// ---- 通用 ----
Id string `json:"id"`
Title string `json:"title"`
Width int `json:"width"`
Height int `json:"height"`
Orientation int `json:"orientation"` // 0未知 1横版 2竖版 3方形
// ---- 三档图片地址 ----
// Thumb 用于列表网格、Preview 用于全屏展示、Full 用于下载。
// 自建图库这三者分别是 480px 缩略图 / 长边 1920 预览图 / 原图;
// 开源平台则取各平台 CDN 提供的对应尺寸,没有的就退回上一档。
ThumbUrl string `json:"thumbUrl"`
PreviewUrl string `json:"previewUrl"`
FullUrl string `json:"fullUrl"`
// ---- 归属 ----
Source string `json:"source"` // 平台编码,自建图库固定为 "mine"
SourceName string `json:"sourceName"` // 平台显示名,用于界面标注
FromOpen bool `json:"fromOpen"` // true=开源平台 false=自建图库
// ---- 版权信息(自建图库留空)----
Author string `json:"author"`
AuthorUrl string `json:"authorUrl"`
PageUrl string `json:"pageUrl"` // 平台详情页,用于「查看原页面」
License string `json:"license"` // 许可说明,如 "Unsplash License"
// ---- 自建图库专有 ----
Tags string `json:"tags"`
Category string `json:"category"`
Filesize int64 `json:"filesize"`
CreatedAt string `json:"createdAt"`
}
// WallpaperSourceInfo 是开源平台的可用性描述,供前端渲染平台切换器。
//
// Enabled 与 Configured 要分开看:前者是用户的开关,后者是凭据是否齐备。
// 两者都为真时 Available 才为真 —— 前端据此把平台置灰并给出 Hint
// 而不是点了没反应。
type WallpaperSourceInfo struct {
Code string `json:"code"`
Name string `json:"name"`
Enabled int `json:"enabled"`
Sort int `json:"sort"`
Configured bool `json:"configured"`
Available bool `json:"available"`
Hint string `json:"hint"` // 不可用原因,可用时为空
Remark string `json:"remark"`
// Config 是脱敏后的配置apiKey 只回传是否已设置,不回传明文)。
HasApiKey bool `json:"hasApiKey"`
}
// WallpaperSourceConfig 对应 wallpaper_source.config 字段的 JSON。
//
// 全部字段可选:缺失即用该平台的默认值。解析失败不报错、回退全默认,
// 避免一个平台的脏配置拖垮整个来源列表。
type WallpaperSourceConfig struct {
// ApiKey / ApiSecret 平台凭据。Bing 与 Picsum 不需要。
ApiKey string `json:"apiKey"`
ApiSecret string `json:"apiSecret"`
// DefaultQuery 默认搜索词,用户没传关键词时用。
DefaultQuery string `json:"defaultQuery"`
// Purity 分级过滤Wallhavensfw / sketchy / nsfw。默认只放 sfw。
Purity string `json:"purity"`
// Categories 分类Wallhavengeneral/anime/people 的组合,逗号分隔。
Categories string `json:"categories"`
// BaseUrl 可选覆盖平台接口地址(便于自建反代或走镜像)。
BaseUrl string `json:"baseUrl"`
}
// WallpaperSourceSaveInput 是后台保存开源平台配置的入参。
type WallpaperSourceSaveInput struct {
Code string `json:"code"`
Name string `json:"name"`
Enabled int `json:"enabled"`
Sort int `json:"sort"`
Remark string `json:"remark"`
// Config 是 dto.WallpaperSourceConfig 的 JSON 字符串。
// 其中 apiKey 允许留空 —— 留空表示「不修改已保存的 Key」
// 这样后台就不必把密钥明文回传到前端再原样传回来。
Config string `json:"config"`
}
// WallpaperQuery 是列表查询条件,开源平台与自建图库共用。
type WallpaperQuery struct {
Source string // 平台编码;"mine" 表示自建图库
Query string // 搜索词(自建图库匹配标题/标签/分类)
Orientation int // 0不限 1横版 2竖版 3方形
Tag string // 标签(仅自建图库)
Page int
Size int
}
// WallpaperSaveInput 是后台编辑壁纸元数据的入参(不含文件本身)。
type WallpaperSaveInput struct {
Id uint64 `json:"id"`
Title string `json:"title"`
Tags string `json:"tags"`
Category string `json:"category"`
Enabled int `json:"enabled"`
Sort int `json:"sort"`
Remark string `json:"remark"`
}
// WallpaperStat 是图库概览统计。
type WallpaperStat struct {
Total int `json:"total"` // 总数
Enabled int `json:"enabled"` // 启用数
Disabled int `json:"disabled"` // 停用数
Portrait int `json:"portrait"` // 竖版数
Landscape int `json:"landscape"` // 横版数
TotalBytes int64 `json:"totalBytes"` // 原图占用字节
}