added task queue (django rq) & removes all files when the model is deleted

This commit is contained in:
Chneemann 2024-08-12 18:43:29 +02:00
parent 3564fcc360
commit 9e976e06fd
6 changed files with 90 additions and 24 deletions

View file

@ -1,4 +1,18 @@
asgiref==3.8.1
click==8.1.7
Django==5.0.7
django-cors-headers==4.4.0
django-debug-toolbar==4.4.6
django-redis==5.4.0
django-rq==2.10.2
djangorestframework==3.15.2
ffmpeg-python==0.2.0
future==1.0.0
imageio-ffmpeg==0.5.1
numpy==2.0.1
pillow==10.4.0
psutil==6.0.0
redis==5.0.8
rq==1.16.2
setuptools==72.1.0
sqlparse==0.5.1

View file

@ -6,8 +6,8 @@ class Video(models.Model):
title = models.CharField(max_length=80)
description = models.CharField(max_length=500)
film_genre = models.CharField(max_length=50, blank=True, null=True)
video_file = models.FileField(upload_to='videos', blank=True, null=True)
thumbnail = models.FileField(upload_to='img', null=True, blank=True)
video_file = models.FileField(upload_to='videos/', blank=True, null=True)
thumbnail = models.ImageField(upload_to='thumbnails/', blank=True, null=True)
def __str__(self):
return self.title

View file

@ -1,8 +1,10 @@
from .models import Video
from content.tasks import convert_video, create_thumbnail
from content.tasks import convert_video, create_thumbnails
from django.dispatch import receiver
from django.db.models.signals import post_save, post_delete
from django.conf import settings
import os
import django_rq
@receiver(post_save, sender=Video)
def video_post_save(sender, instance, created, **kwargs):
@ -10,20 +12,58 @@ def video_post_save(sender, instance, created, **kwargs):
Generates a thumbnail for a newly created `Video` instance.
"""
if created:
queue = django_rq.get_queue("default", autocommit=True)
#Convert Video
convert_video(instance.video_file.path, "480")
convert_video(instance.video_file.path, "720")
convert_video(instance.video_file.path, "1080")
queue.enqueue(convert_video, instance.video_file.path, "480")
queue.enqueue(convert_video, instance.video_file.path, "720")
queue.enqueue(convert_video, instance.video_file.path, "1080")
#Create Thumbnail
create_thumbnail(instance)
queue.enqueue(create_thumbnails, instance)
@receiver(post_delete, sender=Video)
def auto_delete_file_on_delete(sender, instance, **kwargs):
"""
Deletes file from filesystem
Deletes video file and its converted files from filesystem
when corresponding `Video` object is deleted.
"""
# Delete the original video file
if instance.video_file:
if os.path.isfile(instance.video_file.path):
os.remove(instance.video_file.path)
os.remove(instance.video_file.path)
# Delete the converted videos
if instance.video_file:
delete_converted_files(instance.video_file.path)
# Delete the thumbnails
if instance.thumbnail:
thumbnail_dir = settings.THUMBNAIL_DIR
base_filename = os.path.splitext(os.path.basename(instance.video_file.path))[0]
thumbnail_1080p_path = os.path.join(thumbnail_dir, base_filename + '_1080p.jpg')
thumbnail_480_path = os.path.join(thumbnail_dir, base_filename + '_480p.jpg')
if os.path.isfile(thumbnail_1080p_path):
os.remove(thumbnail_1080p_path)
if os.path.isfile(thumbnail_480_path):
os.remove(thumbnail_480_path)
def remove_first_mp4(filename):
"""
Remove the first .mp4 extension from the filename.
"""
name_part, ext_part = filename.split('.mp4', 1)
new_filename = name_part + ext_part
return new_filename
def delete_converted_files(video_file_path):
"""
Delete all converted video files related to the original video file.
"""
resolutions = ["480", "720", "1080"]
for resolution in resolutions:
converted_video_path = video_file_path + f'_{resolution}p.mp4'
converted_video_path = remove_first_mp4(converted_video_path)
if os.path.isfile(converted_video_path):
os.remove(converted_video_path)

View file

@ -15,27 +15,27 @@ def remove_first_mp4(filename):
new_filename = name_part + ext_part
return new_filename
def create_thumbnail(source):
video_file_path = source.video_file.path
def create_thumbnails(self):
video_file_path = self.video_file.path
thumbnail_dir = settings.THUMBNAIL_DIR
base_filename = os.path.splitext(os.path.basename(video_file_path))[0]
thumbnail_1920_filename = base_filename + '_1920p.jpg'
thumbnail_1920_path = os.path.join(thumbnail_dir, thumbnail_1920_filename)
thumbnail_1080p_filename = base_filename + '_1080p.jpg'
thumbnail_1080p_path = os.path.join(thumbnail_dir, thumbnail_1080p_filename)
thumbnail_480_filename = base_filename + '_480p.jpg'
thumbnail_480_path = os.path.join(thumbnail_dir, thumbnail_480_filename)
thumbnail_path = os.path.join(thumbnail_dir, base_filename + ".jpg")
if not os.path.exists(thumbnail_dir):
os.makedirs(thumbnail_dir)
try:
ffmpeg.input(video_file_path, ss=1).output(thumbnail_1920_path, vf='scale=1920:-1', vframes=1).run(overwrite_output=True)
ffmpeg.input(video_file_path, ss=1).output(thumbnail_480_path, vf='scale=480:-1', vframes=1).run(overwrite_output=True)
ffmpeg.input(video_file_path, ss=1).output(thumbnail_1080p_path, vf='scale=1920:-1', vframes=1).run(overwrite_output=True)
ffmpeg.input(video_file_path, ss=1).output(thumbnail_480_path, vf='scale=720:-1', vframes=1).run(overwrite_output=True)
source.thumbnail_1920 = os.path.relpath(thumbnail_1920_path, start=settings.MEDIA_ROOT)
source.thumbnail_480 = os.path.relpath(thumbnail_480_path, start=settings.MEDIA_ROOT)
source.save()
# Hier speichern wir nur das Thumbnail für die Vorschau im Modell
self.thumbnail = os.path.relpath(thumbnail_path, start=settings.MEDIA_ROOT)
self.save()
except ffmpeg._run.Error as e:
print(f"Ein Fehler ist aufgetreten: {e.stderr.decode()}")

View file

@ -52,6 +52,7 @@ INSTALLED_APPS = [
'rest_framework',
'corsheaders',
'debug_toolbar',
'django_rq',
'content.apps.ContentConfig',
'users',
]
@ -102,10 +103,20 @@ INTERNAL_IPS = [
'127.0.0.1',
]
RQ_QUEUES = {
'default': {
'HOST': 'localhost',
'PORT': 6379,
'DB': 0,
'PASSWORD': 'foobared',
'DEFAULT_TIMEOUT': 360,
}
}
CACHE_TTL = 60 * 15
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
THUMBNAIL_DIR = os.path.join(BASE_DIR, 'media/img')
THUMBNAIL_DIR = os.path.join(BASE_DIR, 'media/thumbnails')
MEDIA_URL = '/media/'
WSGI_APPLICATION = 'videoflix.wsgi.application'

View file

@ -15,7 +15,7 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from users import views as user_views
@ -32,6 +32,7 @@ from debug_toolbar.toolbar import debug_toolbar_urls
urlpatterns = [
path('admin/', admin.site.urls),
path('django-rq/', include('django_rq.urls')),
# Content URLs
path('content/', content_views.video_list),