courses + continue-watching // GET api/library.php?view=folder&id=N -> folder contents + progress // GET api/library.php?view=video&id=N -> video + playlist + resume info require_once __DIR__ . '/../includes/auth.php'; require_once __DIR__ . '/../includes/functions.php'; header('Content-Type: application/json'); $userId = requireLoginApi(); function folderSummary(array $f, int $userId): array { return [ 'id' => (int)$f['id'], 'name' => $f['name'], 'progress' => folderProgress($userId, $f['path']), ]; } function videoSummary(array $v): array { $duration = $v['duration_seconds'] ?? $v['watched_duration'] ?? null; $position = (float)($v['position_seconds'] ?? 0); return [ 'id' => (int)$v['id'], 'name' => $v['name'], 'filename' => $v['filename'], 'duration' => $duration !== null ? (float)$duration : null, 'position' => $position, 'completed' => (bool)($v['completed'] ?? false), 'percent' => ($duration ?? 0) > 0 ? min(100, (int)round(100 * $position / $duration)) : 0, ]; } function quizSummary(array $q): array { return [ 'id' => (int)$q['id'], 'name' => $q['name'], 'filename' => $q['filename'], 'questions' => (int)$q['num_questions'], 'attempts' => (int)($q['attempts'] ?? 0), 'best_score' => (int)($q['best_score'] ?? 0), 'completed' => (bool)($q['completed'] ?? false), ]; } function crumbList(array $folder): array { return array_map( fn($c) => ['id' => (int)$c['id'], 'name' => $c['name']], folderBreadcrumbs($folder) ); } $view = $_GET['view'] ?? 'home'; switch ($view) { case 'home': echo json_encode([ 'courses' => array_map(fn($c) => folderSummary($c, $userId), childFolders(null)), 'continue' => array_map(fn($r) => [ 'id' => (int)$r['id'], 'name' => $r['name'], 'folder_path' => $r['folder_path'], 'position' => (float)$r['position_seconds'], 'duration' => $r['duration_seconds'] !== null ? (float)$r['duration_seconds'] : null, ], continueWatching($userId)), ]); break; case 'folder': $folder = getFolder((int)($_GET['id'] ?? 0)); if (!$folder) { http_response_code(404); echo json_encode(['error' => 'Folder not found']); break; } echo json_encode([ 'folder' => ['id' => (int)$folder['id'], 'name' => $folder['name']], 'breadcrumbs' => crumbList($folder), 'progress' => folderProgress($userId, $folder['path']), 'subfolders' => array_map(fn($f) => folderSummary($f, $userId), childFolders((int)$folder['id'])), 'videos' => array_map('videoSummary', folderVideos((int)$folder['id'], $userId)), 'quizzes' => array_map('quizSummary', folderQuizzes((int)$folder['id'], $userId)), ]); break; case 'video': $video = getVideo((int)($_GET['id'] ?? 0)); if (!$video) { http_response_code(404); echo json_encode(['error' => 'Video not found']); break; } $folder = getFolder((int)$video['folder_id']); $playlist = folderVideos((int)$folder['id'], $userId); $stmt = db()->prepare( 'SELECT position_seconds, completed FROM video_progress WHERE user_id = ? AND video_id = ?' ); $stmt->execute([$userId, (int)$video['id']]); $saved = $stmt->fetch() ?: null; $resumeAt = ($saved && !$saved['completed'] && $saved['position_seconds'] > 5) ? (float)$saved['position_seconds'] : 0; $prevId = $nextId = null; foreach ($playlist as $i => $p) { if ((int)$p['id'] === (int)$video['id']) { $prevId = isset($playlist[$i - 1]) ? (int)$playlist[$i - 1]['id'] : null; $nextId = isset($playlist[$i + 1]) ? (int)$playlist[$i + 1]['id'] : null; break; } } echo json_encode([ 'video' => ['id' => (int)$video['id'], 'name' => $video['name']], 'folder' => ['id' => (int)$folder['id'], 'name' => $folder['name']], 'breadcrumbs' => crumbList($folder), 'playlist' => array_map('videoSummary', $playlist), 'resume_at' => $resumeAt, 'prev_id' => $prevId, 'next_id' => $nextId, 'stream_url' => 'stream.php?id=' . (int)$video['id'], ]); break; default: http_response_code(400); echo json_encode(['error' => 'Unknown view']); }