soundwave/docs/PLAYLIST_BROWSING_FEATURE.md
Iulian 51679d1943 Initial commit - SoundWave v1.0
- Full PWA support with offline capabilities
- Comprehensive search across songs, playlists, and channels
- Offline playlist manager with download tracking
- Pre-built frontend for zero-build deployment
- Docker-based deployment with docker compose
- Material-UI dark theme interface
- YouTube audio download and management
- Multi-user authentication support
2025-12-16 23:43:07 +00:00

14 KiB

Playlist Browsing Feature - Implementation Summary

Overview

Implemented comprehensive playlist browsing functionality allowing users to view and interact with all tracks within downloaded YouTube playlists. Users can now click on a playlist to see all available media, with clear indicators for downloaded vs. not-yet-downloaded tracks.

Problem Statement

Previously, playlists showed only metadata (title, channel, item count, download progress) but users couldn't:

  • View the list of tracks within a playlist
  • Play individual tracks from a playlist
  • See which tracks were downloaded vs. pending
  • Browse playlist contents in an organized manner

Solution Implemented

Backend Changes

1. Enhanced Playlist Detail Endpoint (playlist/views.py)

def get(self, request, playlist_id):
    """Get playlist details with items"""
    playlist = get_object_or_404(Playlist, playlist_id=playlist_id, owner=request.user)
    
    # Optional inclusion of items via query parameter
    include_items = request.query_params.get('include_items', 'false').lower() == 'true'
    
    if include_items:
        # Get all playlist items with full audio details
        items = PlaylistItem.objects.filter(playlist=playlist)\
            .select_related('audio').order_by('position')
        response_data['items'] = [{
            'id': item.id,
            'position': item.position,
            'added_date': item.added_date,
            'audio': AudioSerializer(item.audio).data
        } for item in items]

Features:

  • Optional include_items query parameter to control payload size
  • Proper eager loading with select_related to avoid N+1 queries
  • Returns full audio metadata for each track
  • User isolation maintained (owner filter)
  • Ordered by position for correct playlist order

Security:

  • User authentication required (ApiBaseView)
  • Owner-based filtering prevents cross-user access
  • Uses Django's get_object_or_404 for proper 404 handling
  • No SQL injection risks (uses ORM)

2. API Endpoint

GET /api/playlist/{playlist_id}/?include_items=true

Response Format:

{
  "id": 1,
  "playlist_id": "PLxxx",
  "title": "Hip-Hop",
  "channel_name": "Music Channel",
  "item_count": 16,
  "downloaded_count": 16,
  "sync_status": "success",
  "progress_percent": 100,
  "items": [
    {
      "id": 1,
      "position": 0,
      "added_date": "2025-12-15T10:00:00Z",
      "audio": {
        "id": 123,
        "youtube_id": "abc123",
        "title": "Track Title",
        "channel_name": "Artist",
        "duration": 240,
        "file_path": "audio/2025/file.m4a",
        "thumbnail_url": "...",
        "...": "..."
      }
    }
  ]
}

Frontend Changes

1. New PlaylistDetailPage Component (pages/PlaylistDetailPage.tsx)

Features:

  • Back Navigation: Return to playlists list
  • Playlist Header: Title, channel, status chip
  • Download Button: Trigger downloads for incomplete playlists
  • Progress Indicator: Visual progress bar showing download status
  • Statistics Cards: Total tracks, downloaded count, last update
  • Tracks Table: Comprehensive list of all playlist items
  • Download Status Indicators: Visual chips for undownloaded tracks
  • Click to Play: Click anywhere on track row to play
  • Individual Play Buttons: Dedicated play buttons per track
  • Disabled State: Undownloaded tracks are visually dimmed and non-clickable
  • Responsive Design: Mobile-optimized with hidden columns on small screens
  • Loading States: Proper loading spinner during data fetch
  • Error Handling: User-friendly error messages

PWA UI Optimizations:

  • Touch-friendly hit targets (minimum 48px)
  • Smooth transitions and hover effects
  • Responsive table that adapts to screen size
  • Hidden columns on mobile to prevent crowding
  • Clear visual hierarchy with proper spacing
  • Accessible color contrast
  • Font sizes optimized for mobile (0.7rem - 0.875rem)

2. Updated PlaylistsPage (pages/PlaylistsPage.tsx)

<Card 
  onClick={() => window.location.href = `/playlists/${playlist.playlist_id}`}
  sx={{ 
    cursor: 'pointer',
    transition: 'transform 0.2s',
    '&:hover': {
      transform: 'translateY(-4px)',
    }
  }}
>

Changes:

  • Added onClick handler to navigate to detail page
  • Visual feedback on hover (card lifts up)
  • Proper cursor pointer indication
  • Maintains existing download and delete button functionality

3. Updated API Client (api/client.ts)

export const playlistAPI = {
  // ... existing methods
  getWithItems: (playlistId: string) => 
    api.get(`/playlist/${playlistId}/`, { params: { include_items: 'true' } }),
};

Features:

  • Separate method for fetching with items
  • Keeps payload light for list views (no items)
  • Explicit method name for clarity

4. Updated Routing (App.tsx)

<Route path="/playlists" element={<PlaylistsPage />} />
<Route path="/playlists/:playlistId" element={<PlaylistDetailPage setCurrentAudio={setCurrentAudio} />} />

Features:

  • RESTful URL structure
  • Dynamic playlist ID parameter
  • Proper integration with audio player

UI/UX Design

Playlist Detail Page Layout

┌─────────────────────────────────────────────────────────┐
│ ← Back    Hip-Hop                          ✓ Success  ⬇ │
│            By Music Channel                               │
├─────────────────────────────────────────────────────────┤
│ Download Progress              16 / 16 tracks            │
│ ████████████████████████████████ 100%                    │
├─────────────────────────────────────────────────────────┤
│ Total Tracks: 16   Downloaded: 16   Last Updated: Dec 15│
├─────────────────────────────────────────────────────────┤
│ #  │ Title               │ Channel      │ Duration │ ▶  │
├────┼────────────────────┼──────────────┼──────────┼────┤
│ 1  │ Track Name          │ Artist       │ 3:45     │ ▶  │
│ 2  │ Another Track       │ Artist 2     │ 4:20     │ ▶  │
│ 3  │ Third Song          │ Artist 3     │ 3:30     │ ▶  │
│    │ 🔴 Not Downloaded   │              │          │    │
└─────────────────────────────────────────────────────────┘

Mobile Responsiveness

  • Desktop: Full table with all columns
  • Tablet: Channel column hidden
  • Mobile: Only essential columns (# Title, Duration, Play)
  • Font Scaling: Smaller fonts on mobile for better fit
  • Touch Targets: All buttons are 48px+ for easy tapping

Security Analysis

Authentication & Authorization

User Authentication: All endpoints require authentication Owner Isolation: Users can only access their own playlists URL Parameter Validation: Django handles playlist_id validation Query Parameter Sanitization: Boolean conversion prevents injection

Data Exposure

Selective Loading: Items only loaded when requested No Sensitive Data: Only user-owned playlist data returned Proper Serialization: Django REST Framework handles escaping

SQL Injection Prevention

ORM Usage: All queries use Django ORM Parameterized Queries: No raw SQL with user input select_related: Proper join optimization

Cross-User Access Prevention

# Every query filters by owner
playlist = get_object_or_404(Playlist, playlist_id=playlist_id, owner=request.user)
items = PlaylistItem.objects.filter(playlist=playlist)  # Inherits owner check

Performance Optimizations

Backend

  1. Eager Loading: select_related('audio') prevents N+1 queries
  2. Conditional Loading: Items only fetched when include_items=true
  3. Indexed Queries: Database indexes on owner and playlist_id
  4. Ordered Fetching: Single query with ORDER BY instead of sorting in Python

Frontend

  1. Single API Call: All data fetched in one request
  2. Loading States: Prevents janky UI updates
  3. Conditional Rendering: Error/loading/success states handled
  4. Responsive Hiding: Columns hidden on mobile to reduce DOM size

User Workflows

Browsing a Playlist

  1. User navigates to /playlists
  2. Sees all subscribed playlists with progress indicators
  3. Clicks on "Hip-Hop" playlist card
  4. Page loads showing all 16 tracks
  5. User can:
    • See which tracks are downloaded (normal opacity)
    • See which tracks are pending (dimmed with "Not Downloaded" chip)
    • Click any downloaded track to play
    • Click download button to fetch remaining tracks
    • Click back to return to playlists list

Playing from Playlist

  1. User clicks on a downloaded track
  2. Track immediately starts playing in the main player
  3. Player shows on right side (desktop) or bottom (mobile)
  4. User can seek, pause, adjust volume, view lyrics (if available)
  5. User continues browsing playlist while audio plays

Testing Checklist

Functional Tests

  • Playlist list loads correctly
  • Clicking playlist navigates to detail page
  • Playlist detail shows all tracks
  • Downloaded tracks are playable
  • Not-downloaded tracks show indicator
  • Play button works for each track
  • Row click plays the track
  • Back button returns to playlist list
  • Download button triggers download task
  • Progress bar shows correct percentage
  • Statistics show correct counts

Security Tests

  • Cannot access other users' playlists
  • Authentication required for all endpoints
  • No SQL injection via playlist_id
  • No XSS via track titles
  • Proper 404 for invalid playlist IDs

Performance Tests

  • Large playlists (100+ tracks) load efficiently
  • No N+1 query issues
  • Reasonable response times (<500ms)
  • Mobile scrolling is smooth

Responsiveness Tests

  • Desktop view shows all columns
  • Tablet view hides channel column
  • Mobile view shows essential info only
  • Touch targets are 48px+ on mobile
  • Font sizes are readable on small screens

PWA Tests

  • Works offline after initial load
  • Installable as PWA
  • Touch interactions smooth
  • No layout shift on load
  • Proper scroll behavior

Files Modified

Backend

  • backend/playlist/views.py - Enhanced detail endpoint
  • backend/common/streaming.py - (from previous fix) Range request support

Frontend

  • frontend/src/pages/PlaylistDetailPage.tsx - NEW component
  • frontend/src/pages/PlaylistsPage.tsx - Added click handler
  • frontend/src/api/client.ts - Added getWithItems method
  • frontend/src/App.tsx - Added route and import

Route Conflicts Check

Current Routes

GET  /api/playlist/                      # List playlists
POST /api/playlist/                      # Create/subscribe
GET  /api/playlist/:playlist_id/         # Get single playlist
POST /api/playlist/:playlist_id/         # Trigger actions (download)
DELETE /api/playlist/:playlist_id/       # Delete playlist
GET  /api/playlist/downloads/            # Download management

No Conflicts: All routes are unique and properly ordered RESTful: Follows REST conventions No Ambiguity: downloads/ comes before :playlist_id/ in URL config

Deployment Notes

Build Required

docker compose build
docker compose up -d

No Migrations Needed

  • No database schema changes
  • Pure logic and UI updates

Backwards Compatible

  • Existing API endpoints unchanged
  • New query parameter is optional
  • Old clients continue to work

Future Enhancements

Potential Improvements

  1. Queue Management: Add all playlist tracks to play queue
  2. Shuffle Play: Shuffle and play random tracks from playlist
  3. Search Within Playlist: Filter tracks by title/artist
  4. Sort Options: Sort by title, duration, date added
  5. Batch Operations: Select multiple tracks for operations
  6. Download Priority: Set priority for specific tracks
  7. Playlist Sharing: Share playlists with other users
  8. Smart Playlists: Auto-generate based on criteria
  9. Playlist Statistics: Total duration, most played tracks
  10. Bulk Edit: Edit metadata for multiple tracks

Analytics Opportunities

  • Track which playlists are most viewed
  • Monitor playlist completion rates
  • Track most played tracks per playlist

Date

December 16, 2025

Status

IMPLEMENTED, TESTED, AND DEPLOYED


Summary: Users can now click on any playlist (like the "Hip-Hop" playlist shown in the screenshot) to view all available media tracks. The interface clearly shows which tracks are downloaded and playable, with smooth integration into the existing PWA player system. All security checks passed, no route conflicts detected, and the feature works seamlessly for both admin and managed users.