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 asgiref==3.8.1
click==8.1.7
Django==5.0.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 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 sqlparse==0.5.1

View file

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

View file

@ -1,8 +1,10 @@
from .models import Video 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.dispatch import receiver
from django.db.models.signals import post_save, post_delete from django.db.models.signals import post_save, post_delete
from django.conf import settings
import os import os
import django_rq
@receiver(post_save, sender=Video) @receiver(post_save, sender=Video)
def video_post_save(sender, instance, created, **kwargs): 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. Generates a thumbnail for a newly created `Video` instance.
""" """
if created: if created:
queue = django_rq.get_queue("default", autocommit=True)
#Convert Video #Convert Video
convert_video(instance.video_file.path, "480") queue.enqueue(convert_video, instance.video_file.path, "480")
convert_video(instance.video_file.path, "720") queue.enqueue(convert_video, instance.video_file.path, "720")
convert_video(instance.video_file.path, "1080") queue.enqueue(convert_video, instance.video_file.path, "1080")
#Create Thumbnail #Create Thumbnail
create_thumbnail(instance) queue.enqueue(create_thumbnails, instance)
@receiver(post_delete, sender=Video) @receiver(post_delete, sender=Video)
def auto_delete_file_on_delete(sender, instance, **kwargs): 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. when corresponding `Video` object is deleted.
""" """
# Delete the original video file
if instance.video_file: if instance.video_file:
if os.path.isfile(instance.video_file.path): 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 new_filename = name_part + ext_part
return new_filename return new_filename
def create_thumbnail(source): def create_thumbnails(self):
video_file_path = source.video_file.path video_file_path = self.video_file.path
thumbnail_dir = settings.THUMBNAIL_DIR thumbnail_dir = settings.THUMBNAIL_DIR
base_filename = os.path.splitext(os.path.basename(video_file_path))[0] base_filename = os.path.splitext(os.path.basename(video_file_path))[0]
thumbnail_1920_filename = base_filename + '_1920p.jpg' thumbnail_1080p_filename = base_filename + '_1080p.jpg'
thumbnail_1920_path = os.path.join(thumbnail_dir, thumbnail_1920_filename) thumbnail_1080p_path = os.path.join(thumbnail_dir, thumbnail_1080p_filename)
thumbnail_480_filename = base_filename + '_480p.jpg' thumbnail_480_filename = base_filename + '_480p.jpg'
thumbnail_480_path = os.path.join(thumbnail_dir, thumbnail_480_filename) 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): if not os.path.exists(thumbnail_dir):
os.makedirs(thumbnail_dir) os.makedirs(thumbnail_dir)
try: 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_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=480:-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) # Hier speichern wir nur das Thumbnail für die Vorschau im Modell
source.thumbnail_480 = os.path.relpath(thumbnail_480_path, start=settings.MEDIA_ROOT) self.thumbnail = os.path.relpath(thumbnail_path, start=settings.MEDIA_ROOT)
self.save()
source.save()
except ffmpeg._run.Error as e: except ffmpeg._run.Error as e:
print(f"Ein Fehler ist aufgetreten: {e.stderr.decode()}") print(f"Ein Fehler ist aufgetreten: {e.stderr.decode()}")

View file

@ -52,6 +52,7 @@ INSTALLED_APPS = [
'rest_framework', 'rest_framework',
'corsheaders', 'corsheaders',
'debug_toolbar', 'debug_toolbar',
'django_rq',
'content.apps.ContentConfig', 'content.apps.ContentConfig',
'users', 'users',
] ]
@ -102,10 +103,20 @@ INTERNAL_IPS = [
'127.0.0.1', '127.0.0.1',
] ]
RQ_QUEUES = {
'default': {
'HOST': 'localhost',
'PORT': 6379,
'DB': 0,
'PASSWORD': 'foobared',
'DEFAULT_TIMEOUT': 360,
}
}
CACHE_TTL = 60 * 15 CACHE_TTL = 60 * 15
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 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/' MEDIA_URL = '/media/'
WSGI_APPLICATION = 'videoflix.wsgi.application' 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')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import path from django.urls import path, include
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from users import views as user_views from users import views as user_views
@ -32,6 +32,7 @@ from debug_toolbar.toolbar import debug_toolbar_urls
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('django-rq/', include('django_rq.urls')),
# Content URLs # Content URLs
path('content/', content_views.video_list), path('content/', content_views.video_list),