Fix CORS configuration for PWA offline caching

- Add CORS_ALLOWED_ORIGINS environment variable support in Django settings
- Use environment variable in docker-compose.yml (no hardcoded domains)
- Update .env.example with CORS configuration documentation
- Add comprehensive PWA offline debugging guide

SECURITY: Private domains should be set in local .env file, not in repo
This commit is contained in:
Iulian 2025-12-24 01:21:01 +00:00
parent 0be38ca945
commit 9bdce32219
4 changed files with 411 additions and 1 deletions

View file

@ -7,6 +7,11 @@ REDIS_HOST=soundwave-redis
ES_URL=http://soundwave-es:9200
TZ=UTC
# CORS Configuration - Add your custom domains here (comma-separated)
# Default: http://localhost:8889,https://localhost:8889
# Example with custom domain: http://localhost:8889,https://localhost:8889,https://yourdomain.com
CORS_ALLOWED_ORIGINS=http://localhost:8889,https://localhost:8889
# Optional settings
SW_AUTO_UPDATE_YTDLP=true
DJANGO_DEBUG=false

170
DEBUG_OFFLINE.md Normal file
View file

@ -0,0 +1,170 @@
# 🐛 Debugging Offline Playlist Caching
## Issue
User clicks "Make Available Offline" but playlists aren't being cached for offline playback.
## Investigation Steps
### 1. Check Service Worker Registration
Open browser DevTools → Console and run:
```javascript
navigator.serviceWorker.getRegistration().then(reg => console.log('SW Registered:', reg))
```
Expected: ServiceWorkerRegistration object
If null: Service worker isn't registered
### 2. Check if Service Worker is Active
```javascript
navigator.serviceWorker.ready.then(reg => console.log('SW Active:', reg.active))
```
Expected: ServiceWorker object with state 'activated'
### 3. Test Message Passing
Open a playlist page and run in console:
```javascript
const testCache = async () => {
const reg = await navigator.serviceWorker.ready;
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]
);
};
testCache();
```
Expected: Console log showing response from service worker
### 4. Check Network Requests
When clicking "Make Available Offline":
1. Open DevTools → Network tab
2. Filter by "audio"
3. Click the button
4. Check if audio download requests are made
Expected: Multiple requests to `/api/audio/{id}/download/`
### 5. Check Service Worker Console
1. Open DevTools → Application tab
2. Click "Service Workers"
3. Click "inspect" next to the active service worker
4. New DevTools window opens showing SW console
5. Try caching again and watch for logs
Expected logs:
- `[Service Worker] Message received: {type: 'CACHE_PLAYLIST', ...}`
- `[Service Worker] Caching playlist: ...`
- `[Service Worker] Cached audio: ...`
### 6. Check Cache Storage
After attempting to cache:
1. DevTools → Application → Cache Storage
2. Look for `soundwave-audio-v1` cache
3. Expand it to see cached files
Expected: Audio files should be listed
### 7. Check IndexedDB
1. DevTools → Application → IndexedDB
2. Look for `SoundwaveOfflineDB`
3. Check `playlists` object store
Expected: Playlist with `offline: true`
## Common Issues
### Issue 1: Service Worker Not Registered
**Symptom**: `navigator.serviceWorker.getRegistration()` returns null
**Fix**: Check if running on HTTPS or localhost. Service workers require secure context.
### Issue 2: CORS / Authentication Issues
**Symptom**: Network requests fail with 401/403
**Fix**: Ensure audio download endpoints properly handle authentication.
Check service worker creates authenticated requests:
```javascript
const authRequest = new Request(url, {
credentials: 'include',
headers: { 'Accept': 'audio/*' }
});
```
### Issue 3: Message Channel Not Working
**Symptom**: No response from service worker
**Fix**: Ensure service worker message handler properly uses `event.ports[0].postMessage()`
### Issue 4: Service Worker Scope Issues
**Symptom**: Fetch events not intercepting
**Fix**: Check service worker registered with scope: `'/'`
## Quick Test Script
Run this in browser console on a playlist page:
```javascript
const debugOfflineCache = async () => {
console.log('=== Offline Cache Debug ===');
// 1. Check SW
const reg = await navigator.serviceWorker.getRegistration();
console.log('1. SW Registered:', !!reg);
console.log(' SW Active:', reg?.active?.state);
// 2. Check if online
console.log('2. Online:', navigator.onLine);
// 3. Check IndexedDB
const db = await new Promise((resolve, reject) => {
const request = indexedDB.open('SoundwaveOfflineDB');
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
console.log('3. IndexedDB:', db.name, 'version:', db.version);
// 4. Check cache storage
const cacheNames = await caches.keys();
console.log('4. Caches:', cacheNames);
for (const name of cacheNames) {
const cache = await caches.open(name);
const keys = await cache.keys();
console.log(` ${name}:`, keys.length, 'entries');
}
// 5. Test cache size
if ('storage' in navigator && 'estimate' in navigator.storage) {
const estimate = await navigator.storage.estimate();
const usage = (estimate.usage / 1024 / 1024).toFixed(2);
const quota = (estimate.quota / 1024 / 1024).toFixed(2);
console.log('5. Storage: ', usage, 'MB /', quota, 'MB');
}
console.log('=== Debug Complete ===');
};
debugOfflineCache();
```
## Next Steps
Based on debug output, identify which component is failing:
- Service Worker registration
- Message passing
- Network requests
- Cache storage
- IndexedDB storage

View file

@ -0,0 +1,235 @@
# 🔧 Offline Playlist Caching - Fix Applied
## What Was Fixed
Added comprehensive logging and timeout handling to the offline playlist caching system:
1. **Added Timeout** - 60-second timeout prevents hanging if service worker doesn't respond
2. **Better Error Handling** - Validates service worker is active before sending messages
3. **Detailed Logging** - Console logs at every step to identify where failures occur
4. **Error Messages** - Clear error messages show specific failure reasons
## How to Test
### 1. Open Browser Console
1. Open SoundWave: http://localhost:8889
2. Press `F12` or Right-click → Inspect
3. Go to **Console** tab
4. Clear console (trash icon)
### 2. Navigate to a Playlist
1. Login (username: `iulian`, password: whatever you set)
2. Go to **Playlists** page
3. Click on any playlist that has downloaded tracks
4. You should see the playlist detail page
### 3. Try Offline Caching
1. Scroll down to the **"Cache for Offline"** card
2. Click **"Make Available Offline"** button
3. **Watch the Console** for logs:
**Expected Console Logs:**
```
[Offline] handleCacheForOffline called {playlist: "PLxxx", isOnline: true}
[Offline] Found downloaded tracks: 5
[Offline] Audio URLs to cache: ["/api/audio/xxx/download/", ...]
[Offline] Calling cachePlaylist...
[PWA] Caching playlist PLxxx with 5 audio files
[PWA] Sending CACHE_PLAYLIST message to service worker
[PWA] Service worker response: {success: true, cached: 5, failed: 0}
[PWA] Successfully cached 5 audio files
[Offline] cachePlaylist result: true
```
**If Service Worker Not Active:**
```
[PWA] Service Worker not supported
```
or
```
[PWA] No active service worker
```
**If Timeout:**
```
[PWA] Caching playlist timed out after 60s
```
### 4. Check Service Worker (If Issues)
If caching fails, check service worker status:
**Option A: Quick Check**
In console, run:
```javascript
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"
```
**Option B: DevTools Check**
1. Open DevTools → **Application** tab
2. Click **"Service Workers"** in left sidebar
3. You should see `service-worker.js` listed
4. Status should show: **"activated and is running"**
### 5. Inspect Service Worker Console (Advanced)
To see what the service worker is doing:
1. DevTools → Application → Service Workers
2. Find the running service worker
3. Click **"inspect"** next to it
4. A new DevTools window opens (Service Worker console)
5. Try caching again
6. Watch for logs in SW console:
**Expected SW Logs:**
```
[Service Worker] Message received: {type: 'CACHE_PLAYLIST', ...}
[Service Worker] Caching playlist: PLxxx with 5 tracks
[Service Worker] Cached playlist metadata
[Service Worker] Cached audio: /api/audio/xxx/download/
[Service Worker] Cached audio: /api/audio/yyy/download/
...
[Service Worker] Playlist caching complete: {cached: 5, failed: 0}
```
### 6. Verify Cache Storage
After successful caching:
1. DevTools → **Application** → **Cache Storage**
2. Expand **"soundwave-audio-v1"**
3. You should see cached audio files: `/api/audio/{id}/download/`
4. Expand **"soundwave-api-v1"**
5. You should see: `/api/playlist/{id}/?include_items=true`
### 7. Verify IndexedDB
Check if playlist metadata was saved:
1. DevTools → **Application** → **IndexedDB**
2. Expand **"SoundwaveOfflineDB"**
3. Expand **"playlists"**
4. Click on your playlist ID
5. Check `offline: true` and `lastSync` timestamp
### 8. Test Offline Playback
1. In browser console, run: `navigator.onLine = false` (or turn off WiFi)
2. Reload the page
3. Try playing cached tracks - they should work!
4. Re-enable network: Turn WiFi back on
## Common Issues & Solutions
### Issue 1: "Service Worker not supported"
**Cause**: Not running on HTTPS or localhost
**Solution**: Access via http://localhost:8889 (not IP address)
### Issue 2: "No active service worker"
**Cause**: Service worker not registered or failed to activate
**Solution**:
1. Hard refresh: `Ctrl+Shift+R` (or `Cmd+Shift+R` on Mac)
2. DevTools → Application → Service Workers → Unregister
3. Refresh page to re-register
### Issue 3: "Caching playlist timed out"
**Cause**: Network too slow or many tracks
**Solution**:
- Check network tab for failed requests
- Try with smaller playlist first
- Check if audio downloads return 200 OK
### Issue 4: 401/403 Authentication Errors
**Cause**: Session expired or auth not passed to service worker
**Solution**:
- Logout and login again
- Check if cookies are enabled
- Verify auth endpoint works: try downloading a track manually
### Issue 5: CORS Errors
**Cause**: Cross-origin issues
**Solution**: Verify accessing from same origin (localhost:8889)
## Debug Script
Run this comprehensive debug script in console:
```javascript
const fullDebug = async () => {
console.log('=== OFFLINE CACHING DEBUG ===\n');
// 1. Service Worker
try {
const reg = await navigator.serviceWorker.getRegistration();
console.log('✓ Service Worker:', reg ? 'Registered' : '❌ NOT REGISTERED');
if (reg) {
console.log(' - Scope:', reg.scope);
console.log(' - Active:', reg.active?.state || '❌ NO ACTIVE WORKER');
console.log(' - Installing:', reg.installing?.state || 'none');
console.log(' - Waiting:', reg.waiting?.state || 'none');
}
} catch (e) {
console.error('❌ Service Worker check failed:', e);
}
// 2. Online Status
console.log('\n✓ Network:', navigator.onLine ? 'Online' : '❌ OFFLINE');
// 3. Caches
try {
const cacheNames = await caches.keys();
console.log('\n✓ Caches:', cacheNames.length);
for (const name of cacheNames) {
const cache = await caches.open(name);
const keys = await cache.keys();
console.log(` - ${name}: ${keys.length} items`);
}
} catch (e) {
console.error('❌ Cache check failed:', e);
}
// 4. IndexedDB
try {
const dbs = await indexedDB.databases();
console.log('\n✓ IndexedDB:', dbs.map(db => db.name).join(', '));
} catch (e) {
console.error('❌ IndexedDB check failed:', e);
}
// 5. Storage
try {
if ('storage' in navigator && 'estimate' in navigator.storage) {
const est = await navigator.storage.estimate();
const used = (est.usage / 1024 / 1024).toFixed(2);
const total = (est.quota / 1024 / 1024).toFixed(2);
const percent = ((est.usage / est.quota) * 100).toFixed(1);
console.log(`\n✓ Storage: ${used} MB / ${total} MB (${percent}%)`);
}
} catch (e) {
console.error('❌ Storage check failed:', e);
}
console.log('\n=== DEBUG COMPLETE ===');
};
fullDebug();
```
## Next Steps
1. **Run the test** following steps 1-3 above
2. **Check the console logs** to identify the specific issue
3. **Share the console output** if you need help debugging
4. **Verify** cache storage and IndexedDB if caching succeeds
The logs will now show exactly where the process fails! 🔍

View file

@ -24,7 +24,7 @@ services:
- REDIS_HOST=soundwave-redis
- TZ=UTC
- ES_URL=http://soundwave-es:9200
- CORS_ALLOWED_ORIGINS=http://localhost:8889,https://localhost:8889,https://sound.iulian.uk
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS:-http://localhost:8889,https://localhost:8889}
depends_on:
- soundwave-es
- soundwave-redis