# 🐉 Loongyan 一个轻量级、自托管的全栈相册管理系统。无需数据库,直接以文件系统存储,支持图片和视频,提供动态缩略图生成和现代化的 Web 界面。 ![Dart](https://img.shields.io/badge/Dart-3.10+-00B4AB.svg) ![Svelte](https://img.shields.io/badge/Svelte-5-FF3E00.svg) --- ## ✨ 功能特性 - 📁 **零配置相册管理** - 直接扫描 `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 │ │ │ │ - 图片/缩略图服务 │ │ │ └──────────────────────────────┘ │ │ │ └─────────────────────────────────────┘ ``` **工作流程:** 1. 用户访问 `:8080`,请求由 SvelteKit SSR 处理 2. 前端 `/api/*` 请求被代理到 Dart 后端 `:8081` 3. 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. 克隆项目 ```bash git clone cd loongyan ``` ### 2. 准备数据目录 ```bash mkdir -p data/我的相册 cp /path/to/your/photos/* data/我的相册/ ``` ### 3. 运行后端 ```bash # 安装依赖 dart pub get # 开发运行(端口 8080) dart run bin/server.dart # 输出: Server listening on port 8080 ``` ### 4. 运行前端 ```bash cd web pnpm install pnpm dev # 访问 http://localhost:5173 ``` --- ## 🐳 Docker 部署 ### 构建镜像 ```bash docker build . -t loongyan ``` ### 运行容器 ```bash 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(推荐) ```yaml 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 ``` ```bash docker-compose up -d ``` --- ## 📡 API 文档 ### 基础信息 - **基础 URL**: `http://localhost:8080/api/v1` - **响应格式**: JSON ### 端点列表 | 方法 | 端点 | 描述 | 参数 | |------|------|------|------| | GET | `/` | 测试接口 | - | | GET | `/album` | 获取所有相册 | - | | GET | `/album/` | 获取相册详情 | `id`: 相册ID | | GET | `/album//photo` | 获取相册内照片 | `id`: 相册ID | | GET | `/photo/` | 获取照片元数据 | `id`: 照片ID | | GET | `/photo//file` | 获取原图文件 | `id`: 照片ID | | GET | `/photo//preview` | 获取缩略图 | `id`: 照片ID, `w`: 宽度, `h`: 高度 | | GET | `/echo/` | 回声测试 | `message`: 任意消息 | ### 示例请求 ```bash # 获取相册列表 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`) ```json [ { "id": 123456789, "name": "我的相册", "createdAt": "2024-01-15T08:30:00.000", "updatedAt": "2024-01-15T08:30:00.000" } ] ``` **照片详情** (`GET /photo/`) ```json { "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" } ``` --- ## 🛠️ 开发指南 ### 后端开发 ```bash # 运行测试 dart test # 代码检查 dart analyze # 格式化代码 dart format . # AOT 编译(生产) dart compile exe bin/server.dart -o bin/server ``` ### 前端开发 ```bash cd web # 安装依赖 pnpm install # 开发服务器 pnpm dev # 构建生产版本 pnpm build # 预览生产构建 pnpm preview # 运行测试 pnpm test # 代码检查 pnpm lint # 格式化 pnpm format # 类型检查 pnpm check ``` ### 生成认证 Schema ```bash cd web pnpm auth:schema ``` --- ## ⚙️ 配置说明 ### 后端环境变量 | 变量名 | 默认值 | 说明 | |--------|--------|------| | `PORT` | `8081` | Dart 后端监听端口(容器内部) | | `DATA_DIR` | `/app/data` | 数据目录 | | `CACHE_DIR` | `/app/cache` | 缓存目录 | ### 前端环境变量 前端使用 `.env` 文件配置,参考 `.env.example`: ```bash # 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](https://dart.dev/) - 编程语言 - [Shelf](https://pub.dev/packages/shelf) - Web 框架 - [shelf_router](https://pub.dev/packages/shelf_router) - 路由库 - [libvips](https://www.libvips.org/) - 高性能图片处理 ### 前端 - [Svelte 5](https://svelte.dev/) - 前端框架 - [SvelteKit](https://kit.svelte.dev/) - 全栈框架 - [Vite](https://vitejs.dev/) - 构建工具 - [Better Auth](https://www.better-auth.com/) - 认证库 - [Paraglide JS](https://inlang.com/m/gerre34r/library-inlang-paraglideJs) - 国际化 - [Drizzle ORM](https://orm.drizzle.team/) - 数据库 ORM --- ## 🤝 贡献指南 1. Fork 本仓库 2. 创建特性分支 (`git checkout -b feature/amazing-feature`) 3. 提交更改 (`git commit -m 'Add amazing feature'`) 4. 推送到分支 (`git push origin feature/amazing-feature`) 5. 创建 Pull Request --- --- ## 🙏 致谢 - 感谢 [Shelf](https://pub.dev/packages/shelf) 团队提供的 Dart Web 框架 - 感谢 [Svelte](https://svelte.dev/) 团队带来的优秀前端体验 - 感谢 [libvips](https://www.libvips.org/) 提供的高性能图片处理能力 ---
Made with ❤️ by Loongyan Team