refactor: unify video resolutions and clean up code

This commit is contained in:
Chneemann 2025-04-26 22:24:05 +02:00
parent bf4b1da3f9
commit df8305806f
7 changed files with 58 additions and 75 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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']
);
}

View file

@ -44,52 +44,30 @@
</div>
<div class="center">
<div class="resolution-controls">
<!-- Resolution buttons -->
@for (resolution of availableResolutions; track $index) {
<button
[ngClass]="{
'resolution-btn': true,
active: currentResolution === '360p',
'not-available': !movieIsUploaded['360']
}"
[disabled]="!movieIsUploaded['360'] || currentResolution === '360p'"
(click)="changeResolution('360p')"
>
360p
</button>
<button
[ngClass]="{
'resolution-btn': true,
active: currentResolution === '720p',
'not-available': !movieIsUploaded['720']
}"
[disabled]="!movieIsUploaded['720'] || currentResolution === '720p'"
(click)="changeResolution('720p')"
>
720p
</button>
<button
[ngClass]="{
'resolution-btn': true,
active: currentResolution === '1080p',
'not-available': !movieIsUploaded['1080']
active: currentResolution === resolution,
'not-available': !movieIsUploaded[resolution]
}"
[disabled]="
!movieIsUploaded['1080'] || currentResolution === '1080p'
!movieIsUploaded[resolution] || currentResolution === resolution
"
(click)="changeResolution('1080p')"
(click)="changeResolution(resolution)"
>
1080p
{{ resolution }}
</button>
}
</div>
<p
*ngIf="
!movieIsUploaded['360'] ||
!movieIsUploaded['720'] ||
!movieIsUploaded['1080']
"
>
<!-- Resolution instructions -->
@if (isAnyResolutionUnavailable()) {
<p>
(If a button cannot be selected, the video will be converted, which
may take a few seconds.)
</p>
}
</div>
<div class="logo">
<img src="./../../../../assets/img/logo_ci.svg" alt="Logo" />

View file

@ -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;
}

View file

@ -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]);

View file

@ -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]))
);
})
);
}