mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 21:33:15 -07:00
feat: add crew on movie page (#4722)
* add crew on movie page * order by director, add default image and fix click Co-authored-by: tidusjar <tidusjar@gmail.com>
This commit is contained in:
parent
2f5d54c5bf
commit
1d53261382
12 changed files with 214 additions and 7 deletions
6
src/.idea/.idea.Ombi/.idea/contentModel.xml
generated
6
src/.idea/.idea.Ombi/.idea/contentModel.xml
generated
|
@ -268,6 +268,12 @@
|
|||
<e p="cast-carousel.component.scss" t="Include" />
|
||||
<e p="cast-carousel.component.ts" t="Include" />
|
||||
</e>
|
||||
<e p="crew-carousel" t="Include">
|
||||
<e p="crew-carousel.component.html" t="Include" />
|
||||
<e p="crew-carousel.component.scss" t="Include" />
|
||||
<e p="crew-carousel.component.ts" t="Include" />
|
||||
</e>
|
||||
|
||||
<e p="deny-dialog" t="Include">
|
||||
<e p="deny-dialog.component.html" t="Include" />
|
||||
<e p="deny-dialog.component.ts" t="Include" />
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { SearchV2Service } from "../../../services";
|
||||
import { IActorCredits, IActorCast } from "../../../interfaces/ISearchTvResultV2";
|
||||
import { IActorCredits, IActorCast, IActorCrew } from "../../../interfaces/ISearchTvResultV2";
|
||||
import { IDiscoverCardResult } from "../../interfaces";
|
||||
import { RequestType } from "../../../interfaces";
|
||||
import { AuthService } from "../../../auth/auth.service";
|
||||
|
@ -38,13 +38,13 @@ export class DiscoverActorComponent implements OnInit {
|
|||
this.searchService.getMoviesByActor(this.actorId),
|
||||
this.searchService.getTvByActor(this.actorId)
|
||||
]).subscribe(([movie, tv]) => {
|
||||
this.pushDiscoverResults(movie.cast, RequestType.movie);
|
||||
this.pushDiscoverResults(tv.cast, RequestType.tvShow);
|
||||
this.pushDiscoverResults(movie.crew, movie.cast, RequestType.movie);
|
||||
this.pushDiscoverResults(tv.crew, tv.cast, RequestType.tvShow);
|
||||
this.finishLoading();
|
||||
});
|
||||
}
|
||||
|
||||
pushDiscoverResults(cast: IActorCast[], type: RequestType) {
|
||||
pushDiscoverResults(crew: IActorCrew[], cast: IActorCast[], type: RequestType) {
|
||||
cast.forEach(m => {
|
||||
this.discoverResults.push({
|
||||
available: false,
|
||||
|
@ -62,6 +62,23 @@ export class DiscoverActorComponent implements OnInit {
|
|||
background: ""
|
||||
});
|
||||
});
|
||||
crew.forEach(m => {
|
||||
this.discoverResults.push({
|
||||
available: false,
|
||||
posterPath: m.poster_path ? `https://image.tmdb.org/t/p/w300/${m.poster_path}` : "../../../images/default_movie_poster.png",
|
||||
requested: false,
|
||||
title: m.title,
|
||||
type: type,
|
||||
id: m.id,
|
||||
url: null,
|
||||
rating: 0,
|
||||
overview: m.overview,
|
||||
approved: false,
|
||||
imdbid: "",
|
||||
denied: false,
|
||||
background: ""
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private loading() {
|
||||
|
|
|
@ -4,6 +4,7 @@ import { ArtistDetailsComponent } from "./artist/artist-details.component";
|
|||
import { ArtistInformationPanel } from "./artist/panels/artist-information-panel/artist-information-panel.component";
|
||||
import { ArtistReleasePanel } from "./artist/panels/artist-release-panel/artist-release-panel.component";
|
||||
import { CastCarouselComponent } from "./shared/cast-carousel/cast-carousel.component";
|
||||
import { CrewCarouselComponent } from "./shared/crew-carousel/crew-carousel.component";
|
||||
import { DenyDialogComponent } from "./shared/deny-dialog/deny-dialog.component";
|
||||
import { IssuesPanelComponent } from "./shared/issues-panel/issues-panel.component";
|
||||
import { MediaPosterComponent } from "./shared/media-poster/media-poster.component";
|
||||
|
@ -32,6 +33,7 @@ export const components: any[] = [
|
|||
SocialIconsComponent,
|
||||
MediaPosterComponent,
|
||||
CastCarouselComponent,
|
||||
CrewCarouselComponent,
|
||||
DenyDialogComponent,
|
||||
TvRequestsPanelComponent,
|
||||
MovieAdvancedOptionsComponent,
|
||||
|
|
|
@ -204,6 +204,12 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<crew-carousel [crew]="movie.credits.crew"></crew-carousel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="row card-spacer" *ngIf="movie.videos?.results?.length > 0">
|
||||
|
||||
<div class="col-md-6" *ngFor="let video of movie.videos?.results">
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Component, OnInit, ViewEncapsulation } from "@angular/core";
|
|||
import { ImageService, SearchV2Service, RequestService, MessageService, RadarrService, SettingsStateService } from "../../../services";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
import { ISearchMovieResultV2 } from "../../../interfaces/ISearchMovieResultV2";
|
||||
import { ICrewViewModel, ISearchMovieResultV2 } from "../../../interfaces/ISearchMovieResultV2";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { YoutubeTrailerComponent } from "../shared/youtube-trailer.component";
|
||||
import { AuthService } from "../../../auth/auth.service";
|
||||
|
@ -82,6 +82,7 @@ export class MovieDetailsComponent implements OnInit{
|
|||
this.searchService.getMovieByImdbId(this.imdbId).subscribe(async x => {
|
||||
this.movie = x;
|
||||
this.checkPoster();
|
||||
this.movie.credits.crew = this.orderCrew(this.movie.credits.crew);
|
||||
if (this.movie.requestId > 0) {
|
||||
// Load up this request
|
||||
this.hasRequest = true;
|
||||
|
@ -93,6 +94,7 @@ export class MovieDetailsComponent implements OnInit{
|
|||
this.searchService.getFullMovieDetails(this.theMovidDbId).subscribe(async x => {
|
||||
this.movie = x;
|
||||
this.checkPoster();
|
||||
this.movie.credits.crew = this.orderCrew(this.movie.credits.crew);
|
||||
if (this.movie.requestId > 0) {
|
||||
// Load up this request
|
||||
this.hasRequest = true;
|
||||
|
@ -319,4 +321,16 @@ export class MovieDetailsComponent implements OnInit{
|
|||
|
||||
});
|
||||
}
|
||||
|
||||
private orderCrew(crew: ICrewViewModel[]): ICrewViewModel[] {
|
||||
return crew.sort((a, b) => {
|
||||
if (a.job === "Director") {
|
||||
return -1;
|
||||
} else if (b.job === "Director") {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<a *ngIf="item.profile_path" [routerLink]="'/discover/actor/' + item.id">
|
||||
<ombi-image class="cast-profile-img" src="https://image.tmdb.org/t/p/w300{{item.profile_path}}"></ombi-image>
|
||||
</a>
|
||||
<!-- TODO get profile image default -->
|
||||
<i *ngIf="!item.image && !item.profile_path" class="fa-solid fa-user-large fa-2xl crew-profile-img" aria-hidden="true"></i>
|
||||
|
||||
</div>
|
||||
<div class="col-12">
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<mat-card class="mat-elevation-z8 spacing-below">
|
||||
<mat-card-header>{{'MediaDetails.Crews.CrewTitle' | translate}}</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p-carousel [value]="crew" easing="easeOutStrong" [responsiveOptions]="responsiveOptions" [numVisible]="5" >
|
||||
<ng-template let-item pTemplate="item">
|
||||
<div class="row justify-content-md-center mat-card mat-card-flat carousel-item">
|
||||
<div [routerLink]="'/discover/actor/' + item.id" class="bottom-space link">
|
||||
<a *ngIf="item.image">
|
||||
<img class="crew-profile-img" src="https://image.tmdb.org/t/p/w300{{item.image}}">
|
||||
</a>
|
||||
<a *ngIf="item.profile_path">
|
||||
<img class="crew-profile-img" src="https://image.tmdb.org/t/p/w300{{item.profile_path}}">
|
||||
</a>
|
||||
<i *ngIf="!item.image && !item.profile_path" class="fa-solid fa-user-large fa-2xl crew-profile-img" aria-hidden="true"></i>
|
||||
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<span *ngIf="item.name"><strong>{{item.name}}</strong></span>
|
||||
<span *ngIf="item.person"><strong>{{item.person}}</strong></span>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<span *ngIf="item.job"><small>{{item.job}}</small></span>
|
||||
<span *ngIf="item.department"><small>{{item.position}}</small></span>
|
||||
<span *ngIf="item.title"><small>{{item.title}}</small></span>
|
||||
<span *ngIf="item.overview"><small>{{item.overview}}</small></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</ng-template>
|
||||
</p-carousel>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
|
@ -0,0 +1,87 @@
|
|||
@import "~@angular/material/theming";
|
||||
@import "~styles/variables.scss";
|
||||
::ng-deep body .ui-carousel .ui-carousel-content .ui-carousel-prev,
|
||||
body .ui-carousel .ui-carousel-content .ui-carousel-next {
|
||||
background-color: #ffffff;
|
||||
border: solid 1px rgba(178, 193, 205, 0.64);
|
||||
-moz-border-radius: 50%;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
margin: 0.2em;
|
||||
color: #333333;
|
||||
-moz-transition: color 0.2s;
|
||||
-o-transition: color 0.2s;
|
||||
-webkit-transition: color 0.2s;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
::ng-deep body .ui-carousel .ui-carousel-content .ui-carousel-prev:not(.ui-state-disabled):hover,
|
||||
body .ui-carousel .ui-carousel-content .ui-carousel-next:not(.ui-state-disabled):hover {
|
||||
background-color: #ffffff;
|
||||
color: #000;
|
||||
border-color: solid 1px rgba(178, 193, 205, 0.64);
|
||||
}
|
||||
|
||||
::ng-deep body .ui-carousel .ui-carousel-dots-container .ui-carousel-dot-item>.ui-button {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
::ng-deep body .ui-carousel .ui-carousel-dots-container .ui-carousel-dot-item .ui-carousel-dot-icon {
|
||||
width: 20px;
|
||||
height: 6px;
|
||||
background-color: rgba(255, 255, 255, 0.44);
|
||||
margin: 0 0.2em;
|
||||
}
|
||||
|
||||
::ng-deep body .ui-carousel .ui-carousel-dots-container .ui-carousel-dot-item .ui-carousel-dot-icon::before {
|
||||
content: " ";
|
||||
}
|
||||
|
||||
::ng-deep body .ui-carousel .ui-carousel-dots-container .ui-carousel-dot-item.ui-state-highlight .ui-carousel-dot-icon {
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.carousel-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
::ng-deep .ui-carousel-next {
|
||||
background-color: #ffffff;
|
||||
border: solid 1px rgba(178, 193, 205, 0.64);
|
||||
border-radius: 50%;
|
||||
margin: 0.2em;
|
||||
color: #333333;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
::ng-deep .ui-carousel-content button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.bottom-space {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
@media (min-width: 979px) {
|
||||
|
||||
.crew-profile-img {
|
||||
border-radius: 100%;
|
||||
width: 200px;
|
||||
max-height: 200px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
@media (max-width: 978px) {
|
||||
|
||||
.crew-profile-img {
|
||||
border-radius: 100%;
|
||||
width: 100px;
|
||||
max-height: 100px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
cursor: pointer;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { Component, Input } from "@angular/core";
|
||||
|
||||
@Component({
|
||||
selector: "crew-carousel",
|
||||
templateUrl: "./crew-carousel.component.html",
|
||||
styleUrls: ["./crew-carousel.component.scss"]
|
||||
})
|
||||
export class CrewCarouselComponent {
|
||||
|
||||
constructor() {
|
||||
this.responsiveOptions = [
|
||||
{
|
||||
breakpoint: '1024px',
|
||||
numVisible: 5,
|
||||
numScroll: 5
|
||||
},
|
||||
{
|
||||
breakpoint: '768px',
|
||||
numVisible: 3,
|
||||
numScroll: 3
|
||||
},
|
||||
{
|
||||
breakpoint: '560px',
|
||||
numVisible: 1,
|
||||
numScroll: 1
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@Input() crew: any[];
|
||||
public responsiveOptions: any[];
|
||||
}
|
|
@ -181,6 +181,11 @@
|
|||
}
|
||||
|
||||
|
||||
.crew-profile-img {
|
||||
border-radius: 100%;
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
|
||||
.small-middle-container {
|
||||
margin: auto;
|
||||
|
|
|
@ -364,6 +364,9 @@
|
|||
"Casts": {
|
||||
"CastTitle": "Cast"
|
||||
},
|
||||
"Crews": {
|
||||
"CrewTitle": "Crew"
|
||||
},
|
||||
"EpisodeSelector": {
|
||||
"AllSeasonsTooltip": "This will request every season for this show",
|
||||
"FirstSeasonTooltip": "This will only request the First Season for this show",
|
||||
|
|
|
@ -364,6 +364,9 @@
|
|||
"Casts": {
|
||||
"CastTitle": "Casting"
|
||||
},
|
||||
"Crews": {
|
||||
"CrewTitle": "Equipe"
|
||||
},
|
||||
"EpisodeSelector": {
|
||||
"AllSeasonsTooltip": "Cette action demandera toutes les saisons de cette série",
|
||||
"FirstSeasonTooltip": "Cette action ne demandera que la Première Saison de cette série",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue