switch to movie data from the backend

This commit is contained in:
Chneemann 2024-08-11 21:58:28 +02:00
parent 87b785d386
commit 817ddc63dd
12 changed files with 121 additions and 65 deletions

View file

@ -5,8 +5,9 @@ class Video(models.Model):
created_at = models.DateField(default=date.today) created_at = models.DateField(default=date.today)
title = models.CharField(max_length=80) title = models.CharField(max_length=80)
description = models.CharField(max_length=500) description = models.CharField(max_length=500)
film_genre = models.CharField(max_length=50, blank=True, null=True)
video_file = models.FileField(upload_to='videos', blank=True, null=True) video_file = models.FileField(upload_to='videos', blank=True, null=True)
thumbnail = models.FileField(upload_to='thumbnails/', null=True, blank=True) thumbnail = models.FileField(upload_to='img', null=True, blank=True)
def __str__(self): def __str__(self):
return self.title return self.title

View file

@ -0,0 +1,7 @@
from rest_framework import serializers
from .models import Video
class VideoSerializer(serializers.ModelSerializer):
class Meta:
model = Video
fields = "__all__"

View file

@ -22,7 +22,7 @@ def video_post_save(sender, instance, created, **kwargs):
os.makedirs(thumbnail_dir) os.makedirs(thumbnail_dir)
try: try:
ffmpeg.input(video_file_path, ss=1).output(absolute_thumbnail_path, vframes=1).run(overwrite_output=True) ffmpeg.input(video_file_path, ss=1).output(absolute_thumbnail_path, vf='scale=300:-1', vframes=1).run(overwrite_output=True)
instance.thumbnail = os.path.relpath(thumbnail_path, start=settings.MEDIA_ROOT) instance.thumbnail = os.path.relpath(thumbnail_path, start=settings.MEDIA_ROOT)
instance.save() instance.save()

View file

@ -1,3 +1,16 @@
from django.shortcuts import render from django.shortcuts import render
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .serializer import VideoSerializer
from .models import Video
# Create your views here. # Create your views here.
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def video_list(request):
if request.method == 'GET':
video = Video.objects.all()
serializer = VideoSerializer(video, many=True)
return Response(serializer.data)

View file

@ -15,16 +15,31 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import path, include from django.urls import path
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from users import views from users import views as user_views
from auth.views import LoginView, RegisterView, VerifyEmailView, AuthView, ForgotPasswordView,ChangePasswordView from auth.views import (
LoginView,
RegisterView,
VerifyEmailView,
AuthView,
ForgotPasswordView,
ChangePasswordView
)
from content import views as content_views
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('users/', views.user_list),
path('users/<int:id>/', views.user_detail), # Content URLs
path('content/', content_views.video_list),
# Users URLs
path('users/', user_views.user_list),
path('users/<int:id>/', user_views.user_detail),
# Authentication URLs
path('auth/', AuthView.as_view()), path('auth/', AuthView.as_view()),
path('auth/login/', LoginView.as_view()), path('auth/login/', LoginView.as_view()),
path('auth/register/', RegisterView.as_view()), path('auth/register/', RegisterView.as_view()),

View file

@ -7,7 +7,7 @@
></app-hero-banner> ></app-hero-banner>
<app-categories <app-categories
[movies]="movies" [movies]="movies"
[currentMovie]="currentMovie[0].id" [currentMovie]="currentMovie[0]?.id"
(currentMovieId)="currentMovieId($event)" (currentMovieId)="currentMovieId($event)"
></app-categories> ></app-categories>
} @else { } @else {
@ -21,10 +21,7 @@
</div> </div>
</div> </div>
<video width="100%" height="100%" controls autoplay> <video width="100%" height="100%" controls autoplay>
<source <source src="{{ playMovie }}" type="video/mp4" />
src="./../../../../assets/movies/{{ playMovie }}"
type="video/mp4"
/>
Your browser does not support the video tag. Your browser does not support the video tag.
</video> </video>
</div> </div>

View file

@ -3,47 +3,42 @@ import { HeaderComponent } from '../../../shared/components/header/header.compon
import { HeroBannerComponent } from './hero-banner/hero-banner.component'; import { HeroBannerComponent } from './hero-banner/hero-banner.component';
import { CategoriesComponent } from './categories/categories.component'; import { CategoriesComponent } from './categories/categories.component';
import { AuthService } from '../../../services/auth.service'; import { AuthService } from '../../../services/auth.service';
import { MovieService } from '../../../services/movie.service';
import { Observable, Subscription } from 'rxjs';
import { CommonModule } from '@angular/common';
@Component({ @Component({
selector: 'app-browse', selector: 'app-browse',
standalone: true, standalone: true,
imports: [HeaderComponent, HeroBannerComponent, CategoriesComponent], imports: [
CommonModule,
HeaderComponent,
HeroBannerComponent,
CategoriesComponent,
],
templateUrl: './browse.component.html', templateUrl: './browse.component.html',
styleUrl: './browse.component.scss', styleUrl: './browse.component.scss',
}) })
export class BrowseComponent implements OnInit { export class BrowseComponent implements OnInit {
movies = [ movies: any[] = [];
{
id: 1,
title: 'Our Galaxy',
description:
'Experience the fascinating journey through the infinite expanse of our galaxy. "Our Galaxy" offers a detailed insight into the breathtaking structures, stars and planets of our cosmic home. Through stunning visual effects and comprehensive explanations, this documentary guides viewers through the mysteries of the universe and reveals the beauty and complexity of outer space. Perfect for astronomy lovers and the curious who want to learn more about the wonders of the universe',
category: 'Documentary',
imgPath: 'galaxy.png',
videoPath: 'galaxy.mp4',
create: '08.03.2024',
},
{
id: 2,
title: 'Star Trek',
description:
'Join Captain Kirk and the crew of the starship USS Enterprise as they embark on thrilling adventures across the universe. "Star Trek" is a legendary sci-fi saga that explores the final frontier, filled with action, exploration, and unforgettable encounters with alien species. This epic journey showcases the spirit of discovery and the unwavering courage of the Starfleet members as they confront the unknown and protect the galaxy from various threats.',
category: 'Science Fiction',
imgPath: 'star-trek.png',
videoPath: 'star-trek.mp4',
create: '08.02.2024',
},
];
constructor(private authService: AuthService) {} constructor(
private authService: AuthService,
private movieService: MovieService
) {}
currentMovie: any[] = []; currentMovie: any[] = [];
playMovie: string = ''; playMovie: string = '';
ngOnInit(): void { async ngOnInit() {
await this.loadAllMovies();
this.currentMovie.length === 0 ? this.loadRandomMovie() : null; this.currentMovie.length === 0 ? this.loadRandomMovie() : null;
} }
async loadAllMovies() {
this.movies = await this.movieService.getAllMovies();
}
closeVideo(): void { closeVideo(): void {
this.playMovie = ''; this.playMovie = '';
} }

View file

@ -1,13 +1,13 @@
<section class="hide-scrollbar"> <section *ngIf="movies.length > 0" class="hide-scrollbar">
<!-- Column for films of the last 7 days --> <!-- Column for films of the last 7 days -->
<div class="category"> <div *ngIf="recentMovies().length > 0" class="category">
<p>Added in the last 7 days</p> <p>Added in the last 7 days</p>
<div class="movies"> <div class="movies">
@for (movie of recentMovies(); track movie) { @for (movie of recentMovies(); track movie) {
<div class="movie" (click)="openCurrentMovie(movie.id)"> <div class="movie" (click)="openCurrentMovie(movie.id)">
<img <img
[ngClass]="{ selected: movie.id === currentMovie }" [ngClass]="{ selected: movie.id === currentMovie }"
src="./../../../../../assets/movies/banner/{{ movie.imgPath }}" src="{{ environmentBaseUrl + movie.thumbnail }}"
alt="" alt=""
/> />
</div> </div>
@ -25,7 +25,7 @@
<div class="movie" (click)="openCurrentMovie(movie.id)"> <div class="movie" (click)="openCurrentMovie(movie.id)">
<img <img
[ngClass]="{ selected: movie.id === currentMovie }" [ngClass]="{ selected: movie.id === currentMovie }"
src="./../../../../../assets/movies/banner/{{ movie.imgPath }}" src="{{ environmentBaseUrl + movie.thumbnail }}"
alt="" alt=""
/> />
</div> </div>

View file

@ -1,5 +1,6 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { environment } from '../../../../environments/environment.development';
@Component({ @Component({
selector: 'app-categories', selector: 'app-categories',
@ -13,6 +14,8 @@ export class CategoriesComponent {
@Input() currentMovie: number = 0; @Input() currentMovie: number = 0;
@Output() currentMovieId = new EventEmitter<number>(); @Output() currentMovieId = new EventEmitter<number>();
environmentBaseUrl: string = environment.baseUrl.slice(0, -1);
filmGenres = [ filmGenres = [
'Action', 'Action',
'Adventure', 'Adventure',
@ -38,7 +41,7 @@ export class CategoriesComponent {
} }
allMovies(filmGenre: string) { allMovies(filmGenre: string) {
return this.movies.filter((movie) => movie.category === filmGenre); return this.movies.filter((movie) => movie.film_genre === filmGenre);
} }
recentMovies() { recentMovies() {

View file

@ -1,18 +1,21 @@
<section <section
class="movie-banner" class="movie-banner"
[style.backgroundImage]="'url(' + getImagePath() + ')'" [ngStyle]="{
'background-image':
'url(' + environmentBaseUrl + currentMovie[0]?.thumbnail + ')'
}"
> >
@if (currentMovie.length > 0) { @if (currentMovie.length > 0) {
<div class="content"> <div class="content">
<div class="title">{{ currentMovie[0].title }}</div> <div class="title">{{ currentMovie[0]?.title }}</div>
<div class="description"> <div class="description">
{{ currentMovie[0].description }} {{ currentMovie[0]?.description }}
</div> </div>
<app-btn-large <app-btn-large
[value]="'Play'" [value]="'Play'"
[imgPath]="'play'" [imgPath]="'play'"
[imgReverse]="true" [imgReverse]="true"
(click)="playMovieId(currentMovie[0].videoPath)" (click)="playMovieId(environmentBaseUrl + currentMovie[0]?.video_file)"
></app-btn-large> ></app-btn-large>
</div> </div>
} }

View file

@ -7,6 +7,8 @@ import {
Output, Output,
} from '@angular/core'; } from '@angular/core';
import { BtnLargeComponent } from '../../../../shared/components/btn-large/btn-large.component'; import { BtnLargeComponent } from '../../../../shared/components/btn-large/btn-large.component';
import { MovieService } from '../../../../services/movie.service';
import { environment } from '../../../../environments/environment.development';
@Component({ @Component({
selector: 'app-hero-banner', selector: 'app-hero-banner',
@ -19,28 +21,15 @@ export class HeroBannerComponent {
@Input() currentMovie: any[] = []; @Input() currentMovie: any[] = [];
@Output() playMovie = new EventEmitter<string>(); @Output() playMovie = new EventEmitter<string>();
constructor(private el: ElementRef) {} environmentBaseUrl: string = environment.baseUrl.slice(0, -1);
ngAfterViewInit() { constructor(private el: ElementRef, private movieService: MovieService) {}
this.truncateText();
}
playMovieId(videoPath: string) { playMovieId(videoPath: string) {
this.playMovie.emit(videoPath); this.playMovie.emit(videoPath);
} }
getImagePath(): string { getImagePath(): any {
return `./../../../../../assets/movies/banner/${this.currentMovie[0]?.imgPath}`; return '123';
}
truncateText() {
const descriptionEl = this.el.nativeElement.querySelector('.description');
const maxHeight = descriptionEl.offsetHeight;
let text = descriptionEl.innerText;
while (descriptionEl.scrollHeight > maxHeight) {
text = text.slice(0, -1);
descriptionEl.innerText = text + '...';
}
} }
} }

View file

@ -0,0 +1,33 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { lastValueFrom, Observable, of } from 'rxjs';
import { environment } from '../environments/environment.development';
@Injectable({
providedIn: 'root',
})
export class MovieService {
constructor(private http: HttpClient) {}
getAllMovies(): Promise<any> {
const url = environment.baseUrl + '/content/';
const headers = this.getAuthHeaders();
return lastValueFrom(this.http.get(url, { headers }));
}
getMovieFiles(videoUrl: number): Promise<any> {
const url = environment.baseUrl + `${videoUrl}`;
const headers = this.getAuthHeaders();
return lastValueFrom(this.http.get(url, { headers }));
}
private getAuthHeaders(): HttpHeaders {
let authToken = localStorage.getItem('authToken');
if (!authToken) {
authToken = sessionStorage.getItem('authToken');
}
return new HttpHeaders({
Authorization: `Token ${authToken}`, // Ensure this matches your backend
});
}
}