refactor: improve code readability and maintainability across components
This commit is contained in:
parent
039711b18f
commit
87b026ff35
14 changed files with 50 additions and 50 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
FILM_GENRES = [
|
||||
VIDEO_GENRES = [
|
||||
('action', 'Action'),
|
||||
('adventure', 'Adventure'),
|
||||
('animation', 'Animation'),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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'])
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface FilmGenre {
|
||||
export interface Genre {
|
||||
code: string;
|
||||
name: string;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
})
|
||||
Loading…
Reference in a new issue