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

250 lines
8.7 KiB
PHP

<?php
/**
* Playlists API
*
* GET /api/playlists.php?id=X - Get playlist details
* GET /api/playlists.php?user_id=X - Get user's playlists
* POST /api/playlists.php - Create playlist
* PUT /api/playlists.php?id=X - Update playlist
* DELETE /api/playlists.php?id=X - Delete playlist
*
* POST /api/playlists.php?id=X&action=add_video - Add video to playlist
* POST /api/playlists.php?id=X&action=remove_video - Remove video from playlist
* POST /api/playlists.php?id=X&action=reorder - Reorder videos
* POST /api/playlists.php?id=X&action=follow - Follow playlist
* POST /api/playlists.php?id=X&action=unfollow - Unfollow playlist
* POST /api/playlists.php?id=X&action=add_collaborator - Add collaborator
* POST /api/playlists.php?id=X&action=remove_collaborator - Remove collaborator
*/
require_once dirname(__DIR__) . '/f_core/config.boot.php';
require_once dirname(__DIR__) . '/f_core/f_classes/class.playlists.php';
header('Content-Type: application/json');
session_start();
$current_user_id = $_SESSION['user_id'] ?? null;
$playlists = new VPlaylists();
$method = $_SERVER['REQUEST_METHOD'];
// GET - Retrieve playlist(s)
if ($method === 'GET') {
if (isset($_GET['id'])) {
// Get single playlist
$playlist = $playlists->get($_GET['id'], $current_user_id);
if (!$playlist) {
http_response_code(404);
echo json_encode(['success' => false, 'error' => 'Playlist not found']);
exit;
}
// Get items
$shuffle = isset($_GET['shuffle']) && $_GET['shuffle'] === 'true';
$items = $playlists->getItems($_GET['id'], $shuffle);
$playlist['items'] = $items;
echo json_encode(['success' => true, 'data' => $playlist]);
} elseif (isset($_GET['user_id'])) {
// Get user's playlists
$include_private = $current_user_id && $current_user_id == $_GET['user_id'];
$user_playlists = $playlists->getUserPlaylists($_GET['user_id'], $include_private);
echo json_encode(['success' => true, 'data' => $user_playlists]);
} else {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Missing playlist or user ID']);
}
}
// POST - Create or perform actions
elseif ($method === 'POST') {
if (!$current_user_id) {
http_response_code(401);
echo json_encode(['success' => false, 'error' => 'Authentication required']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
$action = $_GET['action'] ?? $input['action'] ?? 'create';
if ($action === 'create') {
// Create new playlist
$title = $input['title'] ?? '';
$description = $input['description'] ?? '';
$privacy = $input['privacy'] ?? 'public';
$is_collaborative = isset($input['is_collaborative']) && $input['is_collaborative'];
if (empty($title)) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Title is required']);
exit;
}
$playlist_id = $playlists->create($current_user_id, $title, $description, $privacy, $is_collaborative);
if ($playlist_id) {
echo json_encode(['success' => true, 'playlist_id' => $playlist_id]);
} else {
http_response_code(500);
echo json_encode(['success' => false, 'error' => 'Failed to create playlist']);
}
} elseif ($action === 'add_video') {
$playlist_id = $_GET['id'] ?? $input['playlist_id'];
$video_id = $input['video_id'] ?? null;
if (!$playlist_id || !$video_id) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Playlist ID and video ID required']);
exit;
}
$result = $playlists->addVideo($playlist_id, $video_id, $current_user_id);
echo json_encode(['success' => (bool)$result]);
} elseif ($action === 'remove_video') {
$playlist_id = $_GET['id'] ?? $input['playlist_id'];
$video_id = $input['video_id'] ?? null;
if (!$playlist_id || !$video_id) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Playlist ID and video ID required']);
exit;
}
$result = $playlists->removeVideo($playlist_id, $video_id, $current_user_id);
echo json_encode(['success' => (bool)$result]);
} elseif ($action === 'reorder') {
$playlist_id = $_GET['id'] ?? $input['playlist_id'];
$item_positions = $input['positions'] ?? null;
if (!$playlist_id) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Playlist ID required']);
exit;
}
$result = $playlists->reorderItems($playlist_id, $item_positions);
echo json_encode(['success' => (bool)$result]);
} elseif ($action === 'follow') {
$playlist_id = $_GET['id'] ?? $input['playlist_id'];
if (!$playlist_id) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Playlist ID required']);
exit;
}
$result = $playlists->follow($playlist_id, $current_user_id);
echo json_encode(['success' => (bool)$result]);
} elseif ($action === 'unfollow') {
$playlist_id = $_GET['id'] ?? $input['playlist_id'];
if (!$playlist_id) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Playlist ID required']);
exit;
}
$result = $playlists->unfollow($playlist_id, $current_user_id);
echo json_encode(['success' => (bool)$result]);
} elseif ($action === 'add_collaborator') {
$playlist_id = $_GET['id'] ?? $input['playlist_id'];
$collaborator_id = $input['collaborator_id'] ?? null;
$permissions = $input['permissions'] ?? [];
if (!$playlist_id || !$collaborator_id) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Playlist ID and collaborator ID required']);
exit;
}
$result = $playlists->addCollaborator($playlist_id, $current_user_id, $collaborator_id, $permissions);
echo json_encode(['success' => (bool)$result]);
} elseif ($action === 'remove_collaborator') {
$playlist_id = $_GET['id'] ?? $input['playlist_id'];
$collaborator_id = $input['collaborator_id'] ?? null;
if (!$playlist_id || !$collaborator_id) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Playlist ID and collaborator ID required']);
exit;
}
$result = $playlists->removeCollaborator($playlist_id, $current_user_id, $collaborator_id);
echo json_encode(['success' => (bool)$result]);
} else {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Invalid action']);
}
}
// PUT - Update playlist
elseif ($method === 'PUT') {
if (!$current_user_id) {
http_response_code(401);
echo json_encode(['success' => false, 'error' => 'Authentication required']);
exit;
}
$playlist_id = $_GET['id'] ?? null;
if (!$playlist_id) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Playlist ID required']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
$result = $playlists->update($playlist_id, $current_user_id, $input);
if ($result) {
echo json_encode(['success' => true]);
} else {
http_response_code(403);
echo json_encode(['success' => false, 'error' => 'Permission denied or invalid data']);
}
}
// DELETE - Delete playlist
elseif ($method === 'DELETE') {
if (!$current_user_id) {
http_response_code(401);
echo json_encode(['success' => false, 'error' => 'Authentication required']);
exit;
}
$playlist_id = $_GET['id'] ?? null;
if (!$playlist_id) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Playlist ID required']);
exit;
}
$result = $playlists->delete($playlist_id, $current_user_id);
if ($result) {
echo json_encode(['success' => true]);
} else {
http_response_code(403);
echo json_encode(['success' => false, 'error' => 'Permission denied']);
}
}
else {
http_response_code(405);
echo json_encode(['success' => false, 'error' => 'Method not allowed']);
}