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 */}