最近继续折腾
LSky Pro图床,发现原有的图片查询接口有点"死板",只能按相册查,不能按存储策略查,也不能跨相册获取所有图片。于是又开始了一番改造 😏
这篇文章记录了我对 LSky Pro 图片接口的两个主要改进:
1. 升级图片查询接口,支持按存储策略灵活查询
2. 上传接口新增指定相册功能
📝 问题分析
原有的 /api/v1/images 接口存在以下限制:
| 问题 | 说明 |
|---|---|
| 无法获取所有图片 | 不传 album_id 只返回未分类图片,无法跨相册查询 |
| 无法按存储策略筛选 | 没有 strategy_id 参数支持 |
| 分页数量固定 | 写死 40 条,无法通过参数调整 |
这显然不够灵活,所以决定动手改一改 🔧
🛠️ 实现步骤
1. 新建控制器
在路径 app/Http/Controllers/Api/V1/ 下新建控制器Images2Controller.php
核心代码如下:
<?php
namespace App\Http\Controllers\Api\V1;
use App\Enums\ImagePermission;
use App\Http\Controllers\Controller;
use App\Models\Image;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
/**
* 图片列表接口 v2
* 20251214 by Tim 新增:支持按存储策略、相册灵活查询图片
*/
class Images2Controller extends Controller
{
/**
* 获取图片列表
*
* 参数组合逻辑:
* - 无参数:返回默认相册(未分类)的图片
* - album_id=5:返回相册5的所有图片
* - strategy_id=1:返回存储策略1的所有图片(跨相册)
* - strategy_id=1&album_id=5:返回存储策略1且相册5的图片
*/
public function index(Request $request): Response
{
/** @var User $user */
$user = Auth::user();
$strategyId = (int) $request->query('strategy_id');
$albumId = (int) $request->query('album_id');
$perPage = (int) $request->query('per_page') ?: 40;
// 验证用户是否有权限访问该存储策略
if ($strategyId) {
$hasAccess = $user->group->strategies()->where('strategies.id', $strategyId)->exists();
if (! $hasAccess) {
return $this->fail('无权访问该存储策略');
}
}
// 语法:->when(条件,true回调,false回调)
$images = $user->images()
// 按存储策略过滤
->when($strategyId, function (Builder $builder, $strategyId) {
$builder->where('strategy_id', $strategyId);
})
// 相册过滤
->when($albumId, function (Builder $builder, $albumId) {
// 有相册ID,按相册过滤
$builder->where('album_id', $albumId);
}, function (Builder $builder) use ($strategyId) {
// 没有相册ID时:有存储策略则不限制相册,没有存储策略则返回默认相册(未分类)
if (!$strategyId) {
$builder->whereNull('album_id');
}
})
// 排序
->when($request->query('order') ?: 'newest', function (Builder $builder, $order) {
switch ($order) {
case 'earliest':
$builder->orderBy('created_at');
break;
case 'utmost':
$builder->orderByDesc('size');
break;
case 'least':
$builder->orderBy('size');
break;
default:
$builder->latest();
}
})
// 权限过滤
->when($request->query('permission') ?: 'all', function (Builder $builder, $permission) {
switch ($permission) {
case 'public':
$builder->where('permission', ImagePermission::Public);
break;
case 'private':
$builder->where('permission', ImagePermission::Private);
break;
}
})
// 关键词搜索
->when($request->query('keyword'), function (Builder $builder, $keyword) {
$builder->where(function (Builder $query) use ($keyword) {
$query->where('origin_name', 'like', "%{$keyword}%")
->orWhere('alias_name', 'like', "%{$keyword}%");
});
})
->paginate($perPage)
->withQueryString();
// 处理返回字段,与 images 接口保持一致
$images->getCollection()->each(function (Image $image) {
$image->human_date = $image->created_at->diffForHumans();
$image->date = $image->created_at->format('Y-m-d H:i:s');
$image->append(['pathname', 'links'])->setVisible([
'album', 'key', 'name', 'pathname', 'origin_name', 'size', 'mimetype', 'extension', 'md5', 'sha1',
'width', 'height', 'links', 'human_date', 'date',
]);
});
return $this->success('success', $images);
}
}
2. 配置路由
编辑 routes/api.php,用新控制器替换原有路由:
<?php
use App\Http\Controllers\Api\V1\Images2Controller; //20251214 by Tim
Route::group([
'middleware' => 'auth:sanctum',
], function () {
// [!code --]
Route::get('images', [ImageController::class, 'images']);
// [!code ++]
Route::get('images', [Images2Controller::class, 'index']); //20251214 by Tim 新增图片获取,支持按存储策略、相册查询
// ...其他路由
});3. 参数组合逻辑
新接口的查询逻辑:
| 参数组合 | 返回结果 |
|---|---|
| 无参数 | 默认相册(未分类)的图片 |
| album_id=5 | 相册5的所有图片 |
| strategy_id=1 | 存储策略1的所有图片(跨相册) ✨ |
| strategy_id=1&album_id=5 | 存储策略1 且 相册5 的图片 |
这样就能灵活地按存储策略或相册来查询图片了 🎉
📤 上传支持指定相册
顺便把上传接口也改进了一下,支持在上传时直接指定相册。
修改文件
编辑 app/Services/ImageService.php,在 public function store(Request $request): Image 函数中添加相册参数支持:
// 默认储存策略
if (! is_null($user)) {
if (Utils::config(ConfigKey::IsUserNeedVerify) && ! $user->email_verified_at) {
throw new UploadException('账户未验证');
}
if ($user->status !== UserStatus::Normal) {
throw new UploadException('账号状态异常');
}
if ($file->getSize() / 1024 + $user->images()->sum('size') > $user->capacity) {
throw new UploadException('储存空间不足');
}
// [!code ++:9]
// 20251213 by Tim 新增API上传支持指定相册。确定图片所属相册:优先使用请求指定的相册,否则使用用户默认相册
$albumId = $request->has('album_id')
? $request->input('album_id')
: $user->configs->get(UserConfigKey::DefaultAlbum);
if ($albumId) {
if (!$user->albums()->where('id', $albumId)->exists()) {
throw new UploadException('指定的相册不存在或不属于您');
}
$image->album_id = $albumId;
}
$image->user_id = $user->id;
// 用户设置的图片默认权限
$image->permission = $user->configs->get(UserConfigKey::DefaultPermission, ImagePermission::Private);
}使用方式
POST /api/v1/upload
Authorization: Bearer {token}
Content-Type: multipart/form-data
file: (图片文件)
album_id: 1 # 可选,指定相册ID
strategy_id: 1 # 可选,指定存储策略ID参数说明
| 参数 | 行为 |
|---|---|
| 不传 album_id | 使用用户默认相册设置 |
| album_id=1 | 保存到指定相册(需属于当前用户) |
| album_id= (空值) | 不保存到任何相册(覆盖默认设置) |
🩹 顺手修复图片格式排除
在折腾的过程中,发现一些特殊格式(PSD、TIF、BMP 等)在处理时会出问题,于是顺手加了格式排除(虽然我目前用不上)。
格式排除汇总
| 处理环节 | 排除格式 |
|---|---|
| 图片处理(压缩/水印) | ico, gif, svg, psd, tif, bmp, mp4, mov, avi, mkv, webm |
| 图片检测(审核) | psd, ico, tif, bmp, svg, mp4, mov, avi, mkv, webm |
| 缩略图生成 | svg, psd, tif, bmp, ico, mp4, mov, avi, mkv, webm |
🧪 使用示例
查询图片
# 获取默认相册(未分类)图片
curl -H "Authorization: Bearer your_token" \
"https://your-lsky.com/api/v1/images"
# 获取存储策略1的所有图片(跨相册)
curl -H "Authorization: Bearer your_token" \
"https://your-lsky.com/api/v1/images?strategy_id=1"
# 获取存储策略1下相册5的图片,每页20条
curl -H "Authorization: Bearer your_token" \
"https://your-lsky.com/api/v1/images?strategy_id=1&album_id=5&per_page=20"上传到指定相册
curl -X POST \
-H "Authorization: Bearer your_token" \
-F "file=@photo.jpg" \
-F "album_id=3" \
"https://your-lsky.com/api/v1/upload"✅ 总结
本次改造完成了以下功能:
| 功能 | 说明 |
|---|---|
| 图片查询升级 | 支持按存储策略查询,支持自定义分页 |
| 上传指定相册 | 上传时可直接指定目标相册 |
| 格式排除优化 | 特殊格式不再报错 |
修改文件汇总
| 文件 | 修改类型 | 说明 |
|---|---|---|
| app/Http/Controllers/Api/V1/Images2Controller.php | 新建 | 图片查询接口 v2 |
| app/Services/ImageService.php | 修改 | 添加相册参数支持、格式排除 |
| routes/api.php | 修改 | 更新路由配置 |
完全向后兼容,原有调用方式不受影响,只是多了新功能 ~
补充
同时也对 halo-lsky-pro 插件进行升级,适配 Halo 2.22 并且上传支持相册