diff --git a/backend/video_app/signals.py b/backend/video_app/signals.py
index a09bd08..5e2f8ef 100644
--- a/backend/video_app/signals.py
+++ b/backend/video_app/signals.py
@@ -51,9 +51,9 @@ def delete_converted_files(video_file_path):
"""
Delete all converted video files related to the original video file.
"""
- resolutions = ["360", "720", "1080"]
+ resolutions = ["360p", "720p", "1080p"]
for resolution in resolutions:
- converted_video_path = video_file_path + f'_{resolution}p.mp4'
+ converted_video_path = video_file_path + f'_{resolution}.mp4'
converted_video_path = remove_first_mp4(converted_video_path)
if os.path.isfile(converted_video_path):
os.remove(converted_video_path)
diff --git a/backend/video_app/views.py b/backend/video_app/views.py
index 88e47ab..3ce53f0 100644
--- a/backend/video_app/views.py
+++ b/backend/video_app/views.py
@@ -30,7 +30,7 @@ def check_video_resolutions(request, id):
"""
Check if a specific video exists in different resolutions (360p, 720p, 1080p).
"""
- resolutions = ['360', '720', '1080']
+ resolutions = ['360p', '720p', '1080p']
result = {}
try:
@@ -41,7 +41,7 @@ def check_video_resolutions(request, id):
video_dir = os.path.join(settings.MEDIA_ROOT, 'videos', str(id))
for res in resolutions:
- video_file_name = f"{video.file_name}_{res}p.m3u8"
+ video_file_name = f"{video.file_name}_{res}.m3u8"
video_file_path = os.path.join(video_dir, video_file_name)
result[res] = os.path.exists(video_file_path)
diff --git a/frontend/src/app/components/home/hero-banner/hero-banner.component.ts b/frontend/src/app/components/home/hero-banner/hero-banner.component.ts
index 0ff436a..9fedb71 100644
--- a/frontend/src/app/components/home/hero-banner/hero-banner.component.ts
+++ b/frontend/src/app/components/home/hero-banner/hero-banner.component.ts
@@ -42,9 +42,9 @@ export class HeroBannerComponent implements OnChanges {
playUrl: string = '';
environmentBaseUrl: string = environment.baseUrl;
movieIsUploaded: { [resolution: string]: boolean } = {
- '320': true,
- '720': true,
- '1080': true,
+ '320p': true,
+ '720p': true,
+ '1080p': true,
};
constructor(
private movieService: MovieService,
@@ -123,9 +123,9 @@ export class HeroBannerComponent implements OnChanges {
isAnyResolutionUploaded(): boolean {
return (
- this.movieIsUploaded['320'] ||
- this.movieIsUploaded['720'] ||
- this.movieIsUploaded['1080']
+ this.movieIsUploaded['320p'] ||
+ this.movieIsUploaded['720p'] ||
+ this.movieIsUploaded['1080p']
);
}
diff --git a/frontend/src/app/components/home/home.component.html b/frontend/src/app/components/home/home.component.html
index 2d50e67..ca1be50 100644
--- a/frontend/src/app/components/home/home.component.html
+++ b/frontend/src/app/components/home/home.component.html
@@ -44,52 +44,30 @@
+
+ @for (resolution of availableResolutions; track $index) {
-
-
+ }
-
+
+ @if (isAnyResolutionUnavailable()) {
+
(If a button cannot be selected, the video will be converted, which
may take a few seconds.)
+ }

diff --git a/frontend/src/app/components/home/home.component.ts b/frontend/src/app/components/home/home.component.ts
index ca9c755..cadcd5f 100644
--- a/frontend/src/app/components/home/home.component.ts
+++ b/frontend/src/app/components/home/home.component.ts
@@ -33,11 +33,12 @@ export class HomeComponent implements OnInit {
playMovie: string = '';
isLoading: boolean = true;
uploadMovieOverview: boolean = false;
- currentResolution: '360p' | '720p' | '1080p' = '720p';
+ availableResolutions: string[] = ['360p', '720p', '1080p'];
+ currentResolution = '720p';
movieIsUploaded: { [resolution: string]: boolean } = {
- '360': false,
- '720': false,
- '1080': false,
+ '360p': false,
+ '720p': false,
+ '1080p': false,
};
constructor(
@@ -98,8 +99,8 @@ export class HomeComponent implements OnInit {
this.updateLikeMovies();
}
- changeResolution(resolution: '360p' | '720p' | '1080p') {
- if (this.videoPlayer && this.movieIsUploaded[resolution.replace('p', '')]) {
+ changeResolution(resolution: string) {
+ if (this.videoPlayer && this.movieIsUploaded[resolution]) {
this.videoPlayer.switchResolution(resolution);
this.currentResolution = resolution;
}
@@ -109,6 +110,7 @@ export class HomeComponent implements OnInit {
this.isLoading = true;
try {
this.movies = await this.movieService.getAllMovies();
+ console.log(this.movies);
} finally {
this.isLoading = false;
}
@@ -136,6 +138,12 @@ export class HomeComponent implements OnInit {
}
}
+ isAnyResolutionUnavailable(): boolean {
+ return this.availableResolutions.some(
+ (resolution) => !this.movieIsUploaded[resolution]
+ );
+ }
+
toggleUploadMovieOverview(value: any) {
this.uploadMovieOverview = value;
}
diff --git a/frontend/src/app/components/home/video-player/video-player.component.ts b/frontend/src/app/components/home/video-player/video-player.component.ts
index b756bf0..af58c70 100644
--- a/frontend/src/app/components/home/video-player/video-player.component.ts
+++ b/frontend/src/app/components/home/video-player/video-player.component.ts
@@ -62,7 +62,7 @@ export class VideoPlayerComponent implements OnInit, OnDestroy {
}
}
- public switchResolution(resolution: '360p' | '720p' | '1080p') {
+ public switchResolution(resolution: string) {
if (this.resolutionUrls[resolution]) {
if (this.hls) {
this.hls.loadSource(this.resolutionUrls[resolution]);
diff --git a/frontend/src/app/services/movie.service.ts b/frontend/src/app/services/movie.service.ts
index 144df3e..10f82cc 100644
--- a/frontend/src/app/services/movie.service.ts
+++ b/frontend/src/app/services/movie.service.ts
@@ -1,12 +1,5 @@
import { Injectable } from '@angular/core';
-import {
- BehaviorSubject,
- catchError,
- firstValueFrom,
- map,
- Observable,
- of,
-} from 'rxjs';
+import { catchError, firstValueFrom, map, Observable, of } from 'rxjs';
import { ApiService } from './api.service';
import { AuthService } from './auth.service';
@@ -14,7 +7,10 @@ import { AuthService } from './auth.service';
providedIn: 'root',
})
export class MovieService {
- private movieCache: { [key: number]: { [resolution: string]: boolean } } = {};
+ private movieCache: {
+ [key: number]: { [resolution: string]: boolean };
+ } = {};
+ private readonly availableResolutions = ['360p', '720p', '1080p'];
constructor(
private apiService: ApiService,
@@ -53,35 +49,36 @@ export class MovieService {
}
/**
- * Checks if a movie with the given video ID has been uploaded in the following resolutions: 360p, 720p, 1080p.
+ * Check if a movie is available in all resolutions on the server.
+ * This method caches the result to avoid unnecessary requests.
*
* @param videoID the ID of the movie to check
- * @returns an observable that emits an object with the following properties:
- * - '360': a boolean indicating whether the movie has been uploaded in 360p resolution
- * - '720': a boolean indicating whether the movie has been uploaded in 720p resolution
- * - '1080': a boolean indicating whether the movie has been uploaded in 1080p resolution
+ * @returns a promise resolving to an object with the available resolutions
+ * as keys and booleans indicating the availability as values.
*/
isMovieResolutionUploaded(
videoID: number
): Observable<{ [resolution: string]: boolean }> {
- const cachedRes = this.movieCache[videoID];
- if (cachedRes && Object.values(cachedRes).every(Boolean)) {
- return new BehaviorSubject(cachedRes).asObservable();
+ const cachedResolutions = this.movieCache[videoID];
+
+ if (cachedResolutions && Object.values(cachedResolutions).every(Boolean)) {
+ return of(cachedResolutions);
}
return this.apiService.get(`/video/movie/${videoID}/`, true).pipe(
map((res: any) => {
- const resolutions = {
- '360': res['360'] || false,
- '720': res['720'] || false,
- '1080': res['1080'] || false,
- };
+ const resolutions = Object.fromEntries(
+ this.availableResolutions.map((r) => [r, !!res[r]])
+ );
this.movieCache[videoID] = resolutions;
return resolutions;
}),
- catchError(() => {
+ catchError((error) => {
+ console.error('Failed to fetch movie resolutions', error);
this.authService.logout();
- return of({ '360': false, '720': false, '1080': false });
+ return of(
+ Object.fromEntries(this.availableResolutions.map((r) => [r, false]))
+ );
})
);
}