- Add CORS_ALLOWED_ORIGINS environment variable support in Django settings - Update docker-compose.yml to include CORS origins (HTTP, HTTPS, custom domain) - Add comprehensive PWA offline debugging guide
9.1 KiB
🐛 PWA Offline Caching Debug Guide
Issue Summary
PWA fails to cache playlists for offline playing with errors like "Failed to cache playlist" and no sound plays offline.
Root Causes Identified
1. CORS Configuration Missing
Problem: Django wasn't reading CORS_ALLOWED_ORIGINS from environment variables.
Fixed: Updated backend/config/settings.py to read from environment variable.
Verify Fix:
# Rebuild container
docker compose build
docker compose up -d
# Check logs
docker compose logs soundwave | grep CORS
2. Service Worker Not Receiving Messages
Problem: Service worker might not be active or registered properly.
Check:
// In browser console
navigator.serviceWorker.getRegistration().then(reg => {
console.log('SW Registered:', !!reg);
console.log('SW Active:', reg?.active?.state);
});
Expected output:
SW Registered: true
SW Active: "activated"
3. Audio Fetch Failing Due to CORS or Auth
Problem: Service worker can't fetch audio files due to CORS or authentication issues.
Step-by-Step Debugging
Step 1: Check Service Worker Status
Open DevTools (F12) → Application tab → Service Workers
You should see:
- ✅
service-worker.jsregistered - ✅ Status: "activated and is running"
- ✅ Source:
http://localhost:8889/service-worker.js
If not registered:
// In console
navigator.serviceWorker.register('/service-worker.js')
.then(reg => console.log('SW Registered', reg))
.catch(err => console.error('SW Registration failed', err));
Step 2: Test Service Worker Communication
// In browser console
const testSW = async () => {
const reg = await navigator.serviceWorker.ready;
if (!reg.active) {
console.error('❌ No active service worker');
return;
}
const messageChannel = new MessageChannel();
messageChannel.port1.onmessage = (event) => {
console.log('✅ Response from SW:', event.data);
};
reg.active.postMessage(
{
type: 'CACHE_PLAYLIST',
playlistId: 'test123',
audioUrls: ['/api/audio/test/download/']
},
[messageChannel.port2]
);
};
testSW();
Expected: Response from service worker within 1-2 seconds.
Step 3: Check CORS Headers
Open DevTools → Network tab
- Navigate to a playlist
- Click "Make Available Offline"
- Look for requests to
/api/audio/{id}/download/ - Click on one request
- Check Response Headers
Required headers:
Access-Control-Allow-Origin: https://sound.iulian.uk
Access-Control-Allow-Credentials: true
Content-Type: audio/mpeg (or audio/mp4, etc.)
If CORS headers missing:
- ❌ Backend CORS not configured correctly
- ❌ Check
CORS_ALLOWED_ORIGINSenvironment variable
Step 4: Test Manual Audio Fetch
// In browser console
const testAudioFetch = async () => {
try {
const response = await fetch('/api/audio/YOUR_YOUTUBE_ID/download/', {
credentials: 'include',
headers: {
'Accept': 'audio/*'
}
});
console.log('Status:', response.status);
console.log('Headers:', [...response.headers.entries()]);
console.log('Content-Type:', response.headers.get('content-type'));
if (response.ok) {
console.log('✅ Audio fetch successful');
const blob = await response.blob();
console.log('✅ Blob size:', (blob.size / 1024 / 1024).toFixed(2), 'MB');
} else {
console.error('❌ Audio fetch failed:', response.statusText);
}
} catch (err) {
console.error('❌ Fetch error:', err);
}
};
testAudioFetch();
Replace YOUR_YOUTUBE_ID with an actual YouTube ID from your playlist.
Step 5: Inspect Service Worker Console
- DevTools → Application → Service Workers
- Find the active service worker
- Click "inspect" next to it
- A new DevTools window opens (Service Worker console)
- Try caching a playlist again
- Watch the SW console for errors
Expected logs in SW console:
[Service Worker] Message received: {type: 'CACHE_PLAYLIST', ...}
[Service Worker] Caching playlist: PLxxx with 5 tracks
[Service Worker] Cached playlist metadata
[Service Worker] Fetching: /api/audio/xxx/download/
[Service Worker] ✓ Cached: /api/audio/xxx/download/ - 3.45 MB
[Service Worker] ✓ Cached: /api/audio/yyy/download/ - 4.12 MB
...
[Service Worker] Playlist caching complete
Common errors:
❌ TypeError: Failed to fetch
→ CORS issue or network problem
❌ HTTP 401 Unauthorized
→ Authentication cookies not sent
❌ HTTP 403 Forbidden
→ CORS or CSRF issue
❌ HTTP 404 Not Found
→ Audio not downloaded yet or wrong URL
Step 6: Check Cache Storage
DevTools → Application → Cache Storage
You should see:
soundwave-v1- Static assetssoundwave-api-v1- API responsessoundwave-audio-v1- Audio files ← This is where audio should besoundwave-images-v1- Images
Click on soundwave-audio-v1:
- Should show cached audio files with keys like
/api/audio/{id}/download/ - Each entry should have a size (MB)
If empty after caching:
- ❌ Caching failed silently
- Check SW console for errors
Step 7: Test Offline Playback
- Cache a playlist (follow steps above to ensure it works)
- DevTools → Network tab
- Change throttling to "Offline"
- Try playing a track
What to check:
- Network tab shows requests but they should come from "ServiceWorker"
- Console should show:
[Service Worker] ✓ Serving audio from cache: /api/audio/xxx/download/
If fails:
❌ [Service Worker] ✗ Cache miss for: /api/audio/xxx/download/
→ Audio wasn't cached properly
❌ [Service Worker] Available cached audio: []
→ Cache is empty
Quick Fixes
Fix 1: Restart Docker Containers
cd /home/iulian/projects/zi-tube/soundwave
docker compose down
docker compose build --no-cache
docker compose up -d
Fix 2: Clear All Caches
// In browser console
const clearAllCaches = async () => {
const cacheNames = await caches.keys();
await Promise.all(cacheNames.map(name => caches.delete(name)));
console.log('✅ All caches cleared');
// Unregister service worker
const reg = await navigator.serviceWorker.getRegistration();
if (reg) {
await reg.unregister();
console.log('✅ Service worker unregistered');
}
console.log('🔄 Reload page now');
};
clearAllCaches();
Then reload the page (hard refresh: Ctrl+Shift+R).
Fix 3: Update Service Worker
// In browser console
const updateSW = async () => {
const reg = await navigator.serviceWorker.getRegistration();
if (reg) {
await reg.update();
console.log('✅ Service worker updated');
}
};
updateSW();
Fix 4: Check Container Environment Variables
# Check if CORS is set
docker compose exec soundwave env | grep CORS
# Should show:
# CORS_ALLOWED_ORIGINS=http://localhost:8889,https://localhost:8889,https://sound.iulian.uk
If not shown, environment variable not set in docker-compose.yml.
Known Issues & Solutions
Issue: "Failed to cache playlist" after 60 seconds
Cause: Timeout - too many files or slow network
Solution:
- Cache smaller playlists first (< 10 tracks)
- Check network speed
- Increase timeout in
frontend/src/utils/pwa.ts(line ~325)
Issue: CORS error when fetching audio
Cause: Backend not configured for HTTPS origin
Solution: Already fixed in docker-compose.yml and settings.py
Issue: Service worker not updating
Cause: Browser caching old service worker
Solution:
- DevTools → Application → Service Workers
- Check "Update on reload"
- Hard refresh (Ctrl+Shift+R)
Issue: Audio plays online but not offline
Cause: Audio not in cache or wrong cache key
Solution:
- Check Cache Storage (Step 6)
- Verify cache keys match request URLs exactly
- Re-cache the playlist
Testing Checklist
Before reporting the issue is fixed:
- Service worker registered and active
- CORS headers present on audio downloads
- Can cache a small playlist (3-5 tracks)
- Cache Storage shows audio files
- Offline mode: can play cached tracks
- Network tab shows "ServiceWorker" as source
- No console errors during playback
Advanced: Check Django CORS Settings
# SSH into container
docker compose exec soundwave bash
# Open Django shell
python manage.py shell
# Check CORS settings
from django.conf import settings
print("CORS_ALLOWED_ORIGINS:", settings.CORS_ALLOWED_ORIGINS)
print("CORS_ALLOW_CREDENTIALS:", settings.CORS_ALLOW_CREDENTIALS)
print("CSRF_TRUSTED_ORIGINS:", settings.CSRF_TRUSTED_ORIGINS)
Expected output:
CORS_ALLOWED_ORIGINS: ['http://localhost:8889', 'https://localhost:8889', 'https://sound.iulian.uk']
CORS_ALLOW_CREDENTIALS: True
CSRF_TRUSTED_ORIGINS: ['http://localhost:8889', 'https://localhost:8889', 'https://sound.iulian.uk']
Need More Help?
If still not working after following this guide:
- Share output from Step 1 (SW status)
- Share output from Step 4 (audio fetch test)
- Share screenshot of Step 5 (SW console errors)
- Share screenshot of Step 6 (Cache Storage)
This will help identify the exact issue.