From 842730e3dd13d309217b7621d67368a170447be9 Mon Sep 17 00:00:00 2001 From: x1ao4 Date: Tue, 16 Sep 2025 01:20:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=BB=E5=8A=A1=E6=B5=B7?= =?UTF-8?q?=E6=8A=A5=E7=9A=84=E5=8A=A0=E8=BD=BD=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E5=90=AF=E7=94=A8=E9=95=BF=E7=BC=93=E5=AD=98=E5=B9=B6=E4=BF=9D?= =?UTF-8?q?=E7=95=99=E6=9B=B4=E6=8D=A2=E6=B5=B7=E6=8A=A5=E7=9A=84=E7=B2=BE?= =?UTF-8?q?=E7=A1=AE=E7=83=AD=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 `/cache/images` 改为 `Cache-Control: public, max-age=31536000, immutable` 提升切页性能;在自定义海报、刷新剧目、批量重下海报时发送 `poster_updated:`,前端 SSE 监听后对目标节目设置 `imageCacheBustById`,仅变更项追加 `?t=` 强制刷新,未变更项命中缓存。 --- app/run.py | 27 +++++++++++++++++++++++---- app/templates/index.html | 12 ++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/app/run.py b/app/run.py index ac756e2..abd78ab 100644 --- a/app/run.py +++ b/app/run.py @@ -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: diff --git a/app/templates/index.html b/app/templates/index.html index 7a25055..b5c9edd 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -5531,6 +5531,18 @@ let changeReason = ''; try { changeReason = JSON.parse(ev && ev.data || '{}').reason || ''; } catch (e) {} + // 如果是海报更新通知(poster_updated:),为该节目设置缓存穿透,避免使用旧缓存 + 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');