# Phase 7: Bunny.net Video Integration

## Architecture
We designed an isolated abstract `BunnyVideoService` capable of communicating securely via Token Authentication. Instead of bloating our local server storage parsing multi-gigabyte video formats, we maintain a pure API layer where Laravel brokers connections to the Bunny Stream edge network.

## Secure Player Delivery (DRM)
The core endpoint `generateSignedUrl($videoId, $expiresInSeconds)` explicitly guards video playlists against generic hotlinking and external scraping.

**Mechanism**:
1. It retrieves the base `Pull Zone` and `Token Key` config.
2. Formats a static UNIX expiration window.
3. Generates an HMAC-SHA256 `HS256-` token with `token_path=/{video_id}/` so the HLS playlist and its segment files share the same short-lived directory grant.
4. Returns the dynamically active path-based `playlist.m3u8` stream.

## Administrative Video Injection
The `Admin\VideoController@store` implements the first-phase `createVideo()` logic communicating via REST using the native `Http::withHeaders()` facade. This guarantees that internal metadata matches exact instances in the CDN library before we issue the direct-to-S3/TUS frontend upload logic. By offloading video upload streams to direct JS bridges, we save WAMP/PHP from failing under massive payload bottlenecks.

Admins can also attach already-uploaded Bunny Stream videos directly inside the course builder. Each lecture form accepts either:

- a raw Bunny Stream video GUID
- a Bunny iframe/embed URL
- a Bunny playlist URL ending in `playlist.m3u8`

Laravel normalizes that input into `lessons.bunny_video_id`. Student playback never uses the admin-entered URL directly; the lesson controller calls `BunnyVideoService::generateSignedUrl()` for enrolled users only.

For Bunny's embedded player, the lesson controller signs the iframe URL with `BunnyVideoService::generateSignedEmbedUrl()` and uses `BUNNY_EMBED_TOKEN_TTL` for the expiry window. Keep this short, normally `300` seconds, because any iframe URL visible in the browser can be copied until its token expires.

## Student Watch Analytics
The protected player posts progress back to `student.lesson.progress` while the video plays, pauses, ends, or starts a new session. The `lesson_progress` table now tracks:

- `watched_seconds` for the furthest watched point
- `last_position_seconds` for resume playback
- `watch_count` for repeat viewing sessions
- `last_watched_at` and `completed_at`

The student dashboard uses these fields to show which lectures were watched, partial watch duration, repeat sessions, and the latest watch time.
   
## Operational Notes
For real anti-download protection, Bunny Stream token authentication must be enabled on the Stream pull zone and direct public file access should stay disabled in Bunny. Bunny's current CDN docs recommend path-based directory tokens for HLS/DASH delivery so segment requests inherit authorization from the manifest URL. For embed playback, set allowed domains in Bunny and keep `BUNNY_EMBED_TOKEN_TTL` short; a copied signed iframe URL cannot be made secret once it is delivered to the browser, so expiry is the enforceable limit.
