From 186733dccfebdfebf94c0ef72ccc7fa3ea6542c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=E6=82=A6?= Date: Wed, 7 Jan 2026 18:34:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E5=8D=95=E4=B8=80SyncToken?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=EF=BC=8C=E5=90=88=E5=B9=B6=E7=BD=91=E6=98=93?= =?UTF-8?q?=E4=BA=91ID=E5=88=B0SyncToken=EF=BC=8C=E5=AE=9E=E7=8E=B0"?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E5=8D=B3=E6=9B=BF=E6=8D=A2"=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20=E8=B0=83=E6=95=B4=E5=90=8C=E6=AD=A5=E7=AD=96?= =?UTF-8?q?=E7=95=A5=EF=BC=9A=E7=BD=91=E6=98=93=E4=BA=91=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=B8=8B=EF=BC=8C=E8=87=AA=E5=8A=A8=E6=89=A7=E8=A1=8C"?= =?UTF-8?q?=E6=8B=89=E5=8F=96=E7=BD=91=E6=98=93=E4=BA=91=20->=20=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E6=9C=AC=E5=9C=B0(=E9=9D=9E=E8=A6=86=E7=9B=96)=20->?= =?UTF-8?q?=20=E6=8E=A8=E9=80=81=E8=87=B3=E7=A7=81=E6=9C=89=E4=BA=91KV"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 110 +++++++++++++++++++++++++---------------------------- 1 file changed, 52 insertions(+), 58 deletions(-) diff --git a/index.html b/index.html index ceb3bd9..8636778 100644 --- a/index.html +++ b/index.html @@ -431,7 +431,7 @@ ); - const SideDrawer = ({ isOpen, onClose, view, setView, quality, setQuality, onClearCache, syncToken, setSyncToken, onSyncNow, onImportNetease, neteasePlaylistId, onStopNeteaseSync }) => { + const SideDrawer = ({ isOpen, onClose, view, setView, quality, setQuality, onClearCache, syncToken, setSyncToken, onSyncNow, onImportNetease, syncMode }) => { const [isSyncing, setIsSyncing] = useState(false); const [syncMsg, setSyncMsg] = useState(''); @@ -510,7 +510,9 @@
- +

- 私有云多端同步收藏列表 + {syncMode === 'netease_playlist' + ? '已关联歌单,将合并新歌并自动备份至云端' + : '使用相同的密钥在多端同步收藏列表'}

{syncMsg && {syncMsg}}
-
-
- - {neteasePlaylistId ? ( -
-
-
ID: {neteasePlaylistId}
-
自动更新中
-
- -
- ) : ( - - )} -

- {neteasePlaylistId ? '每15分钟自动检测新歌并加入收藏,随后触发云同步。' : '导入后将自动合并新歌到收藏列表。'} -

+ +

导入后将设置ID为同步密钥,并定期获取新歌

@@ -937,7 +921,7 @@ const [quality, setQuality] = useState(() => localStorage.getItem('th_quality') || '320k'); const [syncToken, setSyncToken] = useState(() => localStorage.getItem('th_sync_token') || ''); const [lastSuccessToken, setLastSuccessToken] = useState(() => localStorage.getItem('th_last_success_token') || ''); - const [neteasePlaylistId, setNeteasePlaylistId] = useState(() => localStorage.getItem('th_netease_playlist_id') || ''); + const [syncMode, setSyncMode] = useState(() => localStorage.getItem('th_sync_mode') || 'server'); // 'server' | 'netease_playlist' // UI State const [showFullPlayer, setShowFullPlayer] = useState(false); @@ -971,7 +955,7 @@ useEffect(() => { localStorage.setItem('th_quality', quality); }, [quality]); useEffect(() => { localStorage.setItem('th_sync_token', syncToken); }, [syncToken]); useEffect(() => { localStorage.setItem('th_last_success_token', lastSuccessToken); }, [lastSuccessToken]); - useEffect(() => { localStorage.setItem('th_netease_playlist_id', neteasePlaylistId); }, [neteasePlaylistId]); + useEffect(() => { localStorage.setItem('th_sync_mode', syncMode); }, [syncMode]); // Auto Sync Logic for Private Server useEffect(() => { @@ -987,36 +971,40 @@ // Auto Sync Logic for Netease Playlist (Interval based) useEffect(() => { - if (neteasePlaylistId) { + if (syncMode === 'netease_playlist' && syncToken) { const doSync = async () => { console.log("Auto syncing netease playlist..."); - const songs = await api.getPlaylist(neteasePlaylistId); - if (songs && songs.length > 0) { - setFavorites(prev => { - const newFavs = [...prev]; - let changed = false; - // Add new songs (reverse to keep latest at top if we prepend) - [...songs].reverse().forEach(song => { - if (!newFavs.find(s => s.id === song.id)) { - newFavs.unshift({ ...song, source: 'netease' }); - changed = true; - } + try { + const songs = await api.getPlaylist(syncToken); + if (songs && songs.length > 0) { + let hasChanges = false; + setFavorites(prev => { + const newFavs = [...prev]; + // Add new songs (reverse to keep latest at top if we prepend) + [...songs].reverse().forEach(song => { + if (!newFavs.find(s => s.id === song.id)) { + newFavs.unshift({ ...song, source: 'netease' }); + hasChanges = true; + } + }); + return hasChanges ? newFavs : prev; }); - return changed ? newFavs : prev; - }); + } + } catch (e) { + console.error("Auto sync netease playlist failed", e); } }; - // Initial sync on mount/mode change (if not already handled by import) - // We can skip initial immediate sync if we assume import did it, but it doesn't hurt to check. - // Actually, if we just refreshed page, we want to check. + // Initial sync on mount is skipped because import handles it, + // or if page refresh, server sync will pull first. + // But if we want to ensure we get new songs from netease on page load: doSync(); // Interval sync (15 minutes) const interval = setInterval(doSync, 15 * 60 * 1000); return () => clearInterval(interval); } - }, [neteasePlaylistId]); + }, [syncMode, syncToken]); // 1. Auto Sync: Incremental update based on diff (Server Mode) const autoSyncFavorites = async () => { @@ -1136,7 +1124,13 @@ return newFavs; }); - setNeteasePlaylistId(id); + setSyncToken(id); + setLastSuccessToken(id); + setSyncMode('netease_playlist'); + + // Trigger cloud sync immediately after state update + // Note: state update is async, so we might need to rely on the useEffect auto-sync + // which watches 'favorites' change. // Switch view to favorites to see result setView('favorites'); @@ -1151,11 +1145,12 @@ } }; - const stopNeteaseSync = () => { - if(confirm("确定要停止自动同步网易云歌单吗?已导入的歌曲不会被删除。")) { - setNeteasePlaylistId(''); + // Detect manual token change to reset mode + useEffect(() => { + if (!syncToken) { + setSyncMode('server'); } - }; + }, [syncToken]); useEffect(() => { if (currentSong) { @@ -1550,8 +1545,7 @@ setSyncToken={setSyncToken} onSyncNow={manualSyncFavorites} onImportNetease={importNeteasePlaylist} - neteasePlaylistId={neteasePlaylistId} - onStopNeteaseSync={stopNeteaseSync} + syncMode={syncMode} /> {/* Top Navigation / Search Bar */}