缩略图懒生成 + 评论登录限流:时间线不再拉原图

- 新增 /uploads/thumb/{key}?w=:首访从存储端读一次原图,标准库盒均值缩放后
  落盘 data/.thumbnail_cache(按内容哈希命名,天然失效);失败写 .failed 冷却
  一小时,非图片/超大一律 302 回原图,前端无感。原图路由改用 ServeContent,
  补上视频拖动进度条所需的 Range 支持
- 前端 thumbURL/thumbifyHtml 接入两套 UI 的时间线配图、长文封面与短文正文,
  并补 loading=lazy;详情页与灯箱仍用原图。/api/site 改为
  {settings, uploads_public_base},让前端识别哪些直链属于自家存储
- 后台登录的滑动窗口限速器抽成 internal/ratelimit 共享包(调用面不变),
  新增:读者登录失败按 IP 20 次/10 分钟、评论写入按读者 5 条/分钟
  (站主豁免,且只计成功写入)
This commit is contained in:
Sakurasan
2026-09-28 13:34:19 +08:00
parent b6342a622d
commit 6108aca34c
17 changed files with 822 additions and 71 deletions
+6 -2
View File
@@ -1,5 +1,6 @@
import { reactive, watch } from 'vue'
import { publicApi } from './api'
import { setThumbBase } from './utils'
// 暗色皮肤固定为 ink —— 是当前唯一支持的暗端皮肤。
const DARK_SKIN = 'ink'
@@ -152,8 +153,11 @@ if (typeof window !== 'undefined' && window.matchMedia) {
export async function loadSite() {
try {
const data = await publicApi.site()
Object.assign(site, data)
const resp = await publicApi.site()
// 响应结构:{ settings: {…}, uploads_public_base }
const { uploads_public_base, settings } = resp || {}
setThumbBase(uploads_public_base)
Object.assign(site, settings)
// 防御性:服务端返回的 light_skin_id 必须是白名单之一,否则兜底 paper
if (!isValidLightSkin(site.light_skin_id)) site.light_skin_id = 'paper'
// ui_id 同理;同时回写本地缓存,让下一次首屏不用等接口就知道该用哪套 UI