mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-16 02:02:55 -07:00
Lots of work on the movie details page !wip
This commit is contained in:
parent
cdec1f4f27
commit
947fe8308d
13 changed files with 197 additions and 23 deletions
|
@ -30,7 +30,7 @@ namespace Ombi.Core.Models.Search.V2
|
|||
public string Homepage { get; set; }
|
||||
public int RootPathOverride { get; set; }
|
||||
public string Status { get; set; }
|
||||
public List<VideoResults> Videos { get; set; }
|
||||
public Videos Videos { get; set; }
|
||||
public CreditsViewModel Credits { get; set; }
|
||||
public int QualityOverride { get; set; }
|
||||
public override RequestType Type => RequestType.Movie;
|
||||
|
@ -54,7 +54,12 @@ namespace Ombi.Core.Models.Search.V2
|
|||
public string origin_country { get; set; }
|
||||
}
|
||||
|
||||
public class VideoResults
|
||||
public class Videos
|
||||
{
|
||||
public VideoResultsDetails[] results { get; set; }
|
||||
}
|
||||
|
||||
public class VideoResultsDetails
|
||||
{
|
||||
public string id { get; set; }
|
||||
public string iso_639_1 { get; set; }
|
||||
|
|
|
@ -99,7 +99,9 @@ namespace Ombi.DependencyInjection
|
|||
public static void RegisterEnginesV2(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IMultiSearchEngine, MultiSearchEngine>();
|
||||
services.AddTransient<IMovieEngineV2, MovieSearchEngineV2>();
|
||||
}
|
||||
|
||||
public static void RegisterHttp(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using AutoMapper;
|
||||
using System.Collections.Generic;
|
||||
using AutoMapper;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
|
@ -76,10 +77,14 @@ namespace Ombi.Mapping.Profiles
|
|||
|
||||
CreateMap<FullMovieInfo, SearchMovieViewModel>().ReverseMap();
|
||||
CreateMap<ProductionCompanies, Production_Companies>().ReverseMap();
|
||||
CreateMap<VideoResults, Videos>().ReverseMap();
|
||||
CreateMap<CreditsViewModel, Credits>().ReverseMap();
|
||||
CreateMap<MovieFullInfoViewModel, FullMovieInfo>()
|
||||
.ForMember(x => x.)
|
||||
CreateMap<MovieFullInfoViewModel, FullMovieInfo>().ReverseMap();
|
||||
CreateMap<Ombi.Api.TheMovieDb.Models.Genre, Ombi.Core.Models.Search.V2.GenreViewModel>().ReverseMap();
|
||||
CreateMap<Ombi.Api.TheMovieDb.Models.Production_Companies, Ombi.Core.Models.Search.V2.ProductionCompaniesViewModel>().ReverseMap();
|
||||
CreateMap<Ombi.Api.TheMovieDb.Models.Videos, Ombi.Core.Models.Search.V2.Videos>().ReverseMap();
|
||||
CreateMap<Ombi.Api.TheMovieDb.Models.Result, Ombi.Core.Models.Search.V2.VideoResultsDetails>().ReverseMap();
|
||||
CreateMap<Ombi.Api.TheMovieDb.Models.FullMovieCast, Ombi.Core.Models.Search.V2.FullMovieCastViewModel>().ReverseMap();
|
||||
CreateMap<Ombi.Api.TheMovieDb.Models.FullMovieCrew, Ombi.Core.Models.Search.V2.FullMovieCrewViewModel>().ReverseMap();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@
|
|||
requestId: number;
|
||||
available: boolean;
|
||||
status: string;
|
||||
videos: IVideoResult[];
|
||||
videos: IVideos;
|
||||
credits: ICreditsViewModel;
|
||||
releaseDates: IReleaseDatesDto;
|
||||
similar: IOtherMovies;
|
||||
|
@ -45,6 +45,10 @@
|
|||
background: any;
|
||||
}
|
||||
|
||||
export interface IVideos {
|
||||
results: IVideoResult[];
|
||||
}
|
||||
|
||||
export interface IGenresViewModel {
|
||||
id: number;
|
||||
name: string;
|
||||
|
|
|
@ -6,6 +6,7 @@ import { SearchService } from "../services";
|
|||
import { SharedModule } from "../shared/shared.module";
|
||||
import { MovieDetailsComponent } from "./movie-details.component";
|
||||
import { PipeModule } from "../pipes/pipe.module";
|
||||
import { MovieDetailsTrailerComponent } from "./movie-details-trailer.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "movie/:movieDbId", component: MovieDetailsComponent },
|
||||
|
@ -18,10 +19,14 @@ const routes: Routes = [
|
|||
],
|
||||
declarations: [
|
||||
MovieDetailsComponent,
|
||||
MovieDetailsTrailerComponent
|
||||
],
|
||||
exports: [
|
||||
RouterModule,
|
||||
],
|
||||
entryComponents: [
|
||||
MovieDetailsTrailerComponent
|
||||
],
|
||||
providers: [
|
||||
SearchService
|
||||
],
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<iframe width="100%" height="315px" [src]="'https://www.youtube.com/embed/' + data.videos.results[0].key | safe" frameborder="0"
|
||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
|
@ -0,0 +1,15 @@
|
|||
import { Component, Inject } from "@angular/core";
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material";
|
||||
import { ISearchMovieResultV2 } from "../interfaces/ISearchMovieResultV2";
|
||||
|
||||
@Component({
|
||||
selector: "movie-trailer",
|
||||
templateUrl: "./movie-details-trailer.component.html",
|
||||
})
|
||||
export class MovieDetailsTrailerComponent {
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<MovieDetailsTrailerComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: ISearchMovieResultV2) {}
|
||||
|
||||
}
|
|
@ -9,9 +9,11 @@
|
|||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-10 offset-lg-2 col-md-8 offset-md-4 col-sm-7 offset-sm-5 col-6 offset-6">
|
||||
<h1>{{movie.title}} <span *ngIf="movie.releaseDate" class="year align-middle">({{movie.releaseDate
|
||||
<h1>{{movie.title}} <span *ngIf="movie.releaseDate" class="grey-text align-middle">({{movie.releaseDate
|
||||
| date:'yyyy'}})</span>
|
||||
</h1>
|
||||
|
||||
<h5 class="tagline grey-text">{{movie.tagline}}</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -22,7 +24,7 @@
|
|||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-2 col-sm-3 hidden-xs">
|
||||
<div class="sidebar affixable affix-top" style="width: 173px;">
|
||||
<div class="sidebar sidebar-poster affixable affix-top" style="width: 173px;">
|
||||
<div class="poster">
|
||||
<img class="real" src="https://image.tmdb.org/t/p/w300/{{movie.posterPath}}" alt="Poster"
|
||||
style="display: block;">
|
||||
|
@ -34,7 +36,6 @@
|
|||
|
||||
<!--Next to poster-->
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
@ -57,6 +58,19 @@
|
|||
<small *ngIf="movie.voteCount"><strong>Votes:</strong> {{movie.voteCount |
|
||||
thousandShort: 1}}</small>
|
||||
</div>
|
||||
<div>
|
||||
<small><strong>Status:</strong> {{movie.status}}</small>
|
||||
</div>
|
||||
<div>
|
||||
<small><strong>Runtime:</strong> {{movie.runtime}} Minutes</small>
|
||||
</div>
|
||||
<div>
|
||||
<small *ngIf="movie.revenue"><strong>Revenue:</strong> {{movie.revenue | currency:
|
||||
'USD'}}</small>
|
||||
</div>
|
||||
<div>
|
||||
<small *ngIf="movie.budget"><strong>Budget:</strong> {{movie.budget | currency: 'USD'}}</small>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
|
@ -79,17 +93,101 @@
|
|||
</div>
|
||||
<div class="row card-spacer">
|
||||
<div class="col-md-2">
|
||||
<div><div>
|
||||
<a *ngIf="movie.homepage" class="btn-spacing" href="{{movie.homepage}}" target="_blank"
|
||||
mat-raised-button color="accent">Home Page</a></div>
|
||||
<div>
|
||||
<a *ngIf="movie.homepage" class="btn-spacing" href="{{movie.homepage}}" target="_blank" mat-raised-button color="accent">Home Page</a>
|
||||
<a *ngIf="movie.theMovieDbId" href="https://www.themoviedb.org/movie/{{movie.theMovieDbId}}" target="_blank" mat-raised-button class="btn-blue btn-spacing">The Movie DB</a>
|
||||
<a *ngIf="movie.imdbId" href="https://www.imdb.com/title/tt1727824/{{movie.imdbId}}" target="_blank" mat-raised-button class="imdb-color btn-spacing">IMDb</a>
|
||||
<a *ngIf="movie.id" href="https://www.themoviedb.org/movie/{{movie.id}}"
|
||||
target="_blank" mat-raised-button class="btn-blue btn-spacing">The Movie DB</a></div>
|
||||
<div>
|
||||
<a *ngIf="movie.imdbId" href="https://www.imdb.com/title/tt1727824/{{movie.imdbId}}" target="_blank"
|
||||
mat-raised-button class="imdb-color btn-spacing">IMDb</a></div>
|
||||
<div>
|
||||
<a *ngIf="movie.videos.results.length > 0" mat-raised-button class="btn-blue btn-spacing"
|
||||
(click)="openDialog()">Trailer</a></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row card-spacer">
|
||||
<div class="col-12">
|
||||
<mat-accordion>
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
Recommendations
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer" *ngIf="movie.recommendations.results.length > 0">
|
||||
|
||||
<div class="col-md-2" *ngFor="let r of movie.recommendations.results">
|
||||
<div class="sidebar affixable affix-top preview-poster">
|
||||
<div class="poster">
|
||||
<a [routerLink]="'/details/movie/'+r.id">
|
||||
<img class="real grow" matTooltip="{{r.title}}" src="https://image.tmdb.org/t/p/w300/{{r.poster_path}}"
|
||||
alt="Poster" style="display: block;">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
Similar
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer" *ngIf="movie.similar.results.length > 0">
|
||||
|
||||
<div class="col-md-2" *ngFor="let r of movie.similar.results">
|
||||
<div class="sidebar affixable affix-top preview-poster">
|
||||
<div class="poster ">
|
||||
<a [routerLink]="'/details/movie/'+r.id">
|
||||
<img class="real grow" matTooltip="{{r.title}}" src="https://image.tmdb.org/t/p/w300/{{r.poster_path}}"
|
||||
alt="Poster" style="display: block;">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
Videos
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer" *ngIf="movie.videos.results.length > 0">
|
||||
|
||||
<div class="col-md-6" *ngFor="let video of movie.videos.results">
|
||||
<iframe width="100%" height="315px" [src]="'https://www.youtube.com/embed/' + video.key | safe"
|
||||
frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- THIS IS THE YOUTUBE VIDEOS
|
||||
<div *ngFor="let video of movie.videos.results">
|
||||
<iframe width="560" height="315" [src]="'https://www.youtube.com/embed/' + video.key | safe" frameborder="0"
|
||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div> -->
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -87,9 +87,9 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
#summary-wrapper .summary .container h1 .year,
|
||||
.summary-wrapper .summary .container h1 .year {
|
||||
color: #999;
|
||||
|
||||
.grey-text {
|
||||
color:#999;
|
||||
}
|
||||
|
||||
#summary-wrapper .summary .container h1,
|
||||
|
@ -111,7 +111,7 @@ section {
|
|||
position: relative !important;
|
||||
}
|
||||
|
||||
#info-wrapper .sidebar {
|
||||
#info-wrapper .sidebar-poster {
|
||||
margin-top: -180px;
|
||||
}
|
||||
|
||||
|
@ -148,3 +148,19 @@ section {
|
|||
.btn-spacing {
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.preview-poster {
|
||||
width: 173px;
|
||||
}
|
||||
|
||||
.grow {
|
||||
transition: all .2s ease-in-out;
|
||||
}
|
||||
.grow:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
|
@ -3,6 +3,8 @@ import { ImageService, SearchV2Service } from "../services";
|
|||
import { ActivatedRoute } from "@angular/router";
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
import { ISearchMovieResultV2 } from "../interfaces/ISearchMovieResultV2";
|
||||
import { MatDialog } from "@angular/material";
|
||||
import { MovieDetailsTrailerComponent } from "./movie-details-trailer.component";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./movie-details.component.html",
|
||||
|
@ -13,7 +15,8 @@ export class MovieDetailsComponent {
|
|||
private theMovidDbId: number;
|
||||
|
||||
constructor(private searchService: SearchV2Service, private route: ActivatedRoute,
|
||||
private sanitizer: DomSanitizer, private imageService: ImageService) {
|
||||
private sanitizer: DomSanitizer, private imageService: ImageService,
|
||||
public dialog: MatDialog) {
|
||||
this.route.params.subscribe((params: any) => {
|
||||
this.theMovidDbId = params.movieDbId;
|
||||
this.load();
|
||||
|
@ -23,7 +26,6 @@ export class MovieDetailsComponent {
|
|||
public load() {
|
||||
this.searchService.getFullMovieDetails(this.theMovidDbId).subscribe(x => {
|
||||
this.movie = x;
|
||||
|
||||
this.imageService.getMovieBanner(this.theMovidDbId.toString()).subscribe(x => {
|
||||
this.movie.background = this.sanitizer.bypassSecurityTrustStyle
|
||||
("url(" + x + ")");
|
||||
|
@ -31,4 +33,11 @@ export class MovieDetailsComponent {
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
public openDialog() {
|
||||
this.dialog.open(MovieDetailsTrailerComponent, {
|
||||
width: '560px',
|
||||
data: this.movie
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
12
src/Ombi/ClientApp/src/app/pipes/SafePipe.ts
Normal file
12
src/Ombi/ClientApp/src/app/pipes/SafePipe.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
|
||||
@Pipe({ name: 'safe' })
|
||||
|
||||
export class SafePipe implements PipeTransform {
|
||||
|
||||
constructor(private sanitizer: DomSanitizer) { }
|
||||
transform(url) {
|
||||
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
import { ModuleWithProviders, NgModule } from "@angular/core";
|
||||
import { HumanizePipe } from "./HumanizePipe";
|
||||
import { ThousandShortPipe } from "./ThousandShortPipe";
|
||||
import { SafePipe } from "./SafePipe";
|
||||
|
||||
@NgModule({
|
||||
imports: [],
|
||||
declarations: [HumanizePipe, ThousandShortPipe],
|
||||
exports: [HumanizePipe, ThousandShortPipe],
|
||||
declarations: [HumanizePipe, ThousandShortPipe, SafePipe],
|
||||
exports: [HumanizePipe, ThousandShortPipe, SafePipe],
|
||||
})
|
||||
export class PipeModule {
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Observable } from "rxjs";
|
|||
|
||||
import { IMultiSearchResult, ISearchMovieResult, ISearchTvResult } from "../interfaces";
|
||||
import { ServiceHelpers } from "./service.helpers";
|
||||
+
|
||||
|
||||
import { ISearchMovieResultV2 } from "../interfaces/ISearchMovieResultV2";
|
||||
|
||||
@Injectable()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue