Skip to content

Latest commit

 

History

History
346 lines (259 loc) · 10.9 KB

File metadata and controls

346 lines (259 loc) · 10.9 KB

ChronoFrame

Chronoframe

Latest Release Latest Nightly Release License

Discord Server

Featured|HelloGitHub ChronoFrame - Self-hosted photo gallery for photographers. | Product Hunt

Languages: English | 中文

丝滑的照片展示和管理应用,支持多种图片格式和大尺寸图片渲染。

在线演示: TimoYin's Mems

✨ 特性

🖼️ 强大的图片管理

  • 在线管理照片 - 通过 Web 界面轻松管理和浏览照片
  • 探索地图 - 在地图上浏览照片拍摄位置
  • 智能 EXIF 解析 - 自动提取拍摄时间、地理位置、相机参数等元数据
  • 地理位置识别 - 自动识别(Reverse Geocoding)照片拍摄地点
  • 多格式支持 - 支持 JPEG、PNG、HEIC/HEIF 等主流图片格式
  • 智能缩略图 - 基于 ThumbHash 技术的高效缩略图生成

🔧 现代技术栈

  • Nuxt 4 - 基于最新的 Nuxt 框架,提供 SSR/SSG 支持
  • TypeScript - 完整的类型安全保障
  • TailwindCSS - 现代化的 CSS 框架
  • Drizzle ORM - 类型安全的数据库 ORM

☁️ 灵活的存储方案

  • 多存储后端 - 支持 S3 兼容存储、本地文件系统
  • CDN 加速 - 可配置 CDN 地址加速图片访问

🐳 部署

推荐使用预构建的 docker 镜像部署,在 ghcr 上查看镜像

创建 .env 文件并配置。

下面是最小化配置示例,完整的配置项参考 配置指南

# 管理员邮箱(必须)
CFRAME_ADMIN_EMAIL=
# 管理员用户名(可选,默认 ChronoFrame)
CFRAME_ADMIN_NAME=
# 管理员密码(可选,默认 CF1234@!)
CFRAME_ADMIN_PASSWORD=

# 站点信息(均可选)
NUXT_PUBLIC_APP_TITLE=
NUXT_PUBLIC_APP_SLOGAN=
NUXT_PUBLIC_APP_AUTHOR=
NUXT_PUBLIC_APP_AVATAR_URL=

# 地图提供器 (maplibre/mapbox)
NUXT_PUBLIC_MAP_PROVIDER=maplibre
# 使用 MapLibre 需要 MapTiler 访问令牌
NUXT_PUBLIC_MAP_MAPLIBRE_TOKEN=
# 使用 Mapbox 需要 Mapbox 访问令牌
NUXT_PUBLIC_MAPBOX_ACCESS_TOKEN=

# Mapbox 无域名限制令牌(反向地理编码,可选)
NUXT_MAPBOX_ACCESS_TOKEN=

# 存储提供者(local、s3 或 openlist)
NUXT_STORAGE_PROVIDER=local
NUXT_PROVIDER_LOCAL_PATH=/app/data/storage

# 会话密码(必须,32 位随机字符串)
NUXT_SESSION_PASSWORD=

拉取镜像

我们推荐使用预构建的 Docker 镜像进行部署,镜像托管在 GHCR 和 Docker Hub,您可以根据网络情况选择合适的源。

docker pull ghcr.io/hoshinosuzumi/chronoframe:latest
docker pull hoshinosuzumi/chronoframe:latest

Docker

一行命令启动:

docker run -d --name chronoframe -p 3000:3000 -v $(pwd)/data:/app/data --env-file .env ghcr.io/hoshinosuzumi/chronoframe:latest

Docker Compose

创建 docker-compose.yml

services:
  chronoframe:
    image: ghcr.io/hoshinosuzumi/chronoframe:latest
    container_name: chronoframe
    restart: unless-stopped
    ports:
      - '3000:3000'
    volumes:
      - ./data:/app/data
    env_file:
      - .env

启动:

docker compose up -d

📖 使用指南

如未配置 CFRAME_ADMIN_EMAILCFRAME_ADMIN_PASSWORD,默认账号如下:

  • 邮箱: admin@chronoframe.com
  • 密码: CF1234@!

登录到控制台

  1. 点击头像跳转到登录页面,可以使用账号密码或 GitHub 登录

上传照片

  1. 访问仪表板页面 /dashboard
  2. Photos 页面中选择图片并点击上传(支持批量上传和拖拽上传)
  3. 系统将自动提取 EXIF 信息、生成缩略图并逆编码照片地理位置

📸 截图

Gallery Photo Detail Map Explore Dashboard

🛠️ 开发

环境要求

  • Node.js 18+
  • pnpm 9.0+

安装依赖

# 使用 pnpm (推荐)
pnpm install

# 或使用其他包管理器
npm install
yarn install

配置环境变量

复制环境变量模板并根据需要配置:

cp .env.example .env

数据库初始化

# 2. 生成数据库迁移文件(可选)
pnpm db:generate

# 3. 执行数据库迁移
pnpm db:migrate

启动开发服务器

pnpm dev

应用将在 http://localhost:3000 启动。

项目结构

chronoframe/
├── app/                    # Nuxt 应用
│   ├── components/         # 组件
│   ├── pages/              # 页面路由
│   ├── composables/        # 组合式函数
│   └── stores/             # Pinia 状态管理
├── packages/
│   └── webgl-image/        # WebGL 图片查看器
├── server/
│   ├── api/                # API 路由
│   ├── database/           # 数据库 schema 和迁移
│   └── services/           # 业务逻辑服务
└── shared/                 # 共享类型和工具

构建命令

# 开发模式 (包含依赖包构建)
pnpm dev

# 仅构建依赖包
pnpm build:deps

# 构建生产版本
pnpm build

# 数据库操作
pnpm db:generate    # 生成迁移文件
pnpm db:migrate     # 执行迁移

# 预览生产版本
pnpm preview

🤝 贡献

欢迎贡献代码!请确保:

  1. Fork 本仓库
  2. 创建功能分支 (git checkout -b feature/amazing-feature)
  3. 提交更改 (git commit -m 'Add some amazing feature')
  4. 推送到分支 (git push origin feature/amazing-feature)
  5. 开启 Pull Request

开发规范

  • 使用 TypeScript 进行类型安全的开发
  • 遵循 ESLint 和 Prettier 代码规范
  • 更新相关文档

📄 许可证

本项目基于 MIT 许可证 开源。

👤 作者

Timothy Yin

❓ FAQ

如何创建管理员用户?

首次启动时,会根据环境变量 CFRAME_ADMIN_EMAILCFRAME_ADMIN_NAMECFRAME_ADMIN_PASSWORD 环境变量创建一个管理员用户。CFRAME_ADMIN_EMAIL 必须是登录使用的 GitHub 账户的邮箱。

支持哪些图片格式?

支持 JPEG、PNG、HEIC/HEIF、MOV(作为实况照片) 格式。

为什么无法使用 GitHub/Local 存储?

目前支持 S3 兼容存储,未来计划支持 GitHub 和本地文件系统存储。

为什么需要/如何配置地图服务?

地图服务用于在地图上浏览照片拍摄位置,以及照片详情中的小地图渲染。目前使用 Mapbox,注册后获取访问令牌并配置到 MAPBOX_TOKEN 环境变量中。

为什么我上传的 MOV 文件没有被识别为实况照片?

需要确保实况照片对的图片(.heic)和视频(.mov)的文件名一致(例如 IMG_1234.heicIMG_1234.mov 会自动匹配)。 一般情况来说,不管是上传 .heic 还是 .mov,都会检测一次配对,因此上传的顺序无关紧要。 如果仍然没有被识别为实况照片,请在仪表盘中找到图片,在操作菜单中手动触发配对检测。

如何导入存储中已有的照片?

目前不支持直接导入已有照片,未来计划支持通过指定目录扫描导入。

本项目与 Afilmory 有何区别?

Afilmory 是一个非常优秀的项目,其部署方式是在本地或 CI 中处理存储中的照片并生成清单文件,然后前端通过读取清单文件来展示照片,属于静态部署。 ChronoFrame 则是一个动态的照片管理应用,提供在线上传、管理和浏览照片的功能,适合需要频繁更新照片的场景。

🙏 致谢

本项目受启发于 Afilmory,同样优秀的个人相册项目。

感谢以下优秀的开源项目和库:

⭐️ Star History

Star History Chart