mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-22 06:13:22 -07:00
Almost nailed it
This commit is contained in:
parent
0b7fe0395b
commit
0a72c2ade9
15 changed files with 133 additions and 32 deletions
|
@ -108,7 +108,7 @@ namespace Ombi.Core.Services
|
|||
});
|
||||
}
|
||||
|
||||
return model.OrderByDescending(x => x.RequestDate);
|
||||
return model.OrderByDescending(x => x.ReleaseDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace Ombi.Helpers
|
|||
public const string LidarrRootFolders = nameof(LidarrRootFolders);
|
||||
public const string LidarrQualityProfiles = nameof(LidarrQualityProfiles);
|
||||
public const string FanartTv = nameof(FanartTv);
|
||||
public const string TmdbImages = nameof(TmdbImages);
|
||||
public const string UsersDropdown = nameof(UsersDropdown);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,5 +46,6 @@ namespace Ombi.Api.TheMovieDb
|
|||
Task<List<Language>> GetLanguages(CancellationToken cancellationToken);
|
||||
Task<List<WatchProvidersResults>> SearchWatchProviders(string media, string searchTerm, CancellationToken cancellationToken);
|
||||
Task<List<MovieDbSearchResult>> AdvancedSearch(DiscoverModel model, int page, CancellationToken cancellationToken);
|
||||
Task<TvImages> GetTvImages(string theMovieDbId, CancellationToken token);
|
||||
}
|
||||
}
|
||||
|
|
44
src/Ombi.TheMovieDbApi/Models/TvImages.cs
Normal file
44
src/Ombi.TheMovieDbApi/Models/TvImages.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
namespace Ombi.Api.TheMovieDb.Models
|
||||
{
|
||||
public class TvImages
|
||||
{
|
||||
public Backdrop[] backdrops { get; set; }
|
||||
public int id { get; set; }
|
||||
public Logo[] logos { get; set; }
|
||||
public Poster[] posters { get; set; }
|
||||
}
|
||||
|
||||
public class Backdrop
|
||||
{
|
||||
public float aspect_ratio { get; set; }
|
||||
public int height { get; set; }
|
||||
public string iso_639_1 { get; set; }
|
||||
public string file_path { get; set; }
|
||||
public float vote_average { get; set; }
|
||||
public int vote_count { get; set; }
|
||||
public int width { get; set; }
|
||||
}
|
||||
|
||||
public class Logo
|
||||
{
|
||||
public float aspect_ratio { get; set; }
|
||||
public int height { get; set; }
|
||||
public string iso_639_1 { get; set; }
|
||||
public string file_path { get; set; }
|
||||
public float vote_average { get; set; }
|
||||
public int vote_count { get; set; }
|
||||
public int width { get; set; }
|
||||
}
|
||||
|
||||
public class Poster
|
||||
{
|
||||
public float aspect_ratio { get; set; }
|
||||
public int height { get; set; }
|
||||
public string iso_639_1 { get; set; }
|
||||
public string file_path { get; set; }
|
||||
public float vote_average { get; set; }
|
||||
public int vote_count { get; set; }
|
||||
public int width { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -514,6 +514,14 @@ namespace Ombi.Api.TheMovieDb
|
|||
return Api.Request<WatchProviders>(request, token);
|
||||
}
|
||||
|
||||
public Task<TvImages> GetTvImages(string theMovieDbId, CancellationToken token)
|
||||
{
|
||||
var request = new Request($"tv/{theMovieDbId}/images", BaseUri, HttpMethod.Get);
|
||||
request.AddQueryString("api_key", ApiToken);
|
||||
|
||||
return Api.Request<TvImages>(request, token);
|
||||
}
|
||||
|
||||
private async Task AddDiscoverSettings(Request request)
|
||||
{
|
||||
var settings = await Settings;
|
||||
|
|
|
@ -46,10 +46,10 @@
|
|||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="detailed-container">
|
||||
<div class="detailed-container" (click)="click()" >
|
||||
<div class="row">
|
||||
<div class="col-5 posterColumn">
|
||||
<ombi-image [src]="request.posterPath" [type]="request.requestType" class="poster" alt="{{request.title}}">
|
||||
<ombi-image [src]="request.posterPath" [type]="request.type" class="poster" alt="{{request.title}}">
|
||||
</ombi-image>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
|
|
|
@ -10,10 +10,6 @@
|
|||
|
||||
background-color: $ombi-background-accent;
|
||||
|
||||
.top-spacing {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.overview {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 4;
|
||||
|
@ -22,12 +18,8 @@
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.posterColumn {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
|
||||
::ng-deep .poster {
|
||||
cursor: pointer;
|
||||
border-radius: 10px;
|
||||
opacity: 1;
|
||||
display: block;
|
||||
|
|
|
@ -4,7 +4,6 @@ import { Story, Meta, moduleMetadata } from '@storybook/angular';
|
|||
import { IRecentlyRequested, RequestType } from '../../interfaces';
|
||||
import { DetailedCardComponent } from './detailed-card.component';
|
||||
import { TranslateModule } from "@ngx-translate/core";
|
||||
import { ImageService } from '../../services/image.service';
|
||||
|
||||
// More on default export: https://storybook.js.org/docs/angular/writing-stories/introduction#default-export
|
||||
export default {
|
||||
|
@ -39,13 +38,12 @@ NewMovieRequest.args = {
|
|||
available: false,
|
||||
tvPartiallyAvailable: false,
|
||||
requestDate: new Date(2022, 1, 1),
|
||||
userName: 'John Doe',
|
||||
username: 'John Doe',
|
||||
userId: '12345',
|
||||
requestType: RequestType.movie,
|
||||
type: RequestType.movie,
|
||||
mediaId: '603',
|
||||
overview: 'The Matrix is a movie about a group of people who are forced to fight against a powerful computer system that controls them.',
|
||||
releaseDate: new Date(2020, 1, 1),
|
||||
posterPath: "https://assets.fanart.tv/fanart/movies/603/movieposter/the-matrix-52256ae1021be.jpg"
|
||||
} as IRecentlyRequested,
|
||||
is4kEnabled: false,
|
||||
};
|
|
@ -12,9 +12,8 @@ import { Subject, takeUntil } from "rxjs";
|
|||
})
|
||||
export class DetailedCardComponent implements OnInit, OnDestroy {
|
||||
@Input() public request: IRecentlyRequested;
|
||||
@Input() public is4kEnabled: boolean = false;
|
||||
|
||||
@Output() public onRequest: EventEmitter<boolean> = new EventEmitter<boolean>();
|
||||
@Output() public onClick: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
public RequestType = RequestType;
|
||||
public loading: false;
|
||||
|
@ -25,18 +24,24 @@ import { Subject, takeUntil } from "rxjs";
|
|||
|
||||
ngOnInit(): void {
|
||||
if (!this.request.posterPath) {
|
||||
switch (this.request.type) {
|
||||
case RequestType.movie:
|
||||
this.imageService.getMoviePoster(this.request.mediaId).pipe(takeUntil(this.$imageSub)).subscribe(x => this.request.posterPath = x);
|
||||
break;
|
||||
case RequestType.tvShow:
|
||||
this.imageService.getTmdbTvPoster(Number(this.request.mediaId)).pipe(takeUntil(this.$imageSub)).subscribe(x => this.request.posterPath = `https://image.tmdb.org/t/p/w300${x}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public submitRequest(is4k: boolean) {
|
||||
this.onRequest.emit(is4k);
|
||||
}
|
||||
|
||||
public getStatus(request: IRecentlyRequested) {
|
||||
if (request.available) {
|
||||
return "Common.Available";
|
||||
}
|
||||
if (request.tvPartiallyAvailable) {
|
||||
return "Common.PartiallyAvailable";
|
||||
}
|
||||
if (request.approved) {
|
||||
return "Common.Approved";
|
||||
} else {
|
||||
|
@ -44,8 +49,12 @@ import { Subject, takeUntil } from "rxjs";
|
|||
}
|
||||
}
|
||||
|
||||
public click() {
|
||||
this.onClick.emit();
|
||||
}
|
||||
|
||||
public getClass(request: IRecentlyRequested) {
|
||||
if (request.available) {
|
||||
if (request.available || request.tvPartiallyAvailable) {
|
||||
return "success";
|
||||
}
|
||||
if (request.approved) {
|
||||
|
|
|
@ -28,6 +28,8 @@ import { APP_BASE_HREF } from "@angular/common";
|
|||
private defaultMovie = "/images/default_movie_poster.png";
|
||||
private defaultMusic = "i/mages/default-music-placeholder.png";
|
||||
|
||||
private alreadyErrored = false;
|
||||
|
||||
constructor (@Inject(APP_BASE_HREF) public href: string) {
|
||||
if (this.href.length > 1) {
|
||||
this.baseUrl = this.href;
|
||||
|
@ -35,6 +37,9 @@ import { APP_BASE_HREF } from "@angular/common";
|
|||
}
|
||||
|
||||
public onError(event: any) {
|
||||
if (this.alreadyErrored) {
|
||||
return;
|
||||
}
|
||||
// set to a placeholder
|
||||
switch(this.type) {
|
||||
case RequestType.movie:
|
||||
|
@ -48,10 +53,11 @@ import { APP_BASE_HREF } from "@angular/common";
|
|||
break;
|
||||
}
|
||||
|
||||
this.alreadyErrored = true;
|
||||
// Retry the original image
|
||||
const timeout = setTimeout(() => {
|
||||
event.target.src = this.src;
|
||||
clearTimeout(timeout);
|
||||
event.target.src = this.src;
|
||||
}, Math.floor(Math.random() * (7000 - 1000 + 1)) + 1000);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<p-carousel #carousel [numVisible]="4" [numScroll]="7" [page]="0" [value]="requests" [responsiveOptions]="responsiveOptions">
|
||||
<p-carousel #carousel [numVisible]="10" [numScroll]="10" [page]="0" [value]="requests" [responsiveOptions]="responsiveOptions">
|
||||
<ng-template let-result pTemplate="item">
|
||||
<ombi-detailed-card [request]="result"></ombi-detailed-card>
|
||||
<ombi-detailed-card [request]="result" (onClick)="navigate(result)"></ombi-detailed-card>
|
||||
</ng-template>
|
||||
</p-carousel>
|
|
@ -9,6 +9,7 @@ import { FeaturesFacade } from "../../../state/features/features.facade";
|
|||
import { ResponsiveOptions } from "../carousel.options";
|
||||
import { RequestServiceV2 } from "app/services/requestV2.service";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
export enum DiscoverType {
|
||||
Upcoming,
|
||||
|
@ -41,7 +42,8 @@ export class RecentlyRequestedListComponent implements OnInit, OnDestroy {
|
|||
private $loadSub = new Subject<void>();
|
||||
|
||||
constructor(private requestService: RequestServiceV2,
|
||||
private featureFacade: FeaturesFacade) {
|
||||
private featureFacade: FeaturesFacade,
|
||||
private router: Router) {
|
||||
Carousel.prototype.onTouchMove = () => {},
|
||||
this.responsiveOptions = ResponsiveOptions;
|
||||
}
|
||||
|
@ -53,11 +55,25 @@ export class RecentlyRequestedListComponent implements OnInit, OnDestroy {
|
|||
|
||||
public ngOnInit() {
|
||||
this.loading();
|
||||
this.loadData(false);
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
public navigate(request: IRecentlyRequested) {
|
||||
this.router.navigate([this.generateDetailsLink(request), request.mediaId]);
|
||||
}
|
||||
|
||||
private loadData(clearExisting: boolean = true) {
|
||||
private generateDetailsLink(request: IRecentlyRequested): string {
|
||||
switch (request.type) {
|
||||
case RequestType.movie:
|
||||
return `/details/movie/`;
|
||||
case RequestType.tvShow:
|
||||
return `/details/tv/`;
|
||||
case RequestType.album: //Actually artist
|
||||
return `/details/artist/`;
|
||||
}
|
||||
}
|
||||
|
||||
private loadData() {
|
||||
this.requestService.getRecentlyRequested().pipe(takeUntil(this.$loadSub)).subscribe(x => {
|
||||
this.requests = x;
|
||||
this.finishLoading();
|
||||
|
|
|
@ -2,7 +2,6 @@ import { RequestType } from "./IRequestModel";
|
|||
|
||||
export interface IRecentlyRequested {
|
||||
requestId: number;
|
||||
requestType: RequestType;
|
||||
userId: string;
|
||||
username: string;
|
||||
available: boolean;
|
||||
|
@ -13,6 +12,7 @@ export interface IRecentlyRequested {
|
|||
releaseDate: Date;
|
||||
approved: boolean;
|
||||
mediaId: string;
|
||||
type: RequestType;
|
||||
|
||||
posterPath: string;
|
||||
}
|
|
@ -33,6 +33,10 @@ export class ImageService extends ServiceHelpers {
|
|||
return this.http.get<string>(`${this.url}poster/tv/${tvdbid}`, { headers: this.headers });
|
||||
}
|
||||
|
||||
public getTmdbTvPoster(tvdbid: number): Observable<string> {
|
||||
return this.http.get<string>(`${this.url}poster/tv/tmdb/${tvdbid}`, { headers: this.headers });
|
||||
}
|
||||
|
||||
public getMovieBackground(movieDbId: string): Observable<string> {
|
||||
return this.http.get<string>(`${this.url}background/movie/${movieDbId}`, { headers: this.headers });
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Ombi.Api.FanartTv;
|
||||
using Ombi.Api.TheMovieDb;
|
||||
using Ombi.Config;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Engine.Interfaces;
|
||||
|
@ -17,11 +19,12 @@ namespace Ombi.Controllers.V1
|
|||
[ApiController]
|
||||
public class ImagesController : ControllerBase
|
||||
{
|
||||
public ImagesController(IFanartTvApi fanartTvApi, IApplicationConfigRepository config,
|
||||
public ImagesController(IFanartTvApi fanartTvApi, IMovieDbApi movieDbApi, IApplicationConfigRepository config,
|
||||
IOptions<LandingPageBackground> options, ICacheService c, IImageService imageService,
|
||||
IMovieEngineV2 movieEngineV2, ITVSearchEngineV2 tVSearchEngineV2)
|
||||
{
|
||||
FanartTvApi = fanartTvApi;
|
||||
_movieDbApi = movieDbApi;
|
||||
Config = config;
|
||||
Options = options.Value;
|
||||
_cache = c;
|
||||
|
@ -33,6 +36,8 @@ namespace Ombi.Controllers.V1
|
|||
private IFanartTvApi FanartTvApi { get; }
|
||||
private IApplicationConfigRepository Config { get; }
|
||||
private LandingPageBackground Options { get; }
|
||||
|
||||
private readonly IMovieDbApi _movieDbApi;
|
||||
private readonly ICacheService _cache;
|
||||
private readonly IImageService _imageService;
|
||||
private readonly IMovieEngineV2 _movieEngineV2;
|
||||
|
@ -175,6 +180,23 @@ namespace Ombi.Controllers.V1
|
|||
return string.Empty;
|
||||
}
|
||||
|
||||
[HttpGet("poster/tv/tmdb/{tmdbId}")]
|
||||
public async Task<string> GetTmdbTvPoster(string tmdbId)
|
||||
{
|
||||
var images = await _cache.GetOrAddAsync($"{CacheKeys.TmdbImages}tv{tmdbId}", () => _movieDbApi.GetTvImages(tmdbId, HttpContext.RequestAborted), DateTimeOffset.Now.AddDays(1));
|
||||
|
||||
if (images?.posters?.Any() ?? false)
|
||||
{
|
||||
return images.posters.Select(x => x.file_path).FirstOrDefault();
|
||||
}
|
||||
|
||||
if (images?.backdrops?.Any() ?? false)
|
||||
{
|
||||
return images.backdrops.Select(x => x.file_path).FirstOrDefault();
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
[HttpGet("background/movie/{movieDbId}")]
|
||||
public async Task<string> GetMovieBackground(string movieDbId)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue