优化任务海报的加载逻辑,启用长缓存并保留更换海报的精确热更新

将 `/cache/images` 改为 `Cache-Control: public, max-age=31536000, immutable` 提升切页性能;在自定义海报、刷新剧目、批量重下海报时发送 `poster_updated:<tmdb_id>`,前端 SSE 监听后对目标节目设置 `imageCacheBustById`,仅变更项追加 `?t=` 强制刷新,未变更项命中缓存。
This commit is contained in:
x1ao4 2025-09-16 01:20:42 +08:00
parent 9fd9d5cd74
commit 842730e3dd
2 changed files with 35 additions and 4 deletions

View File

@ -699,10 +699,13 @@ def favicon():
def serve_cache_images(filename):
resp = send_from_directory(CACHE_IMAGES_DIR, filename)
try:
# 禁用强缓存,允许协商缓存
resp.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate, max-age=0'
resp.headers['Pragma'] = 'no-cache'
resp.headers['Expires'] = '0'
# 启用长期缓存:依赖前端通过 `?t=` 穿透参数在变更时刷新
# 说明:图片文件名稳定且内容稳定,正常情况应命中浏览器缓存;
# 当用户主动更换海报时,前端会为该节目生成新的时间戳参数,形成新的 URL从而触发重新下载。
resp.headers['Cache-Control'] = 'public, max-age=31536000, immutable'
# 清理可能的历史字段(部分代理可能保留)
resp.headers.pop('Pragma', None)
resp.headers.pop('Expires', None)
except Exception:
pass
return resp
@ -4353,6 +4356,11 @@ def redownload_all_posters():
# 更新数据库中的海报路径
cal_db.update_show_poster(int(tmdb_id), poster_local_path)
success_count += 1
# 通知前端该节目海报已更新
try:
notify_calendar_changed(f'poster_updated:{int(tmdb_id)}')
except Exception:
pass
except Exception as e:
logging.error(f"重新下载海报失败 (TMDB ID: {show.get('tmdb_id')}): {e}")
@ -4820,6 +4828,12 @@ def calendar_refresh_show():
try:
notify_calendar_changed('refresh_show')
# 通知前端指定节目海报可能已更新,用于触发按节目维度的缓存穿透
try:
if tmdb_id:
notify_calendar_changed(f'poster_updated:{int(tmdb_id)}')
except Exception:
pass
except Exception:
pass
@ -5157,6 +5171,11 @@ def calendar_edit_metadata():
logging.info(f"成功更新自定义海报: TMDB ID {current_tmdb_id}, 路径: {saved_path}")
changed = True
# 仅当自定义海报保存成功时,通知前端该节目海报已更新
try:
notify_calendar_changed(f'poster_updated:{int(current_tmdb_id)}')
except Exception:
pass
else:
logging.warning(f"自定义海报保存失败: {custom_poster_url}")
except Exception as e:

View File

@ -5531,6 +5531,18 @@
let changeReason = '';
try { changeReason = JSON.parse(ev && ev.data || '{}').reason || ''; } catch (e) {}
// 如果是海报更新通知poster_updated:<tmdb_id>),为该节目设置缓存穿透,避免使用旧缓存
try {
if (typeof changeReason === 'string' && changeReason.startsWith('poster_updated:')) {
const idStr = changeReason.split(':')[1] || '';
const eid = parseInt(idStr, 10);
if (!isNaN(eid)) {
const nowTick = Date.now();
this.$set(this.imageCacheBustById, eid, nowTick);
}
}
} catch (e) {}
// 先拉取最新转存信息并重建映射(用于管理视图与进度判定)
try {
const latestRes = await axios.get('/task_latest_info');