Files
Krystie 9928a23c25 feat: Add enhanced playlist system with auto-play, shuffle, and collaboration
- 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
2026-03-30 17:16:37 -07:00

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 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:

<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 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:

// 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

  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