275ce07c7639a3374578ebc07c1fa641248e941a
🐉 Loongyan
一个轻量级、自托管的全栈相册管理系统。无需数据库,直接以文件系统存储,支持图片和视频,提供动态缩略图生成和现代化的 Web 界面。
✨ 功能特性
- 📁 零配置相册管理 - 直接扫描
data/文件夹,子目录自动识别为相册 - 🖼️ 多格式支持 - 支持 JPEG、PNG、GIF、BMP、WebP 及 MP4、MOV 等视频格式
- ⚡ 动态缩略图 - 基于 libvips 实时生成,支持自定义尺寸参数
- 🌊 流式传输 - 大文件流式输出,节省内存,防止泄漏
- 🎨 现代化界面 - SvelteKit 5 驱动,响应式设计,流畅体验
- 🔧 高性能解析 - 自定义二进制解析器读取图片尺寸,无需 ImageMagick
- 🐳 Docker 支持 - 多阶段构建,一键部署
- 🌍 国际化 - 支持中英文切换(Paraglide JS)
- 🔐 用户认证 - 集成 Better Auth 认证系统
🏛️ 架构说明
Docker 部署采用双服务架构:
┌─────────────────────────────────────┐
│ Docker Container │
│ │
│ ┌──────────────────────────────┐ │
│ │ Node.js (SvelteKit SSR) │ │
│ │ 端口: 8080 (对外暴露) │ │
│ │ - 处理页面请求 │ │
│ │ - 代理 /api/* → Dart 后端 │ │
│ └──────────────┬───────────────┘ │
│ │ 内部通信 │
│ ▼ │
│ ┌──────────────────────────────┐ │
│ │ Dart Server (Shelf) │ │
│ │ 端口: 8081 (仅内部) │ │
│ │ - 提供 RESTful API │ │
│ │ - 图片/缩略图服务 │ │
│ └──────────────────────────────┘ │
│ │
└─────────────────────────────────────┘
工作流程:
- 用户访问
:8080,请求由 SvelteKit SSR 处理 - 前端
/api/*请求被代理到 Dart 后端:8081 - Dart 后端处理数据请求,返回 JSON 或图片流
🏗️ 项目结构
loongyan/
├── bin/ # Dart 后端服务器
│ ├── server.dart # 服务入口
│ ├── router.dart # API 路由定义
│ ├── middleware/ # 中间件(异常处理等)
│ ├── domain/ # 领域层
│ │ ├── entities/ # 实体(Album, Photo)
│ │ └── repositories/ # 数据仓库
│ └── util/ # 工具类(Vips 图片处理)
├── web/ # SvelteKit 前端
│ ├── src/
│ │ ├── lib/
│ │ │ ├── components/ # UI 组件
│ │ │ └── server/ # 服务端逻辑
│ │ └── routes/ # 页面路由
│ └── package.json
├── data/ # 数据目录(相册文件夹)
├── cache/ # 缩略图缓存
├── Dockerfile # 容器化配置
└── pubspec.yaml # Dart 依赖
🚀 快速开始
环境要求
- 后端: Dart SDK ^3.10.7, libvips
- 前端: Node.js 18+, pnpm/npm
1. 克隆项目
git clone <repository-url>
cd loongyan
2. 准备数据目录
mkdir -p data/我的相册
cp /path/to/your/photos/* data/我的相册/
3. 运行后端
# 安装依赖
dart pub get
# 开发运行(端口 8080)
dart run bin/server.dart
# 输出: Server listening on port 8080
4. 运行前端
cd web
pnpm install
pnpm dev
# 访问 http://localhost:5173
🐳 Docker 部署
构建镜像
docker build . -t loongyan
运行容器
docker run -d \
--name loongyan \
-p 8080:8080 \
-v $(pwd)/data:/app/data \
-v $(pwd)/cache:/app/cache \
-e ORIGIN=http://localhost:8080 \
-e BETTER_AUTH_SECRET=your-secret-key-here \
loongyan
注意: 生产环境请务必设置
ORIGIN为你的实际域名,并使用安全的随机字符串作为BETTER_AUTH_SECRET。
Docker Compose(推荐)
version: '3.8'
services:
loongyan:
build: .
ports:
- "8080:8080"
volumes:
- ./data:/app/data
- ./cache:/app/cache
environment:
- PORT=8080
- ORIGIN=http://localhost:8080
- BETTER_AUTH_SECRET=your-secret-key-here
restart: unless-stopped
docker-compose up -d
📡 API 文档
基础信息
- 基础 URL:
http://localhost:8080/api/v1 - 响应格式: JSON
端点列表
| 方法 | 端点 | 描述 | 参数 |
|---|---|---|---|
| GET | / |
测试接口 | - |
| GET | /album |
获取所有相册 | - |
| GET | /album/<id> |
获取相册详情 | id: 相册ID |
| GET | /album/<id>/photo |
获取相册内照片 | id: 相册ID |
| GET | /photo/<id> |
获取照片元数据 | id: 照片ID |
| GET | /photo/<id>/file |
获取原图文件 | id: 照片ID |
| GET | /photo/<id>/preview |
获取缩略图 | id: 照片ID, w: 宽度, h: 高度 |
| GET | /echo/<message> |
回声测试 | message: 任意消息 |
示例请求
# 获取相册列表
curl http://localhost:8080/api/v1/album
# 获取相册内照片
curl http://localhost:8080/api/v1/album/123456/photo
# 获取缩略图(宽度 300px)
curl http://localhost:8080/api/v1/photo/789012/preview?w=300
响应示例
相册列表 (GET /album)
[
{
"id": 123456789,
"name": "我的相册",
"createdAt": "2024-01-15T08:30:00.000",
"updatedAt": "2024-01-15T08:30:00.000"
}
]
照片详情 (GET /photo/<id>)
{
"id": 987654321,
"albumId": 123456789,
"filePath": "data/我的相册/IMG_001.jpg",
"fileName": "IMG_001.jpg",
"fileSize": 2048576,
"mimeType": "image/jpeg",
"width": 1920,
"height": 1080,
"createdAt": "2024-01-15T08:30:00.000"
}
🛠️ 开发指南
后端开发
# 运行测试
dart test
# 代码检查
dart analyze
# 格式化代码
dart format .
# AOT 编译(生产)
dart compile exe bin/server.dart -o bin/server
前端开发
cd web
# 安装依赖
pnpm install
# 开发服务器
pnpm dev
# 构建生产版本
pnpm build
# 预览生产构建
pnpm preview
# 运行测试
pnpm test
# 代码检查
pnpm lint
# 格式化
pnpm format
# 类型检查
pnpm check
生成认证 Schema
cd web
pnpm auth:schema
⚙️ 配置说明
后端环境变量
| 变量名 | 默认值 | 说明 |
|---|---|---|
PORT |
8081 |
Dart 后端监听端口(容器内部) |
DATA_DIR |
/app/data |
数据目录 |
CACHE_DIR |
/app/cache |
缓存目录 |
前端环境变量
前端使用 .env 文件配置,参考 .env.example:
# web/.env
ORIGIN=http://localhost:8080 # 生产环境的实际域名
BETTER_AUTH_SECRET=your-secret-key # 认证密钥(32字符随机字符串)
BACKEND_URL=http://127.0.0.1:8081 # Dart 后端地址(内部通信)
重要: 生产环境必须设置
ORIGIN和BETTER_AUTH_SECRET。
📦 技术栈
后端
- Dart - 编程语言
- Shelf - Web 框架
- shelf_router - 路由库
- libvips - 高性能图片处理
前端
- Svelte 5 - 前端框架
- SvelteKit - 全栈框架
- Vite - 构建工具
- Better Auth - 认证库
- Paraglide JS - 国际化
- Drizzle ORM - 数据库 ORM
🤝 贡献指南
- Fork 本仓库
- 创建特性分支 (
git checkout -b feature/amazing-feature) - 提交更改 (
git commit -m 'Add amazing feature') - 推送到分支 (
git push origin feature/amazing-feature) - 创建 Pull Request
🙏 致谢
Made with ❤️ by Loongyan Team
Description
Languages
Dart
50.9%
Svelte
36.3%
JavaScript
7.5%
CSS
3.4%
Dockerfile
1%
Other
0.9%