From 4e429b6572e09fa4e555fe0d5d2494d092f405f9 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 18 May 2026 02:22:31 +0000 Subject: [PATCH] =?UTF-8?q?fix(play-history):=20=E8=BF=81=E7=A7=BB=20v1=20?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E5=88=B0=E6=96=B0=E5=AD=98=E5=82=A8=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E8=80=81=E7=94=A8=E6=88=B7=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E5=90=8E=E6=B8=85=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cleanupLegacyPlayHistoryStorage 此前只删 v1 旧 key 不做迁移,老用户升级后 最近播放/历史全空。新增 migrateLegacyPlayHistory:在新 PERSIST_KEY 尚不存在 时,把 v1 时代 5 个独立 key 的历史读出合并,经 serializePlayHistoryState 落盘(自动 minify 剥离 base64/派生字段,不会撑爆 5MB 配额),再删旧 key。 调用早于 store 实例化,persistedstate 创建时即可 hydrate 回迁移数据。 https://claude.ai/code/session_01LgUk5QMQsXYa7ZFTYpqeLu --- src/renderer/store/modules/playHistory.ts | 73 +++++++++++++++++++---- 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/src/renderer/store/modules/playHistory.ts b/src/renderer/store/modules/playHistory.ts index 53f7756..92ed998 100644 --- a/src/renderer/store/modules/playHistory.ts +++ b/src/renderer/store/modules/playHistory.ts @@ -13,28 +13,23 @@ import { export type { MusicHistoryItem }; -// 一次性清理 v1 时代遗留的 localStorage key。 -// 旧版本以 5 个独立 key 单独存历史,新版本合并到 PERSIST_KEY 由 persistedstate 管。 -// 不做数据迁移:历史是低关键性衍生数据,老用户升级后看到空"最近播放",重新听几次即可。 -// 仅清掉旧 key 释放配额,避免和新 key 双倍占用 -const LEGACY_KEYS = [ +// v1 时代以 5 个独立 key 单独存历史,新版本合并到 PERSIST_KEY 由 persistedstate 管。 +// 这 5 个 key 的内容会被迁移进新 key(见 migrateLegacyPlayHistory),其余 misc key 直接删。 +const LEGACY_HISTORY_KEYS = [ 'musicHistory', 'podcastHistory', 'playlistHistory', 'albumHistory', - 'podcastRadioHistory', + 'podcastRadioHistory' +] as const; + +const LEGACY_MISC_KEYS = [ // v1 迁移方案的 flag,已随 e53a035 发布到用户机器上 'playHistory-migrated', // v1 时代独立持久化的播放模式,现已并入 player-core-store 'playMode' ]; -export const cleanupLegacyPlayHistoryStorage = (): void => { - if (localStorage.getItem('playHistory-cleaned-v1')) return; - LEGACY_KEYS.forEach((key) => localStorage.removeItem(key)); - localStorage.setItem('playHistory-cleaned-v1', '1'); -}; - // ==================== 类型定义 ==================== // 歌单历史记录 @@ -122,6 +117,60 @@ const serializePlayHistoryState = (state: any): string => { }); }; +const readLegacyArray = (key: string): unknown[] => { + try { + const raw = localStorage.getItem(key); + if (!raw) return []; + const parsed = JSON.parse(raw); + return Array.isArray(parsed) ? parsed : []; + } catch { + return []; + } +}; + +/** + * 把 v1 时代 5 个独立 key 的历史迁移进新的 PERSIST_KEY。 + * + * 仅在新 key 尚不存在时执行——已是 v2 用户的 play-history-store 更新,不能被旧数据覆盖。 + * 落盘走 serializePlayHistoryState:自动 minify 剥离 base64 封面 / lyric / song 等派生 + * 字段,迁移过来的旧脏数据不会反过来撑爆 5MB 配额。 + * + * 调用时机由 cleanupLegacyPlayHistoryStorage 保证早于 playHistory store 实例化 + * (player.ts initializePlayState 第一步,先于 playbackController 动态 import), + * 因此直接写 localStorage 即可被 persistedstate 在 store 创建时 hydrate 回来。 + */ +const migrateLegacyPlayHistory = (): void => { + if (localStorage.getItem(PERSIST_KEY)) return; + const migrated: PersistedPlayHistoryState = { + musicHistory: readLegacyArray('musicHistory') as MusicHistoryItem[], + podcastHistory: readLegacyArray('podcastHistory') as DjProgram[], + playlistHistory: readLegacyArray('playlistHistory') as PlaylistHistoryItem[], + albumHistory: readLegacyArray('albumHistory') as AlbumHistoryItem[], + podcastRadioHistory: readLegacyArray('podcastRadioHistory') as PodcastRadioHistoryItem[] + }; + const hasAny = Object.values(migrated).some((arr) => arr.length > 0); + if (!hasAny) return; + try { + localStorage.setItem(PERSIST_KEY, serializePlayHistoryState(migrated)); + } catch (error) { + console.error('[PlayHistory] v1 历史迁移失败:', error); + } +}; + +/** + * 一次性迁移 + 清理 v1 时代遗留的 localStorage key。 + * 先把 5 个历史 key 迁进新 PERSIST_KEY,再删掉全部旧 key 释放配额, + * 避免和新 key 双倍占用。由 playHistory-cleaned-v1 flag 保证只跑一次。 + */ +export const cleanupLegacyPlayHistoryStorage = (): void => { + if (localStorage.getItem('playHistory-cleaned-v1')) return; + migrateLegacyPlayHistory(); + [...LEGACY_HISTORY_KEYS, ...LEGACY_MISC_KEYS].forEach((key) => + localStorage.removeItem(key) + ); + localStorage.setItem('playHistory-cleaned-v1', '1'); +}; + /** * 播放记录统一管理 Store * 使用 Pinia 单例模式,解决多实例不同步问题