From 05cc94be448886633d7d74a8458e1e4fe620e3cb Mon Sep 17 00:00:00 2001 From: Palwisha Akhtar Date: Wed, 5 Feb 2025 12:58:05 -0700 Subject: [PATCH 1/3] Override VideoAsset save method to include fize size and duration --- Dockerfile | 1 + docker-compose.yml | 2 +- events/forms.py | 3 +-- ...set_duration_alter_videoasset_file_size.py | 23 +++++++++++++++++++ events/models.py | 23 +++++++++++++++++-- requirements/base.txt | 1 + 6 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 events/migrations/0003_alter_videoasset_duration_alter_videoasset_file_size.py diff --git a/Dockerfile b/Dockerfile index 3c1b87f..9ef764b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,7 @@ FROM python:3.12-slim RUN apt-get update && apt-get install -y \ build-essential \ libpq-dev \ + ffmpeg \ && rm -rf /var/lib/apt/lists/* ENV PYTHONUNBUFFERED 1 diff --git a/docker-compose.yml b/docker-compose.yml index e4cb008..97e9d0c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,7 +28,7 @@ services: command: bash -c "python manage.py runserver 0.0.0.0:${DJANGO_PORT}" volumes: - .:/app - - ./media:/app/media + - ./media:/app/arbisoft_sessions_portal/media ports: - "${DJANGO_PORT}:${DJANGO_PORT}" depends_on: diff --git a/events/forms.py b/events/forms.py index 3b7977e..95e5e70 100644 --- a/events/forms.py +++ b/events/forms.py @@ -1,5 +1,4 @@ from django import forms - from events.models import VideoAsset @@ -12,7 +11,7 @@ class VideoAssetForm(forms.ModelForm): class Meta: model = VideoAsset - fields = ('title', 'video_file', 'duration', 'thumbnail', 'file_size') + fields = ('title', 'video_file', 'thumbnail') def clean(self): """ Infer, save and clean the data related to videoasset """ diff --git a/events/migrations/0003_alter_videoasset_duration_alter_videoasset_file_size.py b/events/migrations/0003_alter_videoasset_duration_alter_videoasset_file_size.py new file mode 100644 index 0000000..c7624f8 --- /dev/null +++ b/events/migrations/0003_alter_videoasset_duration_alter_videoasset_file_size.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.16 on 2025-02-05 15:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0002_remove_videoasset_cdn_url_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='videoasset', + name='duration', + field=models.IntegerField(default=0), + ), + migrations.AlterField( + model_name='videoasset', + name='file_size', + field=models.BigIntegerField(default=0), + ), + ] diff --git a/events/models.py b/events/models.py index 3b488a6..f1bac7d 100644 --- a/events/models.py +++ b/events/models.py @@ -1,3 +1,5 @@ +import ffmpeg + from django.conf import settings from django.contrib.auth import get_user_model from django.core.files.storage import FileSystemStorage @@ -65,12 +67,29 @@ class VideoStatus(models.TextChoices): event = models.ForeignKey(Event, on_delete=models.DO_NOTHING, related_name='videos') title = models.CharField(max_length=255) video_file = models.FileField(storage=video_storage, null=True, blank=True) - duration = models.IntegerField() # in seconds + duration = models.IntegerField(default=0) # in seconds thumbnail = models.ImageField(storage=thumbnail_storage, null=True, blank=True) status = models.CharField(max_length=20, choices=VideoStatus.choices) - file_size = models.BigIntegerField() # in bytes + file_size = models.BigIntegerField(default=0) # in bytes created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) + def save(self, *args, **kwargs): + """ Override save method to extract file size and duration """ + if self.video_file: + super().save(*args, **kwargs) + + self.file_size = self.video_file.size + video_path = self.video_file.path + try: + metadata = ffmpeg.probe(video_path) + duration = float(metadata['format']['duration']) + self.duration = int(duration) # Convert to seconds + except Exception as e: + print(f"FFmpeg error: {e}") + + + super().save(*args, **kwargs) + def __str__(self): return self.title diff --git a/requirements/base.txt b/requirements/base.txt index 312a9ee..6df7955 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -7,6 +7,7 @@ django-filter==24.3 djangorestframework==3.15.2 djangorestframework-simplejwt==5.3.1 drf-spectacular==0.28.0 +ffmpeg-python==0.2.0 idna==3.10 Markdown==3.7 pillow==11.1.0 From 2262884de48ec89c6dd4080085b1026b084aa660 Mon Sep 17 00:00:00 2001 From: Palwisha Akhtar Date: Wed, 5 Feb 2025 13:51:32 -0700 Subject: [PATCH 2/3] add specfic exception for ffmpeg --- events/models.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/events/models.py b/events/models.py index f1bac7d..b589795 100644 --- a/events/models.py +++ b/events/models.py @@ -82,12 +82,16 @@ def save(self, *args, **kwargs): self.file_size = self.video_file.size video_path = self.video_file.path try: + video_path = '/app/xyz.mp4' metadata = ffmpeg.probe(video_path) duration = float(metadata['format']['duration']) self.duration = int(duration) # Convert to seconds - except Exception as e: - print(f"FFmpeg error: {e}") - + except ffmpeg._run.Error as e: + print(f"FFmpeg processing error: {e.stderr.decode() if hasattr(e, 'stderr') else e}") + except KeyError: + print("Metadata does not contain 'duration'. Invalid file format.") + except ValueError: + print("Invalid duration value, unable to convert to float.") super().save(*args, **kwargs) From 37c5d4cb382231de6e7d13f8448b3ea109835f1e Mon Sep 17 00:00:00 2001 From: Palwisha Akhtar Date: Wed, 5 Feb 2025 14:00:32 -0700 Subject: [PATCH 3/3] Fix lint issues --- events/forms.py | 1 + events/models.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/events/forms.py b/events/forms.py index 95e5e70..6916bb5 100644 --- a/events/forms.py +++ b/events/forms.py @@ -1,4 +1,5 @@ from django import forms + from events.models import VideoAsset diff --git a/events/models.py b/events/models.py index b589795..dadefaf 100644 --- a/events/models.py +++ b/events/models.py @@ -82,11 +82,10 @@ def save(self, *args, **kwargs): self.file_size = self.video_file.size video_path = self.video_file.path try: - video_path = '/app/xyz.mp4' metadata = ffmpeg.probe(video_path) duration = float(metadata['format']['duration']) self.duration = int(duration) # Convert to seconds - except ffmpeg._run.Error as e: + except ffmpeg.Error as e: print(f"FFmpeg processing error: {e.stderr.decode() if hasattr(e, 'stderr') else e}") except KeyError: print("Metadata does not contain 'duration'. Invalid file format.")