diff --git a/index.html b/index.html
index 7a09c3a..ceb3bd9 100644
--- a/index.html
+++ b/index.html
@@ -431,7 +431,7 @@
);
- const SideDrawer = ({ isOpen, onClose, view, setView, quality, setQuality, onClearCache, syncToken, setSyncToken, onSyncNow, onImportNetease, syncMode }) => {
+ const SideDrawer = ({ isOpen, onClose, view, setView, quality, setQuality, onClearCache, syncToken, setSyncToken, onSyncNow, onImportNetease, neteasePlaylistId, onStopNeteaseSync }) => {
const [isSyncing, setIsSyncing] = useState(false);
const [syncMsg, setSyncMsg] = useState('');
@@ -479,14 +479,14 @@
-
+
- {syncMode === 'netease_playlist'
- ? '当前为网易云歌单同步模式,每15分钟自动刷新'
- : '使用相同的密钥在多端同步收藏列表'}
+ 私有云多端同步收藏列表
{syncMsg &&
{syncMsg}}
+
+
-
-
导入后将开启自动同步,每15分钟获取新歌
+
+ {neteasePlaylistId ? (
+
+
+
ID: {neteasePlaylistId}
+
自动更新中
+
+
+
+ ) : (
+
+ )}
+
+ {neteasePlaylistId ? '每15分钟自动检测新歌并加入收藏,随后触发云同步。' : '导入后将自动合并新歌到收藏列表。'}
+
@@ -921,7 +937,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 [syncMode, setSyncMode] = useState(() => localStorage.getItem('th_sync_mode') || 'server'); // 'server' | 'netease_playlist'
+ const [neteasePlaylistId, setNeteasePlaylistId] = useState(() => localStorage.getItem('th_netease_playlist_id') || '');
// UI State
const [showFullPlayer, setShowFullPlayer] = useState(false);
@@ -955,26 +971,26 @@
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_sync_mode', syncMode); }, [syncMode]);
+ useEffect(() => { localStorage.setItem('th_netease_playlist_id', neteasePlaylistId); }, [neteasePlaylistId]);
// Auto Sync Logic for Private Server
useEffect(() => {
- // Only auto-sync if we are in server mode, have a token, it matches the last successfully synced token,
+ // Only auto-sync if we have a token, it matches the last successfully synced token,
// and there are actual changes compared to last sync.
- if (syncMode === 'server' && syncToken && syncToken === lastSuccessToken && JSON.stringify(favorites) !== JSON.stringify(lastSyncedFavorites)) {
+ if (syncToken && syncToken === lastSuccessToken && JSON.stringify(favorites) !== JSON.stringify(lastSyncedFavorites)) {
const timer = setTimeout(() => {
autoSyncFavorites();
}, 1000);
return () => clearTimeout(timer);
}
- }, [favorites, syncToken, lastSuccessToken, lastSyncedFavorites, syncMode]);
+ }, [favorites, syncToken, lastSuccessToken, lastSyncedFavorites]);
// Auto Sync Logic for Netease Playlist (Interval based)
useEffect(() => {
- if (syncMode === 'netease_playlist' && syncToken) {
+ if (neteasePlaylistId) {
const doSync = async () => {
console.log("Auto syncing netease playlist...");
- const songs = await api.getPlaylist(syncToken);
+ const songs = await api.getPlaylist(neteasePlaylistId);
if (songs && songs.length > 0) {
setFavorites(prev => {
const newFavs = [...prev];
@@ -991,18 +1007,20 @@
}
};
- // Initial sync on mount/mode change
+ // 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.
doSync();
// Interval sync (15 minutes)
const interval = setInterval(doSync, 15 * 60 * 1000);
return () => clearInterval(interval);
}
- }, [syncMode, syncToken]);
+ }, [neteasePlaylistId]);
// 1. Auto Sync: Incremental update based on diff (Server Mode)
const autoSyncFavorites = async () => {
- if (!syncToken || syncToken !== lastSuccessToken || syncMode !== 'server') return;
+ if (!syncToken || syncToken !== lastSuccessToken) return;
try {
// Get latest remote state
const remoteFavorites = await syncService.get('favorites', syncToken) || [];
@@ -1046,25 +1064,6 @@
const manualSyncFavorites = async () => {
if (!syncToken) return;
- // If in Netease Mode, manual sync means fetching playlist again
- if (syncMode === 'netease_playlist') {
- const songs = await api.getPlaylist(syncToken);
- if (songs && songs.length > 0) {
- setFavorites(prev => {
- const newFavs = [...prev];
- [...songs].reverse().forEach(song => {
- if (!newFavs.find(s => s.id === song.id)) {
- newFavs.unshift({ ...song, source: 'netease' });
- }
- });
- return newFavs;
- });
- } else {
- throw new Error("获取歌单失败");
- }
- return;
- }
-
// Server Mode Sync
// Determine Mode: Switch (Overwrite Local) or Sync (Merge)
@@ -1136,10 +1135,9 @@
alert(`成功导入 ${addedCount} 首新歌 (共 ${songs.length} 首)`);
return newFavs;
});
- // Set sync state
- setSyncToken(id);
- setLastSuccessToken(id); // Treat as synced
- setSyncMode('netease_playlist');
+
+ setNeteasePlaylistId(id);
+
// Switch view to favorites to see result
setView('favorites');
} else {
@@ -1153,26 +1151,11 @@
}
};
- // Allow user to switch back to server mode manually by clearing token or just editing it
- // We need to detect if user manually edits input to something that is not the playlist id
- useEffect(() => {
- if (syncMode === 'netease_playlist' && syncToken !== lastSuccessToken) {
- // If user changes token, revert to server mode implicitly?
- // Or wait for them to click sync?
- // For now, let's keep it simple. If they click "Import Netease", it forces Netease mode.
- // If they type a new token and click Sync, it will try to fetch playlist if mode is netease,
- // likely fail, then user might be confused.
- // Better: If user types in input, we assume they might want to switch mode if it fails?
- // Let's rely on the import button to set the mode.
- // If user wants to go back to server mode, they can clear token or we add a toggle?
- // The input label changes, so user knows.
+ const stopNeteaseSync = () => {
+ if(confirm("确定要停止自动同步网易云歌单吗?已导入的歌曲不会被删除。")) {
+ setNeteasePlaylistId('');
}
-
- // If user clears token, reset mode to server (default)
- if (!syncToken) {
- setSyncMode('server');
- }
- }, [syncToken]);
+ };
useEffect(() => {
if (currentSong) {
@@ -1567,7 +1550,8 @@
setSyncToken={setSyncToken}
onSyncNow={manualSyncFavorites}
onImportNetease={importNeteasePlaylist}
- syncMode={syncMode}
+ neteasePlaylistId={neteasePlaylistId}
+ onStopNeteaseSync={stopNeteaseSync}
/>
{/* Top Navigation / Search Bar */}