lzw-723 ff1227cde6
All checks were successful
Dart CI / build (push) Successful in 30s
修改docker工作流触发时间
2026-04-04 14:06:32 +08:00
2026-04-04 13:36:58 +08:00
2026-04-04 13:36:58 +08:00
2026-03-25 14:35:01 +08:00
2026-04-04 13:47:52 +08:00
2026-03-25 13:54:43 +08:00
2026-03-21 22:05:24 +08:00
2026-03-13 22:07:33 +08:00
2026-03-12 21:24:49 +08:00
2026-03-12 21:24:49 +08:00
2026-03-21 22:13:31 +08:00
2026-04-03 22:51:19 +08:00
2026-03-12 21:24:49 +08:00
2026-03-12 21:24:49 +08:00
2026-03-12 21:24:49 +08:00
2026-03-24 22:53:03 +08:00

🐉 Loongyan

一个轻量级、自托管的全栈相册管理系统。无需数据库,直接以文件系统存储,支持图片和视频,提供动态缩略图生成和现代化的 Web 界面。

Dart Svelte


功能特性

  • 📁 零配置相册管理 - 直接扫描 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. 克隆项目

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 后端地址(内部通信)

重要: 生产环境必须设置 ORIGINBETTER_AUTH_SECRET


📦 技术栈

后端

前端


🤝 贡献指南

  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 团队提供的 Dart Web 框架
  • 感谢 Svelte 团队带来的优秀前端体验
  • 感谢 libvips 提供的高性能图片处理能力

Made with ❤️ by Loongyan Team
Description
No description provided
Readme 619 KiB
Languages
Dart 50.9%
Svelte 36.3%
JavaScript 7.5%
CSS 3.4%
Dockerfile 1%
Other 0.9%