feat: Refactor service worker registration and enhance offline download manager with client-side checks
This commit is contained in:
@@ -15,16 +15,18 @@ import { LoginForm } from "./start-screen";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import PageTransition from "./PageTransition";
|
import PageTransition from "./PageTransition";
|
||||||
|
|
||||||
// Service Worker registration
|
// Service Worker registration - moved to useEffect to ensure it only runs client-side
|
||||||
if (typeof window !== 'undefined' && 'serviceWorker' in navigator) {
|
React.useEffect(() => {
|
||||||
navigator.serviceWorker.register('/sw.js')
|
if ('serviceWorker' in navigator) {
|
||||||
.then((registration) => {
|
navigator.serviceWorker.register('/sw.js')
|
||||||
console.log('Service Worker registered successfully:', registration);
|
.then((registration) => {
|
||||||
})
|
console.log('Service Worker registered successfully:', registration);
|
||||||
.catch((error) => {
|
})
|
||||||
console.error('Service Worker registration failed:', error);
|
.catch((error) => {
|
||||||
});
|
console.error('Service Worker registration failed:', error);
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
function NavidromeErrorBoundary({ children }: { children: React.ReactNode }) {
|
function NavidromeErrorBoundary({ children }: { children: React.ReactNode }) {
|
||||||
// For now, since we're switching to offline-first, we'll handle errors differently
|
// For now, since we're switching to offline-first, we'll handle errors differently
|
||||||
|
|||||||
@@ -394,7 +394,95 @@ class DownloadManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadManager = new DownloadManager();
|
// Create a singleton instance that will be initialized on the client side
|
||||||
|
let downloadManagerInstance: DownloadManager | null = null;
|
||||||
|
|
||||||
|
// Only create the download manager instance on the client side
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
downloadManagerInstance = new DownloadManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a safe wrapper around the download manager
|
||||||
|
const downloadManager = {
|
||||||
|
initialize: async () => {
|
||||||
|
if (!downloadManagerInstance) return false;
|
||||||
|
return downloadManagerInstance.initialize();
|
||||||
|
},
|
||||||
|
getOfflineStats: async () => {
|
||||||
|
if (!downloadManagerInstance) return {
|
||||||
|
totalSize: 0,
|
||||||
|
audioSize: 0,
|
||||||
|
imageSize: 0,
|
||||||
|
metaSize: 0,
|
||||||
|
downloadedAlbums: 0,
|
||||||
|
downloadedSongs: 0,
|
||||||
|
lastDownload: null,
|
||||||
|
downloadErrors: 0,
|
||||||
|
remainingStorage: null,
|
||||||
|
autoDownloadEnabled: false,
|
||||||
|
downloadQuality: 'original' as const,
|
||||||
|
downloadOnWifiOnly: true,
|
||||||
|
priorityContent: []
|
||||||
|
};
|
||||||
|
return downloadManagerInstance.getOfflineStats();
|
||||||
|
},
|
||||||
|
downloadAlbum: async (album: Album, songs: Song[], progressCallback: (progress: DownloadProgress) => void) => {
|
||||||
|
if (!downloadManagerInstance) return;
|
||||||
|
return downloadManagerInstance.downloadAlbum(album, songs, progressCallback);
|
||||||
|
},
|
||||||
|
downloadAlbumFallback: async (album: Album, songs: Song[]) => {
|
||||||
|
if (!downloadManagerInstance) return;
|
||||||
|
return downloadManagerInstance.downloadAlbumFallback(album, songs);
|
||||||
|
},
|
||||||
|
downloadSong: async (song: Song) => {
|
||||||
|
if (!downloadManagerInstance) return;
|
||||||
|
return downloadManagerInstance.downloadSong(song);
|
||||||
|
},
|
||||||
|
getOfflineData: () => {
|
||||||
|
if (!downloadManagerInstance) return { albums: {}, songs: {} };
|
||||||
|
return downloadManagerInstance.getOfflineData();
|
||||||
|
},
|
||||||
|
saveOfflineData: (data: any) => {
|
||||||
|
if (!downloadManagerInstance) return;
|
||||||
|
return downloadManagerInstance.saveOfflineData(data);
|
||||||
|
},
|
||||||
|
checkOfflineStatus: async (id: string, type: 'album' | 'song') => {
|
||||||
|
if (!downloadManagerInstance) return false;
|
||||||
|
return downloadManagerInstance.checkOfflineStatus(id, type);
|
||||||
|
},
|
||||||
|
checkOfflineStatusFallback: (id: string, type: 'album' | 'song') => {
|
||||||
|
if (!downloadManagerInstance) return false;
|
||||||
|
return downloadManagerInstance.checkOfflineStatusFallback(id, type);
|
||||||
|
},
|
||||||
|
deleteOfflineContent: async (id: string, type: 'album' | 'song') => {
|
||||||
|
if (!downloadManagerInstance) return;
|
||||||
|
return downloadManagerInstance.deleteOfflineContent(id, type);
|
||||||
|
},
|
||||||
|
deleteOfflineContentFallback: async (id: string, type: 'album' | 'song') => {
|
||||||
|
if (!downloadManagerInstance) return;
|
||||||
|
return downloadManagerInstance.deleteOfflineContentFallback(id, type);
|
||||||
|
},
|
||||||
|
getOfflineItems: async () => {
|
||||||
|
if (!downloadManagerInstance) return { albums: [], songs: [] };
|
||||||
|
return downloadManagerInstance.getOfflineItems();
|
||||||
|
},
|
||||||
|
getOfflineAlbums: () => {
|
||||||
|
if (!downloadManagerInstance) return [];
|
||||||
|
return downloadManagerInstance.getOfflineAlbums();
|
||||||
|
},
|
||||||
|
getOfflineSongs: () => {
|
||||||
|
if (!downloadManagerInstance) return [];
|
||||||
|
return downloadManagerInstance.getOfflineSongs();
|
||||||
|
},
|
||||||
|
downloadQueue: async (songs: Song[]) => {
|
||||||
|
if (!downloadManagerInstance) return;
|
||||||
|
return downloadManagerInstance.downloadQueue(songs);
|
||||||
|
},
|
||||||
|
enableOfflineMode: async (settings: any) => {
|
||||||
|
if (!downloadManagerInstance) return;
|
||||||
|
return downloadManagerInstance.enableOfflineMode(settings);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export function useOfflineDownloads() {
|
export function useOfflineDownloads() {
|
||||||
const [isSupported, setIsSupported] = useState(false);
|
const [isSupported, setIsSupported] = useState(false);
|
||||||
@@ -424,6 +512,13 @@ export function useOfflineDownloads() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initializeDownloadManager = async () => {
|
const initializeDownloadManager = async () => {
|
||||||
|
// Skip initialization on server-side
|
||||||
|
if (!downloadManager) {
|
||||||
|
setIsSupported(false);
|
||||||
|
setIsInitialized(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const supported = await downloadManager.initialize();
|
const supported = await downloadManager.initialize();
|
||||||
setIsSupported(supported);
|
setIsSupported(supported);
|
||||||
setIsInitialized(true);
|
setIsInitialized(true);
|
||||||
|
|||||||
@@ -86,7 +86,10 @@ export function useOfflineLibrarySync() {
|
|||||||
window.addEventListener('online', handleOnline);
|
window.addEventListener('online', handleOnline);
|
||||||
window.addEventListener('offline', handleOffline);
|
window.addEventListener('offline', handleOffline);
|
||||||
|
|
||||||
setIsOnline(navigator.onLine);
|
// Check if navigator is available (client-side only)
|
||||||
|
if (typeof navigator !== 'undefined') {
|
||||||
|
setIsOnline(navigator.onLine);
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('online', handleOnline);
|
window.removeEventListener('online', handleOnline);
|
||||||
|
|||||||
@@ -19,9 +19,12 @@ export interface OfflineLibraryState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useOfflineLibrary() {
|
export function useOfflineLibrary() {
|
||||||
|
// Check if we're on the client side
|
||||||
|
const isClient = typeof window !== 'undefined';
|
||||||
|
|
||||||
const [state, setState] = useState<OfflineLibraryState>({
|
const [state, setState] = useState<OfflineLibraryState>({
|
||||||
isInitialized: false,
|
isInitialized: false,
|
||||||
isOnline: navigator.onLine,
|
isOnline: isClient ? navigator.onLine : true, // Default to true during SSR
|
||||||
isSyncing: false,
|
isSyncing: false,
|
||||||
lastSync: null,
|
lastSync: null,
|
||||||
stats: {
|
stats: {
|
||||||
|
|||||||
Reference in New Issue
Block a user