refactor: improve code readability and maintainability across components

This commit is contained in:
Chneemann 2025-05-02 17:20:17 +02:00
parent 039711b18f
commit 87b026ff35
14 changed files with 50 additions and 50 deletions

View file

@ -3,7 +3,7 @@ certifi==2024.7.4
charset-normalizer==3.3.2
click==8.1.7
diff-match-patch==20230430
Django==5.0.10
Django==5.2
django-cors-headers==4.4.0
django-environ==0.12.0
django-grip==3.5.0
@ -30,7 +30,7 @@ rq==1.16.2
sentry-sdk==2.14.0
setuptools==72.1.0
six==1.16.0
sqlparse==0.5.1
sqlparse==0.5.3
tablib==3.5.0
urllib3==2.2.2
Werkzeug==3.0.6

View file

@ -10,5 +10,5 @@ class VideoResource(resources.ModelResource):
@admin.register(Video)
class VideoAdmin(ImportExportModelAdmin):
resource_class = VideoResource
readonly_fields = ('file_name',)
list_display = ('title', 'file_name', 'created_at')
readonly_fields = ('file_path',)
list_display = ('title', 'file_path', 'created_at')

View file

@ -1,4 +1,4 @@
FILM_GENRES = [
VIDEO_GENRES = [
('action', 'Action'),
('adventure', 'Adventure'),
('animation', 'Animation'),

View file

@ -1,7 +1,7 @@
from django.db import models
from django.conf import settings
from datetime import date
from .class_assets import FILM_GENRES
from .class_assets import VIDEO_GENRES
import os
class Video(models.Model):
@ -9,17 +9,17 @@ class Video(models.Model):
created_at = models.DateField(default=date.today)
title = models.CharField(max_length=80)
description = models.CharField(max_length=500)
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)
genre = models.CharField(max_length=20, choices=VIDEO_GENRES, blank=True, null=True)
file_path = models.FileField(upload_to='videos/', blank=True, null=True)
file_name = models.CharField(max_length=50, blank=True, null=True)
def __str__(self):
return f'({self.id}) {self.title}'
def save(self, *args, **kwargs):
if self.video_file and not self.file_name:
video_file_path = self.video_file.path
base_filename, _ = os.path.splitext(os.path.basename(video_file_path))
if self.file_path and not self.file_name:
file_path = self.file_path.path
base_filename, _ = os.path.splitext(os.path.basename(file_path))
self.file_name = base_filename
super().save(*args, **kwargs)

View file

@ -19,10 +19,10 @@ def video_post_save(sender, instance, created, **kwargs):
#Convert video
for resolution in ["1280x720", "640x360", "1920x1080"]:
queue.enqueue(convert_video_to_hls, instance.video_file.path, resolution, instance.id)
queue.enqueue(convert_video_to_hls, instance.file_path.path, resolution, instance.id)
#Delete the original video file
queue.enqueue(delete_original_video, instance.video_file.path)
queue.enqueue(delete_original_video, instance.file_path.path)
@receiver(post_delete, sender=Video)
def auto_delete_file_on_delete(sender, instance, **kwargs):
@ -30,7 +30,7 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
Deletes the video and all converted files from the file system,
when the corresponding `Video` object is deleted.
"""
main_directory = os.path.dirname(instance.video_file.path)
main_directory = os.path.dirname(instance.file_path.path)
parent_directory = os.path.dirname(main_directory)
model_directory = os.path.join(main_directory, str(instance.id))
thumbnail_directory = os.path.join(parent_directory, 'thumbnails', str(instance.id))

View file

@ -46,7 +46,7 @@ def create_thumbnails(instance, model_id):
"""
Creates high-resolution and low-resolution thumbnails from a video file.
"""
video_file_path = instance.video_file.path
video_file_path = instance.file_path.path
thumbnail_dir = os.path.join(settings.THUMBNAIL_DIR, str(model_id))
base_filename = os.path.splitext(os.path.basename(video_file_path))[0]

View file

@ -3,7 +3,7 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .serializer import VideoSerializer
from .models import Video
from .class_assets import FILM_GENRES
from .class_assets import VIDEO_GENRES
from django.core.cache.backends.base import DEFAULT_TIMEOUT
from django.views.decorators.cache import cache_page
from django.conf import settings
@ -29,9 +29,9 @@ def video_list(request):
@permission_classes([IsAuthenticated])
def genre_list(request):
"""
Return a list of film genres from static choices.
Return a list of video genres from static choices.
"""
genres = [{'code': code, 'name': name} for code, name in FILM_GENRES]
genres = [{'code': code, 'name': name} for code, name in VIDEO_GENRES]
return Response(genres)
@api_view(['GET'])

View file

@ -30,14 +30,14 @@
@if (genres$ | async; as genres) {
<!-- Loop through genres -->
@for (filmGenre of genres; track filmGenre) {
@for (genre of genres; track genre) {
<!-- If genre has videos -->
@if (getAllVideos(filmGenre.code).length > 0) {
@if (getAllVideos(genre.code).length > 0) {
<div class="category">
<p>{{ filmGenre.name }}</p>
<p>{{ genre.name }}</p>
<app-video-list
[videos]="getAllVideos(filmGenre.code)"
[videos]="getAllVideos(genre.code)"
[currentVideo]="currentVideo"
[watchedVideos]="watchedVideos"
(currentVideoId)="openCurrentVideo($event)"

View file

@ -10,8 +10,8 @@ import {
} from '@angular/core';
import { environment } from '../../../../environments/environment';
import { VideoListComponent } from './video-list/video-list.component';
import { FilmGenreService } from '../../../services/film-genre.service';
import { Video } from '../../../interfaces/video.interface';
import { GenreService } from '../../../services/genre.service';
@Component({
selector: 'app-categories',
@ -30,9 +30,9 @@ export class CategoriesComponent implements AfterViewInit {
environmentBaseUrl: string = environment.baseUrl;
isScrollable: boolean = false;
genres$ = this.filmGenreService.getGenres();
genres$ = this.genreService.getGenres();
constructor(private filmGenreService: FilmGenreService) {}
constructor(private genreService: GenreService) {}
ngAfterViewInit(): void {
this.checkScroll();
@ -46,8 +46,8 @@ export class CategoriesComponent implements AfterViewInit {
}
}
getAllVideos(filmGenre: string) {
return this.videos.filter((video) => video.film_genre === filmGenre);
getAllVideos(genre: string) {
return this.videos.filter((video) => video.genre === genre);
}
getFavoriteVideos() {

View file

@ -39,11 +39,11 @@
}
</div>
<select
id="filmGenre"
name="filmGenre"
#filmGenre="ngModel"
[(ngModel)]="videoData.filmGenre"
[class.error-border]="!filmGenre.valid && filmGenre.touched"
id="genre"
name="genre"
#genre="ngModel"
[(ngModel)]="videoData.genre"
[class.error-border]="!genre.valid && genre.touched"
required
>
<option value="action">Action</option>
@ -66,8 +66,8 @@
<option value="western">Western</option>
</select>
<div class="error-msg">
@if (!filmGenre.valid && filmGenre.touched) {
<p>Please enter a movie genre</p>
@if (!genre.valid && genre.touched) {
<p>Please enter a genre</p>
}
</div>
<input
@ -94,8 +94,8 @@
[disabled]="
!videoData.title ||
!videoData.description ||
!videoData.filmGenre ||
!videoData.videoFile ||
!videoData.genre ||
!videoData.file ||
videoData.send
"
></app-btn-large>

View file

@ -28,8 +28,8 @@ export class UploadVideoComponent {
videoData = {
title: '',
description: '',
filmGenre: '',
videoFile: null as File | null,
genre: '',
file: null as File | null,
send: false,
};
@ -54,7 +54,7 @@ export class UploadVideoComponent {
isOneFile(event: any) {
const file = event.target.files[0];
if (file) {
this.videoData.videoFile = file;
this.videoData.file = file;
}
}
isFileSize(event: any) {
@ -93,9 +93,9 @@ export class UploadVideoComponent {
const formData = new FormData();
formData.append('title', this.videoData.title);
formData.append('description', this.videoData.description);
formData.append('film_genre', this.videoData.filmGenre);
if (this.videoData.videoFile) {
formData.append('video_file', this.videoData.videoFile);
formData.append('genre', this.videoData.genre);
if (this.videoData.file) {
formData.append('file_path', this.videoData.file);
}
return formData;
}

View file

@ -1,4 +1,4 @@
export interface FilmGenre {
export interface Genre {
code: string;
name: string;
}

View file

@ -4,7 +4,7 @@ export interface Video {
created_at: string;
title: string;
description: string;
film_genre: string;
video_file: string;
genre: string;
file_path: string;
file_name: string;
}

View file

@ -1,13 +1,13 @@
import { Injectable } from '@angular/core';
import { Observable, of, tap } from 'rxjs';
import { ApiService } from './api.service';
import { FilmGenre } from '../interfaces/film-genre.interface';
import { Genre } from '../interfaces/genre.interface';
@Injectable({
providedIn: 'root',
})
export class FilmGenreService {
private genres: FilmGenre[] = [];
export class GenreService {
private genres: Genre[] = [];
constructor(private apiService: ApiService) {}
@ -15,12 +15,12 @@ export class FilmGenreService {
* Returns the genres either from the cache or from the API endpoint.
* @returns observable of movie genres
*/
getGenres(): Observable<FilmGenre[]> {
getGenres(): Observable<Genre[]> {
if (this.genres.length > 0) {
return of(this.genres);
}
return this.apiService.get<FilmGenre[]>('/video/genres/', true).pipe(
return this.apiService.get<Genre[]>('/video/genres/', true).pipe(
tap((data) => {
this.genres = data;
})