# Enhanced Playlist System EasyStream now includes advanced playlist features with auto-play, shuffle, collaborative editing, and more. ## Features - 📼 **Auto-play** - Automatically play next video when current ends - 🔀 **Shuffle mode** - Random playback order - 🔁 **Repeat modes** - None, repeat all, repeat one - 👥 **Collaborative playlists** - Multiple users can add/manage videos - 👁️ **Privacy controls** - Public, unlisted, or private playlists - 📊 **Analytics** - Track playlist views and playback - ❤️ **Follow playlists** - Users can follow and get updates - 🎨 **Modern player UI** - Clean controls with visual feedback ## Setup ### 1. Database Migration Run the migration to create/enhance playlist tables: ```bash docker-compose exec db mysql -u easystream -peasystream easystream < __install/migrations/003_enhance_playlists.sql ``` This creates: - `db_playlists` - Playlist metadata - `db_playlist_items` - Videos in playlists - `db_playlist_collaborators` - Collaborative access control - `db_playlist_follows` - Playlist followers - `db_playlist_plays` - Playback analytics ### 2. Add Frontend Assets Include CSS and JavaScript in your templates: ```html ``` ### 3. Video Player Integration On your video watch page (`watch.php`), check for playlist parameter: ```php $playlist_id = $_GET['list'] ?? null; $video_id = $_GET['v']; // If playlist exists, the JavaScript will auto-initialize the player ``` The playlist player will automatically initialize if the URL contains `?v=VIDEO_ID&list=PLAYLIST_ID`. ## Usage ### Creating Playlists ```php require_once 'f_core/f_classes/class.playlists.php'; $playlists = new VPlaylists(); // Create a new playlist $playlist_id = $playlists->create( $usr_id, 'My Favorite Videos', 'A collection of my top picks', 'public', // 'public', 'unlisted', or 'private' false // is_collaborative ); // Create a collaborative playlist $playlist_id = $playlists->create( $usr_id, 'Team Project Videos', 'Videos for our project', 'unlisted', true // Enable collaboration ); ``` ### Managing Videos ```php // Add video to playlist $playlists->addVideo($playlist_id, $video_id, $usr_id); // Remove video $playlists->removeVideo($playlist_id, $video_id, $usr_id); // Reorder videos (auto-fix gaps) $playlists->reorderItems($playlist_id); // Manual reorder $positions = [ 101 => 1, // item_id 101 → position 1 102 => 2, // item_id 102 → position 2 103 => 3 ]; $playlists->reorderItems($playlist_id, $positions); ``` ### Collaboration ```php // Add collaborator with permissions $playlists->addCollaborator($playlist_id, $owner_id, $collaborator_id, [ 'can_add' => true, 'can_remove' => false, 'can_reorder' => false ]); // Remove collaborator $playlists->removeCollaborator($playlist_id, $owner_id, $collaborator_id); ``` ### Following Playlists ```php // Follow a playlist $playlists->follow($playlist_id, $usr_id); // Unfollow $playlists->unfollow($playlist_id, $usr_id); ``` ## API Endpoints ### Get Playlist ```http GET /api/playlists.php?id=123&shuffle=true ``` **Response:** ```json { "success": true, "data": { "playlist_id": 123, "title": "My Playlist", "description": "Great videos", "privacy": "public", "is_collaborative": true, "auto_play": true, "allow_shuffle": true, "video_count": 15, "view_count": 342, "is_following": true, "is_collaborator": false, "is_owner": false, "items": [...] } } ``` ### Create Playlist ```http POST /api/playlists.php Content-Type: application/json { "title": "New Playlist", "description": "My videos", "privacy": "public", "is_collaborative": false } ``` ### Update Playlist ```http PUT /api/playlists.php?id=123 Content-Type: application/json { "title": "Updated Title", "auto_play": true, "allow_shuffle": true } ``` ### Add Video ```http POST /api/playlists.php?id=123&action=add_video Content-Type: application/json { "video_id": 456 } ``` ### Remove Video ```http POST /api/playlists.php?id=123&action=remove_video Content-Type: application/json { "video_id": 456 } ``` ### Follow/Unfollow ```http POST /api/playlists.php?id=123&action=follow POST /api/playlists.php?id=123&action=unfollow ``` ### Add Collaborator ```http POST /api/playlists.php?id=123&action=add_collaborator Content-Type: application/json { "collaborator_id": 789, "permissions": { "can_add": true, "can_remove": false, "can_reorder": false } } ``` ## Frontend Player ### Initialization The player auto-initializes from URL parameters: ``` /watch?v=456&list=123 ``` Or initialize manually: ```javascript const player = new PlaylistPlayer(playlistId, { videoId: currentVideoId, autoPlay: true, shuffle: false, repeat: 'all', // 'none', 'one', 'all' playerElement: document.getElementById('video-player') }); ``` ### Player Controls - **Shuffle** - Randomize playback order - **Previous** - Go to previous video - **Next** - Go to next video - **Autoplay** - Toggle auto-play when video ends - **Repeat** - Cycle through: Off → All → One ### Player API ```javascript // Access the global player instance const player = window.playlistPlayer; // Playback control player.playNext(); player.playPrevious(); player.playByIndex(5); player.playVideo(videoId); // Settings player.toggleShuffle(); player.toggleAutoplay(); player.cycleRepeat(); // Playlist management player.removeVideo(videoId); player.loadPlaylist(); // Reload from server ``` ## Collaborative Playlists Collaborative playlists allow multiple users to contribute. **Owner permissions:** - Create/delete playlist - Add/remove/reorder videos - Manage collaborators - Change privacy settings **Collaborator permissions (configurable):** - `can_add` - Add videos to playlist - `can_remove` - Remove videos from playlist - `can_reorder` - Change video order **Example workflow:** 1. Owner creates collaborative playlist 2. Owner adds collaborators with specific permissions 3. Collaborators can add videos (if permitted) 4. All changes tracked with `added_by` field ## Privacy Modes | Mode | Visibility | Shareable | Use Case | |------|-----------|-----------|----------| | **public** | Everyone can see and search | Yes | Public collections, curated lists | | **unlisted** | Only with direct link | Yes | Share with specific people | | **private** | Only owner + collaborators | No | Personal collections | ## Database Schema ### db_playlists | Column | Type | Description | |--------|------|-------------| | playlist_id | INT | Primary key | | usr_id | INT | Owner user ID | | title | VARCHAR(255) | Playlist title | | description | TEXT | Optional description | | privacy | ENUM | public/unlisted/private | | thumbnail | VARCHAR(512) | Custom thumbnail URL | | is_collaborative | TINYINT | Collaboration enabled | | allow_shuffle | TINYINT | Shuffle allowed | | auto_play | TINYINT | Auto-play enabled | | video_count | INT | Cached video count | | view_count | INT | Total playlist views | ### db_playlist_items | Column | Type | Description | |--------|------|-------------| | item_id | INT | Primary key | | playlist_id | INT | Playlist ID | | video_id | INT | Video ID | | position | INT | Order in playlist | | added_by | INT | User who added video | | added_at | DATETIME | When added | ### db_playlist_collaborators | Column | Type | Description | |--------|------|-------------| | collaborator_id | INT | Primary key | | playlist_id | INT | Playlist ID | | usr_id | INT | Collaborator user ID | | can_add | TINYINT | Can add videos | | can_remove | TINYINT | Can remove videos | | can_reorder | TINYINT | Can reorder videos | ## Analytics Track playlist playback for insights: ```php // Track a play $playlists->trackPlay($playlist_id, $video_id, $usr_id); // Get play history $sql = "SELECT * FROM db_playlist_plays WHERE playlist_id = ? ORDER BY played_at DESC LIMIT 100"; ``` **Available metrics:** - Total playlist views - Video completion rates - Popular videos within playlist - User engagement patterns ## Integration Points ### Add "Save to Playlist" Button On video pages, add a quick-save button: ```html ``` ### Playlist Notifications Notify followers when a collaborative playlist is updated: ```php // After adding video to collaborative playlist if ($playlist['is_collaborative']) { $triggers = new VNotificationTriggers(); // Get followers $followers = $playlists->getFollowers($playlist_id); foreach ($followers as $follower) { $triggers->notifySystem( $follower['usr_id'], "New video added to {$playlist['title']}", $video_title, "/playlist?id=$playlist_id" ); } } ``` ## Performance - **Pagination:** Load videos in batches for large playlists - **Caching:** Cache playlist metadata with Redis - **Lazy loading:** Load thumbnails on scroll - **Position indexing:** Fast reordering with indexed position column ## Future Enhancements - [ ] Playlist recommendations based on viewing history - [ ] Batch add videos (from search/channel) - [ ] Playlist templates (create from another playlist) - [ ] Smart playlists (auto-add based on criteria) - [ ] Playlist comments/discussions - [ ] Export/import playlists (JSON/M3U) - [ ] Playlist thumbnail generation (grid of video thumbs) - [ ] Drag-and-drop reordering in UI - [ ] Playlist merging - [ ] View mode (grid vs list) ## Troubleshooting ### Videos not playing in sequence 1. Check `auto_play` is enabled in playlist settings 2. Verify video player has `ended` event listener 3. Check browser console for JavaScript errors ### Collaborator can't add videos 1. Verify playlist has `is_collaborative = 1` 2. Check collaborator has `can_add = 1` permission 3. Ensure user is authenticated ### Shuffle not working 1. Check playlist has `allow_shuffle = 1` 2. Verify JavaScript is loaded 3. Check for shuffle button active state ## Learn More - [YouTube Playlists Documentation](https://support.google.com/youtube/answer/57792) - [HTML5 Video Events](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#events) - [Fisher-Yates Shuffle Algorithm](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)