From 363b30d96ba2dd16a79cfd79cbf6d5da7da1e91a Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 14 Sep 2022 12:44:48 +0100 Subject: [PATCH] feat(discover): :zap: Images for the recently requested area are now loading faster and just better all around --- .../Services/RecentlyRequestedServiceTests.cs | 9 ++-- .../Models/Requests/RecentlyRequestedModel.cs | 3 ++ .../Services/RecentlyRequestedService.cs | 47 +++++++++++++++++-- src/Ombi.TheMovieDbApi/IMovieDbApi.cs | 3 +- src/Ombi.TheMovieDbApi/Models/TvImages.cs | 2 +- src/Ombi.TheMovieDbApi/TheMovieDbApi.cs | 14 ++++-- .../detailed-card/detailed-card.component.ts | 35 ++++++++------ .../src/app/interfaces/IRecentlyRequested.ts | 1 + 8 files changed, 84 insertions(+), 30 deletions(-) diff --git a/src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs b/src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs index c3a9cbcdd..fd67e4e33 100644 --- a/src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs +++ b/src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs @@ -37,6 +37,9 @@ namespace Ombi.Core.Tests.Services .ForEach(b => _fixture.Behaviors.Remove(b)); _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); _mocker = new AutoMocker(); + + _mocker.Setup>(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "test", Alias = "alias", Language = "en" }); + _mocker.Setup(x => x.Username).Returns("test"); _subject = _mocker.CreateInstance(); } @@ -70,8 +73,6 @@ namespace Ombi.Core.Tests.Services _mocker.Setup>(x => x.GetAll()).Returns(movies.AsQueryable().BuildMock().Object); _mocker.Setup>(x => x.GetAll()).Returns(albums.AsQueryable().BuildMock().Object); _mocker.Setup>(x => x.GetChild()).Returns(chilRequests.AsQueryable().BuildMock().Object); - _mocker.Setup>(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "test", Alias = "alias" }); - _mocker.Setup(x => x.Username).Returns("test"); var result = await _subject.GetRecentlyRequested(CancellationToken.None); @@ -134,8 +135,6 @@ namespace Ombi.Core.Tests.Services _mocker.Setup>(x => x.GetAll()).Returns(movies.AsQueryable().BuildMock().Object); _mocker.Setup>(x => x.GetAll()).Returns(albums.AsQueryable().BuildMock().Object); _mocker.Setup>(x => x.GetChild()).Returns(chilRequests.AsQueryable().BuildMock().Object); - _mocker.Setup>(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "test", Alias = "alias" }); - _mocker.Setup(x => x.Username).Returns("test"); var result = await _subject.GetRecentlyRequested(CancellationToken.None); @@ -167,8 +166,6 @@ namespace Ombi.Core.Tests.Services _mocker.Setup>(x => x.GetAll()).Returns(movies.AsQueryable().BuildMock().Object); _mocker.Setup>(x => x.GetAll()).Returns(albums.AsQueryable().BuildMock().Object); _mocker.Setup>(x => x.GetChild()).Returns(chilRequests.AsQueryable().BuildMock().Object); - _mocker.Setup>(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "test", Alias = "alias" }); - _mocker.Setup(x => x.Username).Returns("test"); var result = await _subject.GetRecentlyRequested(CancellationToken.None); diff --git a/src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs b/src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs index cf5716436..4296c2cc1 100644 --- a/src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs +++ b/src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs @@ -17,5 +17,8 @@ namespace Ombi.Core.Models.Requests public DateTime ReleaseDate { get; set; } public bool Approved { get; set; } public string MediaId { get; set; } + + public string PosterPath { get; set; } + public string Background { get; set; } } } diff --git a/src/Ombi.Core/Services/RecentlyRequestedService.cs b/src/Ombi.Core/Services/RecentlyRequestedService.cs index 2c5b2f43b..1c67472d4 100644 --- a/src/Ombi.Core/Services/RecentlyRequestedService.cs +++ b/src/Ombi.Core/Services/RecentlyRequestedService.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Ombi.Api.TheMovieDb; using Ombi.Core.Authentication; using Ombi.Core.Engine.Interfaces; using Ombi.Core.Helpers; @@ -12,7 +13,6 @@ using Ombi.Store.Repository.Requests; using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using static Ombi.Core.Engine.BaseMediaEngine; @@ -26,7 +26,8 @@ namespace Ombi.Core.Services private readonly IMusicRequestRepository _musicRequestRepository; private readonly ISettingsService _customizationSettings; private readonly ISettingsService _ombiSettings; - + private readonly IMovieDbApi _movieDbApi; + private readonly ICacheService _cache; private const int AmountToTake = 7; public RecentlyRequestedService( @@ -37,13 +38,17 @@ namespace Ombi.Core.Services ISettingsService ombiSettings, ICurrentUser user, OmbiUserManager um, - IRuleEvaluator rules) : base(user, um, rules) + IRuleEvaluator rules, + IMovieDbApi movieDbApi, + ICacheService cache) : base(user, um, rules) { _movieRequestRepository = movieRequestRepository; _tvRequestRepository = tvRequestRepository; _musicRequestRepository = musicRequestRepository; _customizationSettings = customizationSettings; _ombiSettings = ombiSettings; + _movieDbApi = movieDbApi; + _cache = cache; } public async Task> GetRecentlyRequested(CancellationToken cancellationToken) @@ -65,8 +70,10 @@ namespace Ombi.Core.Services var model = new List(); + var lang = await DefaultLanguageCode(); foreach (var item in await recentMovieRequests.ToListAsync(cancellationToken)) { + var images = await _cache.GetOrAddAsync($"{CacheKeys.TmdbImages}movie{item.TheMovieDbId}", () => _movieDbApi.GetMovieImages(item.TheMovieDbId.ToString(), cancellationToken), DateTimeOffset.Now.AddDays(1)); model.Add(new RecentlyRequestedModel { RequestId = item.Id, @@ -80,6 +87,8 @@ namespace Ombi.Core.Services UserId = hideUsers.Hide ? string.Empty : item.RequestedUserId, Username = hideUsers.Hide ? string.Empty : item.RequestedUser.UserAlias, MediaId = item.TheMovieDbId.ToString(), + PosterPath = images?.posters?.Where(x => lang.Equals(x?.iso_639_1, StringComparison.InvariantCultureIgnoreCase))?.OrderByDescending(x => x.vote_count)?.Select(x => x.file_path)?.FirstOrDefault(), + Background = images?.backdrops?.Where(x => lang.Equals(x?.iso_639_1, StringComparison.InvariantCultureIgnoreCase))?.OrderByDescending(x => x.vote_count)?.Select(x => x.file_path)?.FirstOrDefault(), }); } @@ -103,6 +112,9 @@ namespace Ombi.Core.Services foreach (var item in await recentTvRequests.ToListAsync(cancellationToken)) { + var providerId = item.ParentRequest.ExternalProviderId.ToString(); + var images = await _cache.GetOrAddAsync($"{CacheKeys.TmdbImages}tv{providerId}", () => _movieDbApi.GetTvImages(providerId.ToString(), cancellationToken), DateTimeOffset.Now.AddDays(1)); + var partialAvailability = item.SeasonRequests.SelectMany(x => x.Episodes).Any(e => e.Available); model.Add(new RecentlyRequestedModel { @@ -117,7 +129,9 @@ namespace Ombi.Core.Services Type = RequestType.TvShow, UserId = hideUsers.Hide ? string.Empty : item.RequestedUserId, Username = hideUsers.Hide ? string.Empty : item.RequestedUser.UserAlias, - MediaId = item.ParentRequest.ExternalProviderId.ToString() + MediaId = providerId.ToString(), + PosterPath = images?.posters?.Where(x => lang.Equals(x?.iso_639_1, StringComparison.InvariantCultureIgnoreCase))?.OrderByDescending(x => x.vote_count)?.Select(x => x.file_path)?.FirstOrDefault(), + Background = images?.backdrops?.Where(x => lang.Equals(x?.iso_639_1, StringComparison.InvariantCultureIgnoreCase))?.OrderByDescending(x => x.vote_count)?.Select(x => x.file_path)?.FirstOrDefault(), }); } @@ -134,7 +148,7 @@ namespace Ombi.Core.Services UserId = user.Id }; } - var settings = await _ombiSettings.GetSettingsAsync(); + var settings = await GetOmbiSettings(); var result = new HideResult { Hide = settings.HideRequestsUsers, @@ -142,5 +156,28 @@ namespace Ombi.Core.Services }; return result; } + protected async Task DefaultLanguageCode() + { + var user = await GetUser(); + if (user == null) + { + return "en"; + } + + if (string.IsNullOrEmpty(user.Language)) + { + var s = await GetOmbiSettings(); + return s.DefaultLanguageCode; + } + + return user.Language; + } + + + private OmbiSettings ombiSettings; + protected async Task GetOmbiSettings() + { + return ombiSettings ??= await _ombiSettings.GetSettingsAsync(); + } } } diff --git a/src/Ombi.TheMovieDbApi/IMovieDbApi.cs b/src/Ombi.TheMovieDbApi/IMovieDbApi.cs index 44dea2656..74f420d39 100644 --- a/src/Ombi.TheMovieDbApi/IMovieDbApi.cs +++ b/src/Ombi.TheMovieDbApi/IMovieDbApi.cs @@ -46,6 +46,7 @@ namespace Ombi.Api.TheMovieDb Task> GetLanguages(CancellationToken cancellationToken); Task> SearchWatchProviders(string media, string searchTerm, CancellationToken cancellationToken); Task> AdvancedSearch(DiscoverModel model, int page, CancellationToken cancellationToken); - Task GetTvImages(string theMovieDbId, CancellationToken token); + Task GetTvImages(string theMovieDbId, CancellationToken token); + Task GetMovieImages(string theMovieDbId, CancellationToken token); } } diff --git a/src/Ombi.TheMovieDbApi/Models/TvImages.cs b/src/Ombi.TheMovieDbApi/Models/TvImages.cs index 2a235d10d..c87c94ce8 100644 --- a/src/Ombi.TheMovieDbApi/Models/TvImages.cs +++ b/src/Ombi.TheMovieDbApi/Models/TvImages.cs @@ -1,6 +1,6 @@ namespace Ombi.Api.TheMovieDb.Models { - public class TvImages + public class MovieDbImages { public Backdrop[] backdrops { get; set; } public int id { get; set; } diff --git a/src/Ombi.TheMovieDbApi/TheMovieDbApi.cs b/src/Ombi.TheMovieDbApi/TheMovieDbApi.cs index 0db03fef3..b54057c4a 100644 --- a/src/Ombi.TheMovieDbApi/TheMovieDbApi.cs +++ b/src/Ombi.TheMovieDbApi/TheMovieDbApi.cs @@ -514,12 +514,20 @@ namespace Ombi.Api.TheMovieDb return Api.Request(request, token); } - public Task GetTvImages(string theMovieDbId, CancellationToken token) + public Task GetTvImages(string theMovieDbId, CancellationToken token) { var request = new Request($"tv/{theMovieDbId}/images", BaseUri, HttpMethod.Get); request.AddQueryString("api_key", ApiToken); - - return Api.Request(request, token); + + return Api.Request(request, token); + } + + public Task GetMovieImages(string theMovieDbId, CancellationToken token) + { + var request = new Request($"movie/{theMovieDbId}/images", BaseUri, HttpMethod.Get); + request.AddQueryString("api_key", ApiToken); + + return Api.Request(request, token); } private async Task AddDiscoverSettings(Request request) diff --git a/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.ts b/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.ts index 3b3794190..b0e313ee5 100644 --- a/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.ts +++ b/src/Ombi/ClientApp/src/app/components/detailed-card/detailed-card.component.ts @@ -27,20 +27,10 @@ import { DomSanitizer, SafeStyle } from "@angular/platform-browser"; 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); - this.imageService.getMovieBackground(this.request.mediaId).pipe(takeUntil(this.$imageSub)).subscribe(x => { - this.background = this.sanitizer.bypassSecurityTrustStyle("linear-gradient(rgba(0,0,0,.5), rgba(0,0,0,.5)), url(" + 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}`); - this.imageService.getTmdbTvBackground(Number(this.request.mediaId)).pipe(takeUntil(this.$imageSub)).subscribe(x => { - this.background = this.sanitizer.bypassSecurityTrustStyle("linear-gradient(rgba(0,0,0,.5), rgba(0,0,0,.5)), url(https://image.tmdb.org/t/p/w300" + x + ")"); - }); - break; - } + this.loadImages(); + } else { + this.request.posterPath = `https://image.tmdb.org/t/p/w300${this.request.posterPath}`; + this.background = this.sanitizer.bypassSecurityTrustStyle("linear-gradient(rgba(0,0,0,.5), rgba(0,0,0,.5)), url(https://image.tmdb.org/t/p/w300" + this.request.background + ")"); } } @@ -82,4 +72,21 @@ import { DomSanitizer, SafeStyle } from "@angular/platform-browser"; this.$imageSub.complete(); } + private loadImages() { + switch (this.request.type) { + case RequestType.movie: + this.imageService.getMoviePoster(this.request.mediaId).pipe(takeUntil(this.$imageSub)).subscribe(x => this.request.posterPath = x); + this.imageService.getMovieBackground(this.request.mediaId).pipe(takeUntil(this.$imageSub)).subscribe(x => { + this.background = this.sanitizer.bypassSecurityTrustStyle("linear-gradient(rgba(0,0,0,.5), rgba(0,0,0,.5)), url(" + 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}`); + this.imageService.getTmdbTvBackground(Number(this.request.mediaId)).pipe(takeUntil(this.$imageSub)).subscribe(x => { + this.background = this.sanitizer.bypassSecurityTrustStyle("linear-gradient(rgba(0,0,0,.5), rgba(0,0,0,.5)), url(https://image.tmdb.org/t/p/w300" + x + ")"); + }); + break; + } + } + } \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/interfaces/IRecentlyRequested.ts b/src/Ombi/ClientApp/src/app/interfaces/IRecentlyRequested.ts index 420c8c6a7..9cd5dc76e 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/IRecentlyRequested.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/IRecentlyRequested.ts @@ -15,4 +15,5 @@ export interface IRecentlyRequested { type: RequestType; posterPath: string; + background: string; } \ No newline at end of file