diff --git a/apps/course/views/webhook.py b/apps/course/views/webhook.py index 699ee13..51b85aa 100644 --- a/apps/course/views/webhook.py +++ b/apps/course/views/webhook.py @@ -93,7 +93,7 @@ class PlugNMeetWebhookAPIView(APIView): 'room_finished': self._handle_room_finished, 'participant_joined': self._handle_participant_joined, 'participant_left': self._handle_participant_left, - 'end_recording': self._handle_end_recording, + 'RECORDING_PROCEEDED': self._handle_recording_proceeded, } handler = handler_map.get(event) @@ -252,17 +252,41 @@ class PlugNMeetWebhookAPIView(APIView): except Exception as e: return {'error': str(e)} - def _handle_end_recording(self, payload: Dict[str, Any]) -> Dict[str, Any]: + def _get_video_duration(self, video_path: str) -> timezone.timedelta: + """Get video duration using ffprobe, return as timedelta.""" + try: + cmd = [ + 'ffprobe', + '-v', 'error', + '-show_entries', 'format=duration', + '-of', 'default=noprint_wrappers=1:nokey=1', + video_path + ] + result = subprocess.run( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + timeout=30 + ) + if result.returncode == 0: + duration_seconds = float(result.stdout.decode().strip()) + return timezone.timedelta(seconds=duration_seconds) + except Exception as e: + logger.warning(f"⚠️ [PlugNMeet Webhook] Duration extraction failed: {e}") + return timezone.timedelta(seconds=0) + + def _handle_recording_proceeded(self, payload: Dict[str, Any]) -> Dict[str, Any]: room_data = payload.get('room', {}) recording_info = payload.get('recording_info', {}) room_id = room_data.get('identity') - recording_id = recording_info.get('recordingId') - file_name = recording_info.get('fileName', 'recording.mp4') - duration = recording_info.get('duration', 0) + recording_id = recording_info.get('recordId') or recording_info.get('recordingId') + file_path = recording_info.get('filePath') if not room_id or not recording_id: return {'message': 'Missing recording metadata'} + + file_name = os.path.basename(file_path) if file_path else f"{recording_id}.mp4" try: session = CourseLiveSession.objects.get(room_id=room_id) @@ -284,19 +308,22 @@ class PlugNMeetWebhookAPIView(APIView): logger.info(f"📥 [PlugNMeet Webhook] Downloading recording {recording_id}...") client.download_file(download_path, tmp_file_path) - # 3. Save to Database + # 3. Read duration using ffprobe + duration = self._get_video_duration(tmp_file_path) + + # 4. Save to Database with open(tmp_file_path, 'rb') as f: content = f.read() recording = LiveSessionRecording.objects.create( session=session, title=f"{session.subject} - Recording", - file_time=timezone.timedelta(seconds=duration) if duration > 0 else None, + file_time=duration if duration.total_seconds() > 0 else None, recording_type='video' if file_name.lower().endswith('.mp4') else 'voice' ) recording.file.save(file_name, ContentFile(content), save=True) - # 4. Generate thumbnail (Optional) + # 5. Generate thumbnail (Optional) self._generate_video_thumbnail(tmp_file_path, recording) logger.info(f"💾 [PlugNMeet Webhook] Recording saved successfully: {recording.id}") @@ -307,7 +334,7 @@ class PlugNMeetWebhookAPIView(APIView): os.unlink(tmp_file_path) except Exception as e: - logger.error(f"❌ [PlugNMeet Webhook] End Recording Error: {e}", exc_info=True) + logger.error(f"❌ [PlugNMeet Webhook] RECORDING_PROCEEDED Error: {e}", exc_info=True) return {'error': str(e)} def _generate_video_thumbnail(self, video_path: str, recording: LiveSessionRecording) -> bool: