when the thumbnail is created the page is refreshed
This commit is contained in:
parent
f20fd0566f
commit
58208d11dd
7 changed files with 97 additions and 41 deletions
|
|
@ -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}'
|
||||
|
|
|
|||
|
|
@ -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,12 +16,11 @@ 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)
|
||||
|
|
|
|||
|
|
@ -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,8 +39,8 @@ 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]
|
||||
|
|
@ -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()}")
|
||||
|
||||
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.")
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue