Innatus

本心自昭

Film Vault 影视墙部署与维护笔记

发布于 # 笔记

Film Vault 影视墙完整部署与维护笔记


1. 项目定位

Film Vault 是一个个人长期使用的影视墙项目。

核心目标:

项目已经支持:

管理员搜索支持分页,方便处理重名作品。


2. 仓库目录

仓库根目录:

C:\Users\haenl\Documents\Codex\2026-04-23-d-1a-web-films-web-tmdb

2.1 目录说明

.
├─ .github/
│  └─ workflows/
│     └─ rebuild-library.yml          # GitHub Actions(可选,用于重建片库)
├─ data/
│  ├─ library.json                    # 源片单(title / year / tmdbId / media_type)
│  ├─ library.resolved.json           # 前端完整静态片库
│  ├─ library.source.js               # 本地 file:// 预览用的数据脚本
│  └─ library.resolved.js             # 本地 file:// 预览用的数据脚本
├─ scripts/
│  ├─ add-movie.mjs                   # 本地命令行搜索并添加影视
│  ├─ rebuild-library.mjs             # 根据源片单重建完整静态片库
│  └─ lib/
│     ├─ movie-db.mjs                 # TMDB 请求封装
│     └─ library-files.mjs            # 片库文件读写
├─ index.html                         # 页面结构
├─ styles.css                         # 样式
├─ app.js                             # 前端逻辑
├─ _worker.js                         # Cloudflare Pages / Workers 管理接口
├─ favicon.svg                        # 网站图标
├─ wrangler.example.toml              # Cloudflare 配置模板
├─ admin.local.example.js             # 本地管理员配置模板
├─ package.json                       # npm scripts
├─ README.md                          # GitHub 首页说明
└─ FilmVault-博客版部署笔记.md         # 这份详细笔记

3. 为什么 data/* 文件不能删

这是项目里一个容易误判的点。

线上虽然主要读写 Cloudflare KV,但仓库里的 data/* 文件依然必须保留,因为它们承担了 4 个作用:

  1. 初始种子数据

    • 新环境第一次部署时,KV 可能是空的
    • 这时 Worker 需要仓库里的静态片库做初始数据源
  2. KV 自动纠偏

    • 如果 KV 里残留了旧数据,Worker 会比较静态文件的 generatedAt
    • 当 GitHub 中的静态片库更新时,会自动覆盖旧 KV
  3. 本地 file:// 预览

    • 双击 index.html 时,页面优先读 library.source.js / library.resolved.js
  4. 版本化备份

    • 仓库里的静态片库是可以追踪、回滚、审计的

结论:


4. 获取项目

4.1 克隆仓库

git clone https://github.com/haenlau/films.git
cd films

4.2 Node.js 版本

推荐:

虽然本地纯预览不依赖 Node,但脚本维护和片库重建需要。


5. 本地预览

5.1 直接双击打开

直接双击:

index.html

项目已经兼容 file:// 打开方式。

页面优先读取:

所以即使没有本地 HTTP 服务,也能正常显示片库。

5.2 本地管理员模式

本地管理员模式用于:

步骤一:创建本地配置文件

复制模板:

copy admin.local.example.js admin.local.js

步骤二:填写本地配置

window.FILM_VAULT_ADMIN = {
  apiKey: "YOUR_TMDB_API_KEY",
  password: "YOUR_LOCAL_ADMIN_PASSWORD"
};

注意:

步骤三:本地使用流程

  1. 双击打开 index.html
  2. 右上角点击 登录管理
  3. 输入 admin.local.js 中的本地密码
  4. 登录成功后,出现 控制台
  5. 控制台中可用:
    • 添加影视
    • 导出片单
    • 导出数据

6. 源片单与完整片库

6.1 data/library.json

这是“源片单”,适合人工维护或脚本维护。

推荐结构:

{
  "title": "我的影视墙",
  "subtitle": "一面为私人观影史准备的影视墙。",
  "generatedAt": "2026-05-11T14:30:48.507Z",
  "entries": [
    {
      "title": "黑洞频率",
      "year": 2000,
      "tmdbId": 10559,
      "media_type": "movie"
    },
    {
      "title": "怪奇物语",
      "year": 2016,
      "tmdbId": 66732,
      "media_type": "tv"
    }
  ]
}

字段说明:

建议:

6.2 data/library.resolved.json

这是前端直接使用的完整片库数据。

包含:

这个文件不建议手工维护,推荐脚本生成。

6.3 本地预览用的 JS 数据文件

为了兼容 file://,项目会额外生成:

格式示例:

window.__FILM_VAULT_SOURCE__ = {
  "title": "我的影视墙",
  "subtitle": "一面为私人观影史准备的影视墙。",
  "entries": [...]
};

window.__FILM_VAULT_RESOLVED__ = {
  "title": "我的影视墙",
  "subtitle": "一面为私人观影史准备的影视墙。",
  "movies": [...]
};

7. 命令行维护片库

7.1 配置 .dev.vars

在项目根目录创建:

.dev.vars

内容示例:

TMDB_API_KEY=YOUR_TMDB_API_KEY

7.2 按名称搜索并添加影视

npm run add:movie -- 怪奇物语

7.3 根据源片单重建完整片库

npm run rebuild:library

7.4 package.json 中的脚本

{
  "name": "film-vault-wall",
  "private": true,
  "type": "module",
  "scripts": {
    "rebuild:library": "node ./scripts/rebuild-library.mjs",
    "add:movie": "node ./scripts/add-movie.mjs"
  }
}

8. TMDB 接口支持范围

这个项目最终不是“电影墙”,而是“影视墙”。

所以当前搜索和详情逻辑支持:

8.1 搜索逻辑

管理员控制台中的“添加影视”搜索支持:

并且支持分页。

当前实现策略:

8.2 详情逻辑

添加时按 media_type 分流:

这是为了保证:


9. 控制台中的搜索分页

这是当前版本的重要能力。

9.1 行为规则

分页控件包括:

9.2 为什么需要分页

很多影视作品存在:

如果不支持翻页,第一页找不到时就无法继续筛选。

9.3 关键实现思路

state.searchQuery = query;
state.searchPage = 1;
state.searchPerformed = true;

const payload = state.admin.mode === "remote"
  ? await remoteSearchMovies(state.searchQuery, state.searchPage)
  : await localSearchMovies(state.searchQuery, state.searchPage);

state.searchResults = payload.results || [];
state.searchTotalPages = Math.max(1, Number(payload.total_pages || 1));
renderSearchResults();
renderSearchPagination();
const page = Math.max(1, Number(body.page || 1));

const response = await fetch(buildTmdbUrl("/search/multi", env.TMDB_API_KEY, {
  language: "zh-CN",
  query,
  include_adult: "false",
  page: String(page),
}));

return json({
  results,
  total_pages: Number(payload.total_pages || 1),
});

10. Cloudflare 部署

推荐使用 Cloudflare Pages

10.1 为什么不是纯 Workers

因为这个项目是:

所以最适合:

10.2 Pages 构建配置

连接 GitHub 仓库后:

10.3 wrangler.example.toml

name = "films"
compatibility_date = "2026-04-23"

pages_build_output_dir = "."

[[kv_namespaces]]
binding = "FILM_VAULT_KV"
id = "replace-with-your-kv-namespace-id"
preview_id = "replace-with-your-preview-kv-namespace-id"

10.4 必要的 KV 配置

创建一个 KV namespace,并绑定:

FILM_VAULT_KV

10.5 必要的 Secrets

在 Cloudflare Pages 中配置:

含义:

10.6 Worker 的职责

_worker.js 主要负责:

10.7 线上数据读写逻辑

线上优先读 Cloudflare KV。

但为了避免 KV 停留在旧数据,Worker 还会:

这个机制很重要,因为它保证:


11. 管理员使用逻辑

11.1 普通访客

11.2 管理员

  1. 点击 管理员登录
  2. 输入密码
  3. 登录成功后出现 控制台
  4. 控制台中可执行:
    • 添加影视
    • 导出片单
    • 导出数据
  5. 在线上环境中,添加/删除会直接写入 Cloudflare KV

12. 默认排序与前端说明

12.1 默认排序

站点默认按:

上映时间

而不是评分优先。

12.2 当前文案说明

当前项目已经统一到“影视”语义,而不是“电影”:


13. Git 提交流程

13.1 进入仓库目录

cd C:\Users\haenl\Documents\Codex\2026-04-23-d-1a-web-films-web-tmdb

13.2 查看状态

git status

13.3 提交全部改动

git add .
git commit -m "your commit message"
git push

13.4 只提交部分文件

git add app.js _worker.js index.html styles.css README.md
git commit -m "your commit message"
git push

14. 隐私与敏感信息

14.1 不应提交到 GitHub 的文件

14.2 可以提交到仓库的内容

注意:


15. 常见问题与排查

15.1 线上为什么还是旧片库

先检查:

15.2 为什么搜索不到目标作品

常见原因:

解决方式:

15.3 为什么本地能搜,线上添加失败

常见原因:

15.4 为什么 data/* 不能删

因为它们负责:


16. 推荐维护方式

方案 A:本地页面维护

适合直接在浏览器里操作:

  1. 配置 admin.local.js
  2. 双击打开 index.html
  3. 登录管理
  4. 添加影视
  5. 导出片单 / 导出数据
  6. 提交到 GitHub

方案 B:命令行批量维护

适合大规模调整:

  1. 修改 data/library.json
  2. 执行 npm run rebuild:library
  3. 提交到 GitHub

方案 C:线上 Cloudflare 管理

适合日常在线维护:

  1. 打开线上站点
  2. 管理员登录
  3. 在控制台里添加或删除影视
  4. 数据直接写入 KV

17. 推荐环境


18. 结论

这个项目最终是一个:

的个人影视墙系统。

只要保留好:

几年后重新看到这份笔记,依然可以完整恢复。