Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38d52c4609 | ||
|
|
2b3f31a204 | ||
|
|
94332ee597 | ||
|
|
aa6dd044ba | ||
|
|
aa9aa31c42 | ||
|
|
bbdb1fb39d | ||
|
|
b3f3594cd5 | ||
|
|
c0504fe62f | ||
|
|
0bc23c796d | ||
|
|
011b291e05 | ||
|
|
effe173d9c | ||
|
|
bdd440d38f | ||
|
|
fe5e4d9a67 | ||
|
|
66d7a0dce1 | ||
|
|
4f13d7d5a1 | ||
|
|
093ef71c2c | ||
|
|
4a87a90d5b | ||
|
|
17cb901046 | ||
|
|
c0ba47d47d | ||
|
|
1d0cb15854 | ||
|
|
465ff63230 | ||
|
|
04a421d3eb | ||
|
|
2642719769 | ||
|
|
4de97fd91e | ||
|
|
ee93913aac | ||
|
|
e54c4e551c | ||
|
|
743409726f | ||
|
|
2fa82cc231 | ||
|
|
dd4c40d846 | ||
|
|
8acf78dac4 | ||
|
|
eb7c051512 | ||
|
|
5ec90a08a1 | ||
|
|
911275c13b | ||
|
|
704a15896d | ||
|
|
c80b92b346 | ||
|
|
67fc980968 | ||
|
|
05af7dffb8 | ||
|
|
ee068513c6 | ||
|
|
fbb022c877 | ||
|
|
2b90d5eb75 | ||
|
|
edb36f8a92 | ||
|
|
a5bbb26ec8 | ||
|
|
9394e590a8 | ||
|
|
0cb84a9662 |
@@ -15,9 +15,12 @@
|
||||
[官网](https://www.lsky.pro) ·
|
||||
[文档](https://docs.lsky.pro) ·
|
||||
[社区](https://github.com/lsky-org/lsky-pro/discussions) ·
|
||||
[演示](https://pic.iqy.ink) ·
|
||||
[演示](https://pic.vv1234.cn) ·
|
||||
[Telegram 群组](https://t.me/lsky_pro)
|
||||
|
||||
> [!WARNING]
|
||||
> 开源版本已停止维护,不再进行新特性更新和 bug 修复。
|
||||
|
||||
> master 分支为未安装三方拓展的版本,通常包含了最新未发布版本的一些实验性新特性和修复补丁,正式版本请点击 [这里](https://github.com/lsky-org/lsky-pro/releases) 下载。
|
||||
> 发现 bug 请提交 [issues](https://github.com/lsky-org/lsky-pro/issues) (提问前建议阅读[提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md))
|
||||
> 有任何想法、建议、或分享,请移步 [社区](https://github.com/lsky-org/lsky-pro/discussions)
|
||||
|
||||
@@ -15,4 +15,10 @@ final class WebDavOption
|
||||
|
||||
/** @var string 密码 */
|
||||
const Password = 'password';
|
||||
|
||||
/** @var string 认证方式 */
|
||||
const AuthType = 'auth_type';
|
||||
|
||||
/** @var string 地址前缀 */
|
||||
const Prefix = 'prefix';
|
||||
}
|
||||
|
||||
@@ -64,7 +64,9 @@ class ImageController extends Controller
|
||||
});
|
||||
|
||||
foreach ($words as $word) {
|
||||
$builder->where('origin_name', 'like', "%{$word}%")->orWhere('alias_name', 'like', "%{$word}%");
|
||||
$builder->where('name', 'like', "%{$word}%")
|
||||
->orWhere('origin_name', 'like', "%{$word}%")
|
||||
->orWhere('alias_name', 'like', "%{$word}%");
|
||||
}
|
||||
})->latest()->paginate(40);
|
||||
$images->getCollection()->each(function (Image $image) {
|
||||
|
||||
@@ -165,9 +165,10 @@ class Controller extends BaseController
|
||||
if (
|
||||
$image->group?->configs->get(GroupConfigKey::IsEnableWatermark) &&
|
||||
$configs->get('mode', Mode::Overlay) == Mode::Dynamic &&
|
||||
! in_array($image->extension, ['ico', 'gif'])
|
||||
! in_array($image->extension, ['ico', 'gif', 'svg'])
|
||||
) {
|
||||
$contents = $service->stickWatermark($contents, $configs)->encode()->getEncoded();
|
||||
$quality = $image->group?->configs->get(GroupConfigKey::ImageSaveQuality, 75);
|
||||
$contents = $service->stickWatermark($contents, $configs)->encode($image->extension, $quality)->getEncoded();
|
||||
}
|
||||
$cacheTtl = (int)$image->group?->configs->get(GroupConfigKey::ImageCacheTtl, 0);
|
||||
// 是否启用了缓存
|
||||
@@ -184,8 +185,8 @@ class Controller extends BaseController
|
||||
|
||||
$mimetype = $image->mimetype;
|
||||
|
||||
// ico 图片直接输出,不经过 InterventionImage 处理
|
||||
if ($image->extension === 'ico') {
|
||||
// ico svg 图片直接输出,不经过 InterventionImage 处理
|
||||
if (in_array($image->extension, ['ico', 'svg'])) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class GroupRequest extends FormRequest
|
||||
'configs.image_save_format' => '',
|
||||
'configs.path_naming_rule' => 'max:400',
|
||||
'configs.file_naming_rule' => 'max:400',
|
||||
'configs.accepted_file_suffixes' => 'required|array|in:jpeg,jpg,png,gif,tif,bmp,ico,psd,webp',
|
||||
'configs.accepted_file_suffixes' => 'required|array|in:jpeg,jpg,png,gif,tif,bmp,ico,psd,webp,svg',
|
||||
|
||||
'configs.is_enable_scan' => 'boolean',
|
||||
'configs.scanned_action' => [
|
||||
|
||||
@@ -124,6 +124,8 @@ class StrategyRequest extends FormRequest
|
||||
'configs.base_uri' => 'required',
|
||||
'configs.username' => '',
|
||||
'configs.password' => '',
|
||||
'configs.auth_type' => '',
|
||||
'configs.prefix' => '',
|
||||
],
|
||||
StrategyKey::Minio => [
|
||||
'configs.access_key' => 'required',
|
||||
@@ -200,9 +202,11 @@ class StrategyRequest extends FormRequest
|
||||
'configs.passive' => '被动模式',
|
||||
],
|
||||
StrategyKey::Webdav => [
|
||||
'configs.base_uri' => 'required',
|
||||
'configs.username' => 'required',
|
||||
'configs.password' => 'required',
|
||||
'configs.base_uri' => '连接地址',
|
||||
'configs.username' => '用户名',
|
||||
'configs.password' => '密码',
|
||||
'configs.auth_type' => '认证方式',
|
||||
'configs.prefix' => '前缀',
|
||||
],
|
||||
StrategyKey::Minio => [
|
||||
'configs.access_key' => 'AccessKey',
|
||||
|
||||
@@ -240,7 +240,7 @@ class Image extends Model
|
||||
|
||||
public function getThumbnailPathname(): string
|
||||
{
|
||||
return trim(config('app.thumbnail_path'), '/')."/{$this->md5}.png";
|
||||
return trim(config('app.thumbnail_path'), '/')."/{$this->md5}.". ($this->extension === 'svg' ? 'svg' : "png");
|
||||
}
|
||||
|
||||
private function generateKey($length = 6): string
|
||||
|
||||
@@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Sabre\DAV\Client;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
@@ -56,6 +57,13 @@ class Strategy extends Model
|
||||
StrategyKey::Minio => 'Minio',
|
||||
];
|
||||
|
||||
const WEBDAV_AUTH_TYPES = [
|
||||
'' => 'Auto',
|
||||
Client::AUTH_BASIC => 'Basic',
|
||||
Client::AUTH_DIGEST => 'Digest',
|
||||
Client::AUTH_NTLM => 'Ntlm',
|
||||
];
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::saving(function (self $strategy) {
|
||||
|
||||
@@ -52,8 +52,8 @@ use League\Flysystem\FilesystemException;
|
||||
use League\Flysystem\Ftp\FtpAdapter;
|
||||
use League\Flysystem\Ftp\FtpConnectionOptions;
|
||||
use League\Flysystem\Local\LocalFilesystemAdapter;
|
||||
use League\Flysystem\PhpseclibV2\SftpAdapter;
|
||||
use League\Flysystem\PhpseclibV2\SftpConnectionProvider;
|
||||
use League\Flysystem\PhpseclibV3\SftpAdapter;
|
||||
use League\Flysystem\PhpseclibV3\SftpConnectionProvider;
|
||||
use League\Flysystem\WebDAV\WebDAVAdapter;
|
||||
use Overtrue\Flysystem\Cos\CosAdapter;
|
||||
use Overtrue\Flysystem\Qiniu\QiniuAdapter;
|
||||
@@ -151,8 +151,8 @@ class ImageService
|
||||
// 上传频率限制
|
||||
$this->rateLimiter($configs, $request);
|
||||
|
||||
// 图片处理,跳过 ico 于 gif
|
||||
if (! in_array($extension, ['ico', 'gif'])) {
|
||||
// 图片处理,跳过 ico gif svg
|
||||
if (! in_array($extension, ['ico', 'gif', 'svg'])) {
|
||||
// 图片保存质量与格式
|
||||
$quality = $configs->get(GroupConfigKey::ImageSaveQuality, 75);
|
||||
$format = $configs->get(GroupConfigKey::ImageSaveFormat);
|
||||
@@ -160,7 +160,7 @@ class ImageService
|
||||
// 获取拓展名,判断是否需要转换
|
||||
$format = $format ?: $extension;
|
||||
$filename = Str::replaceLast($extension, $format, $file->getClientOriginalName());
|
||||
$handleImage = InterventionImage::make($file)->save($format, $quality);
|
||||
$handleImage = InterventionImage::make($file)->save('tmp_' . md5_file($file->getRealPath()), $quality);
|
||||
$file = new UploadedFile($handleImage->basePath(), $filename, $handleImage->mime());
|
||||
// 重新设置拓展名
|
||||
$extension = $format;
|
||||
@@ -245,8 +245,8 @@ class ImageService
|
||||
throw new UploadException('图片记录保存失败');
|
||||
}
|
||||
|
||||
// 图片检测,跳过 tif、ico 以及 psd 格式
|
||||
if ($configs->get(GroupConfigKey::IsEnableScan) && ! in_array($extension, ['psd', 'ico', 'tif'])) {
|
||||
// 图片检测,跳过 tif、ico、psd、svg 格式
|
||||
if ($configs->get(GroupConfigKey::IsEnableScan) && ! in_array($extension, ['psd', 'ico', 'tif', 'svg'])) {
|
||||
$scanConfigs = $configs->get(GroupConfigKey::ScanConfigs);
|
||||
if ($this->scan(
|
||||
driver: $scanConfigs['driver'],
|
||||
@@ -266,9 +266,11 @@ class ImageService
|
||||
}
|
||||
}
|
||||
|
||||
// 生成缩略图
|
||||
$this->makeThumbnail($image, $file);
|
||||
|
||||
// 上传完成后删除临时文件
|
||||
unlink($file->getPathname());
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
@@ -338,11 +340,12 @@ class ImageService
|
||||
'timeout' => 30,
|
||||
]),
|
||||
),
|
||||
StrategyKey::Webdav => new WebDAVAdapter(new Client([
|
||||
StrategyKey::Webdav => new WebDAVAdapter(new Client(([
|
||||
'baseUri' => $configs->get(WebDavOption::BaseUri),
|
||||
'userName' => $configs->get(WebDavOption::Username),
|
||||
'password' => $configs->get(WebDavOption::Password)
|
||||
])),
|
||||
'password' => $configs->get(WebDavOption::Password),
|
||||
'authType' => (int)$configs->get(WebDavOption::AuthType),
|
||||
])), $configs->get(WebDavOption::Prefix) ?: ''),
|
||||
StrategyKey::Minio => new AwsS3V3Adapter(
|
||||
client: new S3Client([
|
||||
'credentials' => [
|
||||
@@ -554,6 +557,10 @@ class ImageService
|
||||
@mkdir(dirname($pathname));
|
||||
}
|
||||
|
||||
// 生成缩略图,svg等格式本身体积足够小且网页原生支持(比生成的png缩略图还小),不用生成缩略图,直接复制文件
|
||||
if($image->extension ==='svg') {
|
||||
copy($data->getPathname(), $pathname);
|
||||
}else{
|
||||
@ini_set('memory_limit', '512M');
|
||||
|
||||
$img = InterventionImage::make($data);
|
||||
@@ -569,6 +576,7 @@ class ImageService
|
||||
|
||||
$img->fit($width, $height, fn($constraint) => $constraint->upsize())->encode('png', 60)->save($pathname);
|
||||
$img->destroy();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Utils::e($e, '生成缩略图时出现异常');
|
||||
}
|
||||
|
||||
2886
composer.lock
generated
2886
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -106,7 +106,7 @@ return [
|
||||
GroupConfigKey::LimitPerDay => 300,
|
||||
GroupConfigKey::LimitPerWeek => 600,
|
||||
GroupConfigKey::LimitPerMonth => 999,
|
||||
GroupConfigKey::AcceptedFileSuffixes => ['jpeg', 'jpg', 'png', 'gif', 'tif', 'bmp', 'ico', 'psd', 'webp'],
|
||||
GroupConfigKey::AcceptedFileSuffixes => ['jpeg', 'jpg', 'png', 'gif', 'tif', 'bmp', 'ico', 'psd', 'webp', 'svg'],
|
||||
GroupConfigKey::ImageSaveFormat => '',
|
||||
GroupConfigKey::ImageSaveQuality => 75,
|
||||
GroupConfigKey::PathNamingRule => '{Y}/{m}/{d}',
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Enums\ConfigKey;
|
||||
use App\Enums\StrategyKey;
|
||||
use App\Models\Group;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
4397
package-lock.json
generated
4397
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
||||
"@tailwindcss/forms": "^0.4.0",
|
||||
"alpinejs": "^3.4.2",
|
||||
"autoprefixer": "^10.1.0",
|
||||
"axios": "^0.25",
|
||||
"axios": "^1.8",
|
||||
"blueimp-canvas-to-blob": "^3.29.0",
|
||||
"blueimp-file-upload": "^10.32.0",
|
||||
"blueimp-load-image": "^5.16.0",
|
||||
@@ -33,7 +33,7 @@
|
||||
"less-loader": "^10.2.0",
|
||||
"lodash": "^4.17.19",
|
||||
"masonry-layout": "^4.2.2",
|
||||
"postcss": "^8.2.1",
|
||||
"postcss": "^8.4.31",
|
||||
"postcss-import": "^14.0.1",
|
||||
"resolve-url-loader": "^4.0.0",
|
||||
"sweetalert2": "^11.3.3",
|
||||
|
||||
@@ -296,6 +296,18 @@
|
||||
<label for="configs[base_uri]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接地址</label>
|
||||
<x-input type="url" name="configs[base_uri]" id="configs[base_uri]" placeholder="请输入连接地址" />
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||
<label for="webdav-configs[auth_type]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>认证方式</label>
|
||||
<x-select id="webdav-auth-type" name="configs[auth_type]" select2>
|
||||
@foreach(\App\Models\Strategy::WEBDAV_AUTH_TYPES as $key => $type)
|
||||
<option value="{{ $key }}" {{ $loop->first ? 'selected' : '' }}>{{ $type }}</option>
|
||||
@endforeach
|
||||
</x-select>
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||
<label for="webdav-configs[prefix]" class="block text-sm font-medium text-gray-700">路径前缀</label>
|
||||
<x-input type="text" name="configs[prefix]" id="webdav-configs[prefix]" placeholder="请输入路径前缀"></x-input>
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||
<label for="configs[username]" class="block text-sm font-medium text-gray-700">用户名</label>
|
||||
<x-input type="text" name="configs[username]" id="configs[username]" placeholder="请输入用户名" />
|
||||
|
||||
@@ -316,6 +316,18 @@
|
||||
<label for="configs[base_uri]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>连接地址</label>
|
||||
<x-input type="url" name="configs[base_uri]" id="configs[base_uri]" placeholder="请输入连接地址" value="{{ $strategy->configs->get('base_uri') }}" />
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||
<label for="webdav-configs[auth_type]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>认证方式</label>
|
||||
<x-select id="webdav-auth-type" name="configs[auth_type]" select2>
|
||||
@foreach(\App\Models\Strategy::WEBDAV_AUTH_TYPES as $key => $type)
|
||||
<option value="{{ $key }}" {{ $key == $strategy->configs->get('auth_type') ? 'selected' : '' }}>{{ $type }}</option>
|
||||
@endforeach
|
||||
</x-select>
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||
<label for="webdav-configs[prefix]" class="block text-sm font-medium text-gray-700">路径前缀</label>
|
||||
<x-input type="text" name="configs[prefix]" id="webdav-configs[prefix]" placeholder="请输入路径前缀" value="{{ $strategy->configs->get('prefix') }}"></x-input>
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-2 mb-4">
|
||||
<label for="configs[username]" class="block text-sm font-medium text-gray-700">用户名</label>
|
||||
<x-input type="text" name="configs[username]" id="configs[username]" placeholder="请输入用户名" value="{{ $strategy->configs->get('username') }}" />
|
||||
|
||||
Reference in New Issue
Block a user