- Create comprehensive playlist management system - Implement auto-play, shuffle, and repeat modes (none/one/all) - Add collaborative playlists with granular permissions - Build playlist follow system for users - Implement playlist analytics and play tracking - Create modern playlist player UI with controls - Add privacy modes (public/unlisted/private) - Document complete API and usage Features: - Auto-play next video when current ends - Shuffle mode for random playback - Repeat modes (off, one, all) - Collaborative editing with permissions - Follow/unfollow playlists - Playlist view tracking - Modern player controls UI - Complete permission system - Production-ready with error handling
11 KiB
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:
docker-compose exec db mysql -u easystream -peasystream easystream < __install/migrations/003_enhance_playlists.sql
This creates:
db_playlists- Playlist metadatadb_playlist_items- Videos in playlistsdb_playlist_collaborators- Collaborative access controldb_playlist_follows- Playlist followersdb_playlist_plays- Playback analytics
2. Add Frontend Assets
Include CSS and JavaScript in your templates:
<link rel="stylesheet" href="/f_scripts/fe/css/playlists.css">
<script src="/f_scripts/fe/js/playlist-player.js"></script>
3. Video Player Integration
On your video watch page (watch.php), check for playlist parameter:
$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
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
// 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
// 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
// Follow a playlist
$playlists->follow($playlist_id, $usr_id);
// Unfollow
$playlists->unfollow($playlist_id, $usr_id);
API Endpoints
Get Playlist
GET /api/playlists.php?id=123&shuffle=true
Response:
{
"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
POST /api/playlists.php
Content-Type: application/json
{
"title": "New Playlist",
"description": "My videos",
"privacy": "public",
"is_collaborative": false
}
Update Playlist
PUT /api/playlists.php?id=123
Content-Type: application/json
{
"title": "Updated Title",
"auto_play": true,
"allow_shuffle": true
}
Add Video
POST /api/playlists.php?id=123&action=add_video
Content-Type: application/json
{
"video_id": 456
}
Remove Video
POST /api/playlists.php?id=123&action=remove_video
Content-Type: application/json
{
"video_id": 456
}
Follow/Unfollow
POST /api/playlists.php?id=123&action=follow
POST /api/playlists.php?id=123&action=unfollow
Add Collaborator
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:
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
// 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 playlistcan_remove- Remove videos from playlistcan_reorder- Change video order
Example workflow:
- Owner creates collaborative playlist
- Owner adds collaborators with specific permissions
- Collaborators can add videos (if permitted)
- All changes tracked with
added_byfield
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:
// 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:
<button onclick="addToPlaylist(<?php echo $video_id; ?>)">
Save to Playlist
</button>
<script>
async function addToPlaylist(videoId) {
// Show playlist selector modal
const playlistId = await showPlaylistSelector();
// Add video
await fetch(`/api/playlists.php?id=${playlistId}&action=add_video`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ video_id: videoId })
});
}
</script>
Playlist Notifications
Notify followers when a collaborative playlist is updated:
// 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
- Check
auto_playis enabled in playlist settings - Verify video player has
endedevent listener - Check browser console for JavaScript errors
Collaborator can't add videos
- Verify playlist has
is_collaborative = 1 - Check collaborator has
can_add = 1permission - Ensure user is authenticated
Shuffle not working
- Check playlist has
allow_shuffle = 1 - Verify JavaScript is loaded
- Check for shuffle button active state