when the thumbnail is created the page is refreshed

This commit is contained in:
Chneemann 2024-08-14 19:21:56 +02:00
parent f20fd0566f
commit 58208d11dd
7 changed files with 97 additions and 41 deletions

View file

@ -9,6 +9,7 @@ class Video(models.Model):
film_genre = models.CharField(max_length=20, choices=FILM_GENRES, blank=True, null=True)
video_file = models.FileField(upload_to='videos/', blank=True, null=True)
file_name = models.CharField(max_length=50, blank=True, null=True)
thumbnail_created = models.BooleanField(default=False)
def __str__(self):
return f'({self.id}) {self.title}'

View file

@ -1,5 +1,5 @@
from .models import Video
from .tasks import convert_video_to_hls, create_thumbnails, delete_original_video
from .tasks import convert_video_to_hls, create_thumbnails, delete_original_video, update_thumbnail_status
from django.dispatch import receiver
from django.db.models.signals import post_save, post_delete
from django.conf import settings
@ -16,13 +16,12 @@ def video_post_save(sender, instance, created, **kwargs):
queue = django_rq.get_queue("default", autocommit=True)
#Create thumbnail
queue.enqueue(create_thumbnails, instance, instance.id)
create_thumbnails(instance, instance.id)
#Convert video
queue.enqueue(convert_video_to_hls, instance.video_file.path, "480", instance.id)
queue.enqueue(convert_video_to_hls, instance.video_file.path, "720", instance.id)
queue.enqueue(convert_video_to_hls, instance.video_file.path, "1080", instance.id)
for resolution in ["480", "720", "1080"]:
queue.enqueue(convert_video_to_hls, instance.video_file.path, resolution, instance.id)
# Delete the original video file
queue.enqueue(delete_original_video, instance.video_file.path)

View file

@ -4,6 +4,7 @@ import ffmpeg
import os
from django.conf import settings
from .models import Video
from django_rq import get_queue
def convert_video_to_hls(source, resolution, model_id):
target_dir = os.path.join(os.path.dirname(source), str(model_id))
@ -38,10 +39,10 @@ def delete_original_video(source):
except OSError as e:
print(f"Error deleting original file: {e}")
def create_thumbnails(self, model_id):
video_file_path = self.video_file.path
def create_thumbnails(instance, model_id):
video_file_path = instance.video_file.path
thumbnail_dir = os.path.join(settings.THUMBNAIL_DIR, str(model_id))
base_filename = os.path.splitext(os.path.basename(video_file_path))[0]
thumbnail_1080p_filename = base_filename + '_1080p.jpg'
thumbnail_1080p_path = os.path.join(thumbnail_dir, thumbnail_1080p_filename)
@ -52,8 +53,19 @@ def create_thumbnails(self, model_id):
os.makedirs(thumbnail_dir)
try:
# Generate the thumbnails
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)
# Update thumbnail status
update_thumbnail_status(model_id)
except ffmpeg._run.Error as e:
print(f"Ein Fehler ist aufgetreten: {e.stderr.decode()}")
print(f"Ein Fehler ist aufgetreten: {e.stderr.decode()}")
def update_thumbnail_status(video_id):
try:
video = Video.objects.get(id=video_id)
video.thumbnail_created = True
video.save()
except Video.DoesNotExist:
print(f"Video with id {video_id} does not exist.")

View file

@ -16,12 +16,25 @@ CACHETTL = getattr(settings, 'CACHE_TTL', DEFAULT_TIMEOUT)
@permission_classes([IsAuthenticated])
#@cache_page(CACHETTL)
def video_list(request):
if request.method == 'GET':
video = Video.objects.all()
serializer = VideoSerializer(video, many=True)
"""
List all videos.
"""
videos = Video.objects.all()
serializer = VideoSerializer(videos, many=True)
return Response(serializer.data)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def check_thumbnail_status(request, video_id):
"""
Check the status of the thumbnail creation for a specific video.
"""
try:
video = Video.objects.get(id=video_id)
return Response({'thumbnail_created': video.thumbnail_created})
except Video.DoesNotExist:
return Response({'error': 'Video not found'}, status=404)
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def video_upload(request):

View file

@ -37,6 +37,7 @@ urlpatterns = [
# Content URLs
path('content/', content_views.video_list),
path('content/upload/', content_views.video_upload),
path('content/<int:video_id>/status/', content_views.check_thumbnail_status),
# Users URLs
path('users/', user_views.user_list),

View file

@ -44,27 +44,47 @@ export class UploadMovieComponent {
}
async onSubmit(ngForm: NgForm) {
if (ngForm.submitted && ngForm.form.valid) {
const formData = new FormData();
formData.append('title', this.movieData.title);
formData.append('description', this.movieData.description);
formData.append('film_genre', this.movieData.filmGenre);
if (this.movieData.videoFile) {
formData.append('video_file', this.movieData.videoFile);
}
try {
await this.movieService.uploadMovie(formData);
this.movieData.send = true;
setTimeout(() => {
ngForm.resetForm();
this.uploadMovieOverview();
this.movieData.send = false;
window.location.reload();
}, 1000);
this.errorService.clearError();
} catch (error) {
this.errorService.handleError(error);
}
if (!ngForm.submitted || !ngForm.form.valid) return;
try {
this.movieData.send = true;
const formData = this.createFormData();
const response = await this.movieService
.uploadMovie(formData)
.toPromise();
const videoId = response.id;
await this.waitForThumbnailCreation(videoId);
ngForm.resetForm();
this.uploadMovieOverview();
this.movieData.send = false;
window.location.reload();
this.errorService.clearError();
} catch (error) {
this.errorService.handleError(error);
}
}
private createFormData(): FormData {
const formData = new FormData();
formData.append('title', this.movieData.title);
formData.append('description', this.movieData.description);
formData.append('film_genre', this.movieData.filmGenre);
if (this.movieData.videoFile) {
formData.append('video_file', this.movieData.videoFile);
}
return formData;
}
private async waitForThumbnailCreation(videoId: number) {
while (true) {
const statusResponse = await this.movieService
.checkThumbnailStatus(videoId)
.toPromise();
if (statusResponse?.thumbnail_created) break;
await new Promise((resolve) => setTimeout(resolve, 2000));
}
}
}

View file

@ -21,12 +21,22 @@ export class MovieService {
return lastValueFrom(this.http.get(url, { headers }));
}
async uploadMovie(formData: FormData) {
uploadMovie(formData: FormData): Observable<any> {
const headers = this.getAuthHeaders();
await lastValueFrom(
this.http.post(`${environment.baseUrl}/content/upload/`, formData, {
headers,
})
return this.http.post<any>(
`${environment.baseUrl}/content/upload/`,
formData,
{ headers }
);
}
checkThumbnailStatus(
videoId: number
): Observable<{ thumbnail_created: boolean }> {
const headers = this.getAuthHeaders();
return this.http.get<{ thumbnail_created: boolean }>(
`${environment.baseUrl}/content/${videoId}/status/`,
{ headers }
);
}