192 lines
3.8 KiB
Markdown
192 lines
3.8 KiB
Markdown
|
|
# Video Progress Tracking - API Usage Examples
|
||
|
|
|
||
|
|
## Save Video Progress
|
||
|
|
|
||
|
|
### POST `/students/lessons/:lessonId/progress`
|
||
|
|
|
||
|
|
**Purpose**: บันทึกตำแหน่งการดูวีดีโอ (เรียกทุก 5 วินาที)
|
||
|
|
|
||
|
|
#### Request:
|
||
|
|
```http
|
||
|
|
POST /api/students/lessons/5/progress
|
||
|
|
Authorization: Bearer <token>
|
||
|
|
Content-Type: application/json
|
||
|
|
|
||
|
|
{
|
||
|
|
"progress_seconds": 450,
|
||
|
|
"duration_seconds": 900
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Response 200:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"lesson_id": 5,
|
||
|
|
"video_progress_seconds": 450,
|
||
|
|
"video_duration_seconds": 900,
|
||
|
|
"video_progress_percentage": 50.00,
|
||
|
|
"is_completed": false,
|
||
|
|
"last_watched_at": "2024-12-24T14:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Auto-Complete (90%+):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"progress_seconds": 810,
|
||
|
|
"duration_seconds": 900
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"lesson_id": 5,
|
||
|
|
"video_progress_seconds": 810,
|
||
|
|
"video_duration_seconds": 900,
|
||
|
|
"video_progress_percentage": 90.00,
|
||
|
|
"is_completed": true,
|
||
|
|
"completed_at": "2024-12-24T14:05:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Get Video Progress
|
||
|
|
|
||
|
|
### GET `/students/lessons/:lessonId/progress`
|
||
|
|
|
||
|
|
**Purpose**: ดึงตำแหน่งการดูวีดีโอเพื่อเล่นต่อ
|
||
|
|
|
||
|
|
#### Request:
|
||
|
|
```http
|
||
|
|
GET /api/students/lessons/5/progress
|
||
|
|
Authorization: Bearer <token>
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Response 200 (Has Progress):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"lesson_id": 5,
|
||
|
|
"video_progress_seconds": 450,
|
||
|
|
"video_duration_seconds": 900,
|
||
|
|
"video_progress_percentage": 50.00,
|
||
|
|
"is_completed": false,
|
||
|
|
"last_watched_at": "2024-12-24T13:30:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Response 200 (No Progress):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"lesson_id": 5,
|
||
|
|
"video_progress_seconds": 0,
|
||
|
|
"video_duration_seconds": null,
|
||
|
|
"video_progress_percentage": 0,
|
||
|
|
"is_completed": false,
|
||
|
|
"last_watched_at": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Frontend Integration
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
const VideoPlayer = ({ lessonId, videoUrl }) => {
|
||
|
|
const videoRef = useRef(null);
|
||
|
|
|
||
|
|
// Load saved progress
|
||
|
|
useEffect(() => {
|
||
|
|
async function loadProgress() {
|
||
|
|
const res = await fetch(`/api/students/lessons/${lessonId}/progress`);
|
||
|
|
const data = await res.json();
|
||
|
|
|
||
|
|
if (data.video_progress_seconds > 0) {
|
||
|
|
videoRef.current.currentTime = data.video_progress_seconds;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
loadProgress();
|
||
|
|
}, [lessonId]);
|
||
|
|
|
||
|
|
// Save progress every 5 seconds
|
||
|
|
useEffect(() => {
|
||
|
|
const interval = setInterval(() => {
|
||
|
|
if (videoRef.current && !videoRef.current.paused) {
|
||
|
|
saveProgress(
|
||
|
|
Math.floor(videoRef.current.currentTime),
|
||
|
|
Math.floor(videoRef.current.duration)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}, 5000);
|
||
|
|
|
||
|
|
return () => clearInterval(interval);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
async function saveProgress(currentTime, duration) {
|
||
|
|
await fetch(`/api/students/lessons/${lessonId}/progress`, {
|
||
|
|
method: 'POST',
|
||
|
|
headers: {
|
||
|
|
'Authorization': `Bearer ${token}`,
|
||
|
|
'Content-Type': 'application/json'
|
||
|
|
},
|
||
|
|
body: JSON.stringify({
|
||
|
|
progress_seconds: currentTime,
|
||
|
|
duration_seconds: duration
|
||
|
|
})
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
return <video ref={videoRef} src={videoUrl} controls />;
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Modified Endpoints
|
||
|
|
|
||
|
|
### GET `/students/courses/:courseId/learn`
|
||
|
|
|
||
|
|
**Added**: `video_progress_percentage` และ `resume_from` ในแต่ละ lesson
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"lessons": [
|
||
|
|
{
|
||
|
|
"id": 1,
|
||
|
|
"title": "Lesson 1",
|
||
|
|
"type": "video",
|
||
|
|
"is_completed": true,
|
||
|
|
"video_progress_percentage": 100
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": 2,
|
||
|
|
"title": "Lesson 2",
|
||
|
|
"type": "video",
|
||
|
|
"is_completed": false,
|
||
|
|
"video_progress_percentage": 50,
|
||
|
|
"resume_from": 450
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### GET `/students/courses/:courseId/progress`
|
||
|
|
|
||
|
|
**Added**: `recently_watched` section
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"course_id": 1,
|
||
|
|
"progress_percentage": 30,
|
||
|
|
"recently_watched": [
|
||
|
|
{
|
||
|
|
"lesson_id": 2,
|
||
|
|
"title": "Lesson 2",
|
||
|
|
"video_progress_percentage": 50,
|
||
|
|
"last_watched_at": "2024-12-24T14:00:00Z"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|