Added Rotten Tomatoes ratings to the detail pages

pull/3970/head
tidusjar 4 years ago
parent fde93d2445
commit cb127f3858

@ -0,0 +1,14 @@
using Ombi.Api.RottenTomatoes.Models;
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Ombi.Api.RottenTomatoes
{
public interface IRottenTomatoesApi
{
Task<MovieRatings> GetMovieRatings(string movieName, int movieYear);
Task<TvRatings> GetTvRatings(string showName, int showYear);
}
}

@ -0,0 +1,35 @@
using System.Collections.Generic;
namespace Ombi.Api.RottenTomatoes.Models
{
public class RottenTomatoesMovieResponse
{
public int total { get; set; }
public List<Movie> movies { get; set; }
}
public class Movie
{
public string id { get; set; }
public string title { get; set; }
public int year { get; set; }
public string mpaa_rating { get; set; }
public object runtime { get; set; }
public string critics_consensus { get; set; }
public MovieRatings ratings { get; set; }
public Links links { get; set; }
}
public class MovieRatings
{
public string critics_rating { get; set; }
public int critics_score { get; set; }
public string audience_rating { get; set; }
public int audience_score { get; set; }
}
public class Links
{
public string alternate { get; set; }
}
}

@ -0,0 +1,20 @@
namespace Ombi.Api.RottenTomatoes.Models
{
public class RottenTomatoesTvResponse
{
public int tvCount { get; set; }
public TvSeries[] tvSeries { get; set; }
}
public class TvSeries
{
public string title { get; set; }
public int startYear { get; set; }
public int endYear { get; set; }
public string url { get; set; }
public string meterClass { get; set; }
public int meterScore { get; set; }
public string image { get; set; }
}
}

@ -0,0 +1,8 @@
namespace Ombi.Api.RottenTomatoes.Models
{
public class TvRatings
{
public string Class { get; set; }
public int Score { get; set; }
}
}

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,56 @@
using Ombi.Api.RottenTomatoes.Models;
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Ombi.Api.RottenTomatoes
{
public class RottenTomatoesApi : IRottenTomatoesApi
{
public RottenTomatoesApi(IApi api)
{
_api = api;
}
private string Endpoint => "https://www.rottentomatoes.com/api/private";
private IApi _api { get; }
public async Task<MovieRatings> GetMovieRatings(string movieName, int movieYear)
{
var request = new Request("/v1.0/movies", Endpoint, HttpMethod.Get);
request.AddHeader("Accept", "application/json");
request.AddQueryString("q", movieName);
var result = await _api.Request<RottenTomatoesMovieResponse>(request);
var movieFound = result.movies.FirstOrDefault(x => x.year == movieYear);
if (movieFound == null)
{
return null;
}
return movieFound.ratings;
}
public async Task<TvRatings> GetTvRatings(string showName, int showYear)
{
var request = new Request("/v2.0/search/", Endpoint, HttpMethod.Get);
request.AddHeader("Accept", "application/json");
request.AddQueryString("q", showName);
request.AddQueryString("limit", 10.ToString());
var result = await _api.Request<RottenTomatoesTvResponse>(request);
var showFound = result.tvSeries.FirstOrDefault(x => x.startYear == showYear);
if (showFound == null)
{
return null;
}
return new TvRatings
{
Class = showFound.meterClass,
Score = showFound.meterScore
};
}
}
}

@ -67,6 +67,7 @@ using Quartz.Spi;
using Ombi.Api.MusicBrainz;
using Ombi.Api.Twilio;
using Ombi.Api.CloudService;
using Ombi.Api.RottenTomatoes;
namespace Ombi.DependencyInjection
{
@ -158,6 +159,7 @@ namespace Ombi.DependencyInjection
services.AddTransient<ICloudMobileNotification, CloudMobileNotification>();
services.AddTransient<IEmbyApiFactory, EmbyApiFactory>();
services.AddTransient<IJellyfinApiFactory, JellyfinApiFactory>();
services.AddTransient<IRottenTomatoesApi, RottenTomatoesApi>();
}
public static void RegisterStore(this IServiceCollection services) {

@ -32,6 +32,7 @@
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
<ProjectReference Include="..\Ombi.Api.Pushover\Ombi.Api.Pushover.csproj" />
<ProjectReference Include="..\Ombi.Api.Radarr\Ombi.Api.Radarr.csproj" />
<ProjectReference Include="..\Ombi.Api.RottenTomatoes\Ombi.Api.RottenTomatoes.csproj" />
<ProjectReference Include="..\Ombi.Api.Service\Ombi.Api.Service.csproj" />
<ProjectReference Include="..\Ombi.Api.SickRage\Ombi.Api.SickRage.csproj" />
<ProjectReference Include="..\Ombi.Api.Slack\Ombi.Api.Slack.csproj" />

@ -121,6 +121,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Webhook", "Ombi.Ap
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.CloudService", "Ombi.Api.CloudService\Ombi.Api.CloudService.csproj", "{5DE40A66-B369-469E-8626-ECE23D9D8034}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.RottenTomatoes", "Ombi.Api.RottenTomatoes\Ombi.Api.RottenTomatoes.csproj", "{8F19C701-7881-4BC7-8BBA-B068A6B954AD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -323,6 +325,10 @@ Global
{5DE40A66-B369-469E-8626-ECE23D9D8034}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5DE40A66-B369-469E-8626-ECE23D9D8034}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5DE40A66-B369-469E-8626-ECE23D9D8034}.Release|Any CPU.Build.0 = Release|Any CPU
{8F19C701-7881-4BC7-8BBA-B068A6B954AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8F19C701-7881-4BC7-8BBA-B068A6B954AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F19C701-7881-4BC7-8BBA-B068A6B954AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F19C701-7881-4BC7-8BBA-B068A6B954AD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -334,6 +340,7 @@ Global
{63E63511-1C7F-4162-8F92-8F7391B3C8A3} = {025FB189-2FFB-4F43-A64B-6F1B5A0D2065}
{2E1A7B91-F29B-42BC-8F1E-1CF2DCC389BA} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{08FF107D-31E1-470D-AF86-E09B015CEE06} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{F03757C7-5145-45C9-AFFF-B4E946755779} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{CFB5E008-D0D0-43C0-AA06-89E49D17F384} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{0E8EF835-E4F0-4EE5-A2B6-678DEE973721} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{E6EE2830-E4AC-4F2E-AD93-2C9305605761} = {EA30DD15-6280-4687-B370-2956EC2E54E5}
@ -369,6 +376,7 @@ Global
{59D19538-0496-44EE-936E-EBBC22CF7B27} = {410F36CF-9C60-428A-B191-6FD90610991A}
{E2186FDA-D827-4781-8663-130AC382F12C} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{5DE40A66-B369-469E-8626-ECE23D9D8034} = {9293CA11-360A-4C20-A674-B9E794431BF5}
{8F19C701-7881-4BC7-8BBA-B068A6B954AD} = {9293CA11-360A-4C20-A674-B9E794431BF5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869}

@ -0,0 +1,11 @@
export interface IMovieRatings {
critics_rating: string;
critics_score: number;
audience_rating: string;
audience_score: number;
}
export interface ITvRatings {
class: string;
score: number;
}

@ -1,4 +1,4 @@
import { Component, ViewEncapsulation } from "@angular/core";
import { Component, Inject, OnInit, ViewEncapsulation } from "@angular/core";
import { ImageService, SearchV2Service, RequestService, MessageService, RadarrService } from "../../../services";
import { ActivatedRoute } from "@angular/router";
import { DomSanitizer } from "@angular/platform-browser";
@ -13,13 +13,15 @@ import { StorageService } from "../../../shared/storage/storage-service";
import { MovieAdvancedOptionsComponent } from "./panels/movie-advanced-options/movie-advanced-options.component";
import { RequestServiceV2 } from "../../../services/requestV2.service";
import { RequestBehalfComponent } from "../shared/request-behalf/request-behalf.component";
import { IMovieRatings } from "../../../interfaces/IRatings";
import { APP_BASE_HREF } from "@angular/common";
@Component({
templateUrl: "./movie-details.component.html",
styleUrls: ["../../media-details.component.scss"],
encapsulation: ViewEncapsulation.None
})
export class MovieDetailsComponent {
export class MovieDetailsComponent implements OnInit {
public movie: ISearchMovieResultV2;
public hasRequest: boolean;
public movieRequest: IMovieRequests;
@ -43,10 +45,13 @@ export class MovieDetailsComponent {
}
}
this.theMovidDbId = params.movieDbId;
this.load();
});
}
public async ngOnInit() {
await this.load();
}
public async load() {
this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser");

@ -1,16 +1,26 @@
<div *ngIf="movie">
<span *ngIf="movie.voteAverage" matTooltip="{{'MediaDetails.Votes' | translate }} {{movie.voteCount | thousandShort: 1}}">
<img class="rating-small" src="{{baseUrl}}/images/tmdb-logo.svg"> {{movie.voteAverage | number:'1.0-1'}}/10
</span>
<span *ngIf="ratings?.critics_rating && ratings?.critics_score">
<img class="rating-small" src="{{baseUrl}}/images/{{ratings.critics_rating === 'Rotten' ? 'rotten-rotten.svg' : 'rotten-fresh.svg'}}"> {{ratings.critics_score}}%
</span>
<span *ngIf="ratings?.audience_rating && ratings?.audience_score">
<img class="rating-small" src="{{baseUrl}}/images/{{ratings.audience_rating === 'Upright' ? 'rotten-audience-fresh.svg' : 'rotten-audience-rotten.svg'}}"> {{ratings.audience_score}}%
</span>
<hr>
<div>
<strong>{{'MediaDetails.Status' | translate }}:</strong>
<div>{{movie.status}}</div>
{{movie.status}}
</div>
<div>
<strong>{{'MediaDetails.Availability' | translate }}</strong>
<div *ngIf="movie.available">{{'Common.Available' | translate}}</div>
<div *ngIf="!movie.available">{{'Common.NotAvailable' | translate}}</div>
<strong>{{'MediaDetails.Availability' | translate }}:</strong>
<span *ngIf="movie.available"> {{'Common.Available' | translate}}</span>
<span *ngIf="!movie.available"> {{'Common.NotAvailable' | translate}}</span>
</div>
<br>
<div>
<div *ngIf="!movie.available">
<strong>{{'MediaDetails.RequestStatus' | translate }}</strong>
<div *ngIf="movie.approved && !movie.available">{{'Common.ProcessingRequest' | translate}}</div>
<div *ngIf="movie.requested && !movie.approved && !movie.available">{{'Common.PendingApproval' | translate}}
@ -20,13 +30,13 @@
</div>
<div *ngIf="request">
<strong>{{'Requests.RequestedBy' | translate }}</strong>
<div>{{request.requestedUser.userAlias}}</div>
<strong>{{'Requests.RequestedBy' | translate }}:</strong>
{{request.requestedUser.userAlias}}
</div>
<div *ngIf="request">
<strong>{{'Requests.RequestDate' | translate }}</strong>
<div>{{request.requestedDate | date}}</div>
<strong>{{'Requests.RequestDate' | translate }}:</strong>
{{request.requestedDate | date}}
</div>
@ -43,56 +53,49 @@
<strong>{{'MediaDetails.QualityOverride' | translate }}</strong>
<div>{{request.qualityOverrideTitle}}</div>
</div>
<br />
<div *ngIf="movie.genres">
<strong>{{'MediaDetails.Genres' | translate }}:</strong>
<div>
<mat-chip-list>
<mat-chip color="accent" selected *ngFor="let genre of movie.genres">
{{genre.name}}
</mat-chip>
</mat-chip-list>
</div>
</div>
<br />
<strong>{{'MediaDetails.TheatricalRelease' | translate }}:</strong>
<div>
<hr>
<strong>{{'MediaDetails.TheatricalRelease' | translate }}:</strong>
{{movie.releaseDate | date: 'mediumDate'}}
<div *ngIf="movie.digitalReleaseDate">
<strong>{{'MediaDetails.DigitalRelease' | translate }}:</strong>
<div>
{{movie.digitalReleaseDate | date: 'mediumDate'}}
</div>
</div>
<div *ngIf="movie.voteAverage">
<strong>{{'MediaDetails.UserScore' | translate }}:</strong>
<div>
{{movie.voteAverage | number:'1.0-1'}} / 10
</div>
</div>
<div *ngIf="movie.voteCount">
<strong>{{'MediaDetails.Votes' | translate }}:</strong>
<div>
{{movie.voteCount | thousandShort: 1}}
</div>
</div>
<div>
<strong>{{'MediaDetails.Runtime' | translate }}:</strong>
<div>{{'MediaDetails.Minutes' | translate:{runtime: movie.runtime} }}</div>
{{'MediaDetails.Minutes' | translate:{runtime: movie.runtime} }}
</div>
<div *ngIf="movie.revenue">
<strong>{{'MediaDetails.Revenue' | translate }}:</strong>
<div> {{movie.revenue | currency: 'USD'}}</div>
{{movie.revenue | currency: 'USD'}}
</div>
<div *ngIf="movie.budget">
<strong>{{'MediaDetails.Budget' | translate }}:</strong>
<div> {{movie.budget | currency: 'USD'}}</div>
{{movie.budget | currency: 'USD'}}
</div>
<hr />
<div *ngIf="movie.genres">
<strong>{{'MediaDetails.Genres' | translate }}:</strong>
<div>
<mat-chip-list>
<mat-chip color="accent" selected *ngFor="let genre of movie.genres">
{{genre.name}}
</mat-chip>
</mat-chip-list>
</div>
</div>
<br />
<hr />
<div *ngIf="movie?.keywords?.keywordsValue?.length > 0">
<strong>{{'MediaDetails.Keywords' | translate }}:</strong>
<mat-chip-list>
@ -100,5 +103,4 @@
{{keyword.name}}
</mat-chip>
</mat-chip-list>
</div>
</div>
</div>

@ -1,15 +1,27 @@
import { Component, ViewEncapsulation, Input } from "@angular/core";
import { Component, ViewEncapsulation, Input, OnInit, Inject } from "@angular/core";
import { ISearchMovieResultV2 } from "../../../../interfaces/ISearchMovieResultV2";
import { IAdvancedData, IMovieRequests } from "../../../../interfaces";
import { IMovieRequests } from "../../../../interfaces";
import { SearchV2Service } from "../../../../services/searchV2.service";
import { IMovieRatings } from "../../../../interfaces/IRatings";
import { APP_BASE_HREF } from "@angular/common";
@Component({
templateUrl: "./movie-information-panel.component.html",
styleUrls: ["../../../media-details.component.scss"],
selector: "movie-information-panel",
encapsulation: ViewEncapsulation.None
})
export class MovieInformationPanelComponent {
export class MovieInformationPanelComponent implements OnInit {
constructor(private searchService: SearchV2Service, @Inject(APP_BASE_HREF) public baseUrl: string) { }
@Input() public movie: ISearchMovieResultV2;
@Input() public request: IMovieRequests;
@Input() public advancedOptions: boolean;
public ratings: IMovieRatings;
public ngOnInit() {
this.searchService.getRottenMovieRatings(this.movie.title, +this.movie.releaseDate.toString().substring(0,4))
.subscribe(x => this.ratings = x);
}
}

@ -10,10 +10,10 @@
<i matTooltip="The TV DB" class="fa fa-tv fa-2x grow-social"></i>
</a>
<a *ngIf="hasTrailer" class="media-icons" (click)="openDialog()"><i
<a *ngIf="hasTrailer" class="media-icons youtube" (click)="openDialog()"><i
matTooltip="Trailer" class="fa fa-youtube-play fa-2x grow-social"></i></a>
<a *ngIf="imdbId" class="media-icons" [href]="doNotAppend ? imdbid : 'https://imdb.com/title/' + imdbId"
<a *ngIf="imdbId" class="media-icons imdb" [href]="doNotAppend ? imdbid : 'https://imdb.com/title/' + imdbId"
target="_blank">
<i matTooltip="Imdb" class="fa fa-imdb fa-2x grow-social"></i>
</a>

@ -1,42 +1,46 @@
<div>
<span *ngIf="tv.rating">
<img style="width: 4em;" src="{{baseUrl}}/images/tvm-logo.png"> {{tv.rating}}/10
</span>
<span *ngIf="ratings?.score && ratings?.class">
<img class="rating-small" src="{{baseUrl}}/images/{{ratings.class === 'rotten' ? 'rotten-rotten.svg' : 'rotten-fresh.svg'}}"> {{ratings.score}}%
</span>
<hr>
<div *ngIf="tv.status">
<strong>{{'MediaDetails.Status' | translate }}:</strong>
<div>
{{tv.status}}
</div>
</div>
<strong>First Aired:</strong>
<div>
{{tv.firstAired | date: 'mediumDate'}}
</div>
</div>
<div *ngIf="seasonCount">
<strong>Seasons:</strong>
{{seasonCount}}
</div>
<div *ngIf="totalEpisodes">
<strong>Episodes:</strong>
{{totalEpisodes}}
</div>
<div *ngIf="advancedOptions && request?.rootPathOverrideTitle">
<strong>{{'MediaDetails.RootFolderOverride' | translate }}</strong>
<strong>{{'MediaDetails.RootFolderOverride' | translate }}:</strong>
<div>{{request.rootPathOverrideTitle}}</div>
</div>
<div *ngIf="advancedOptions && request?.qualityOverrideTitle">
<strong>{{'MediaDetails.QualityOverride' | translate }}</strong>
<strong>{{'MediaDetails.QualityOverride' | translate }}:</strong>
<div>{{request.qualityOverrideTitle}}</div>
</div>
<div>
<strong>{{'MediaDetails.Runtime' | translate }}:</strong>
<div>
{{'MediaDetails.Minutes' | translate:{ runtime: tv.runtime} }}
</div>
</div>
<div *ngIf="tv.rating">
<strong>Rating:</strong>
<div>
{{tv.rating}} / 10
</div>
</div>
<div *ngIf="tv.network">
<strong>Network:</strong>
<div>
{{tv.network.name}}
</div>
</div>
<div *ngIf="tv.genre">
@ -48,16 +52,3 @@
</div>
</div>
<br />
<div *ngIf="seasonCount">
<strong>Seasons:</strong>
<div>
{{seasonCount}}
</div>
</div>
<div *ngIf="totalEpisodes">
<strong>Episodes:</strong>
<div>
{{totalEpisodes}}
</div>
</div>

@ -1,6 +1,8 @@
import { Component, ViewEncapsulation, Input, OnInit } from "@angular/core";
import { ITvRequests } from "../../../../../interfaces";
import { ITvRatings } from "../../../../../interfaces/IRatings";
import { ISearchTvResultV2 } from "../../../../../interfaces/ISearchTvResultV2";
import { SearchV2Service } from "../../../../../services";
@Component({
templateUrl: "./tv-information-panel.component.html",
@ -9,15 +11,21 @@ import { ISearchTvResultV2 } from "../../../../../interfaces/ISearchTvResultV2";
encapsulation: ViewEncapsulation.None
})
export class TvInformationPanelComponent implements OnInit {
constructor(private searchService: SearchV2Service) { }
@Input() public tv: ISearchTvResultV2;
@Input() public request: ITvRequests;
@Input() public advancedOptions: boolean;
public ratings: ITvRatings;
public seasonCount: number;
public totalEpisodes: number = 0;
public nextEpisode: any;
public ngOnInit(): void {
this.searchService.getRottenTvRatings(this.tv.title, +this.tv.firstAired.toString().substring(0,4))
.subscribe(x => this.ratings = x);
this.tv.seasonRequests.forEach(season => {
this.totalEpisodes = this.totalEpisodes + season.episodes.length;
});

@ -226,4 +226,8 @@
.content-end {
text-align: end;
}
.rating-small {
width: 1.3em;
}

@ -11,6 +11,7 @@ import { ISearchMovieResultV2 } from "../interfaces/ISearchMovieResultV2";
import { ISearchTvResultV2, IMovieCollectionsViewModel, IActorCredits } from "../interfaces/ISearchTvResultV2";
import { IArtistSearchResult, IAlbumArt } from "../interfaces/IMusicSearchResultV2";
import { SearchFilter } from "../my-nav/SearchFilter";
import { IMovieRatings, ITvRatings } from "../interfaces/IRatings";
@Injectable()
export class SearchV2Service extends ServiceHelpers {
@ -121,4 +122,13 @@ export class SearchV2Service extends ServiceHelpers {
public getReleaseGroupArt(mbid: string): Observable<IAlbumArt> {
return this.http.get<IAlbumArt>(`${this.url}/releasegroupart/${mbid}`);
}
public getRottenMovieRatings(name: string, year: number): Observable<IMovieRatings> {
return this.http.get<IMovieRatings>(`${this.url}/ratings/movie/${name}/${year}`);
}
public getRottenTvRatings(name: string, year: number): Observable<ITvRatings> {
return this.http.get<ITvRatings>(`${this.url}/ratings/tv/${name}/${year}`);
}
}

@ -14,13 +14,15 @@ using Ombi.Core.Models.Search;
using Ombi.Core.Models.Search.V2;
using Ombi.Core.Models.Search.V2.Music;
using Ombi.Models;
using Ombi.Api.RottenTomatoes.Models;
using Ombi.Api.RottenTomatoes;
namespace Ombi.Controllers.V2
{
public class SearchController : V2Controller
{
public SearchController(IMultiSearchEngine multiSearchEngine, ITvSearchEngine tvSearchEngine,
IMovieEngineV2 v2Movie, ITVSearchEngineV2 v2Tv, IMusicSearchEngineV2 musicEngine)
IMovieEngineV2 v2Movie, ITVSearchEngineV2 v2Tv, IMusicSearchEngineV2 musicEngine, IRottenTomatoesApi rottenTomatoesApi)
{
_multiSearchEngine = multiSearchEngine;
_tvSearchEngine = tvSearchEngine;
@ -29,6 +31,7 @@ namespace Ombi.Controllers.V2
_movieEngineV2.ResultLimit = 12;
_tvEngineV2 = v2Tv;
_musicEngine = musicEngine;
_rottenTomatoesApi = rottenTomatoesApi;
}
private readonly IMultiSearchEngine _multiSearchEngine;
@ -36,6 +39,7 @@ namespace Ombi.Controllers.V2
private readonly ITVSearchEngineV2 _tvEngineV2;
private readonly ITvSearchEngine _tvSearchEngine;
private readonly IMusicSearchEngineV2 _musicEngine;
private readonly IRottenTomatoesApi _rottenTomatoesApi;
/// <summary>
/// Returns search results for both TV and Movies
@ -399,5 +403,22 @@ namespace Ombi.Controllers.V2
{
return await _musicEngine.GetReleaseGroupArt(musicBrainzId, CancellationToken);
}
[HttpGet("ratings/movie/{name}/{year}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public Task<MovieRatings> GetRottenMovieRatings(string name, int year)
{
return _rottenTomatoesApi.GetMovieRatings(name, year);
}
[HttpGet("ratings/tv/{name}/{year}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public Task<TvRatings> GetRottenTvRatings(string name, int year)
{
return _rottenTomatoesApi.GetTvRatings(name, year);
}
}
}

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 560"><g fill="none"><path fill="#FFF" d="M370.57 474.214l23.466-237.956c14.93-4.796 29.498-11.15 40.23-20.262L404.16 446.278c-6.748 10.248-19.863 20.86-33.59 27.936zm-78.197 21.631l2.947-244.528c20.894-.599 47.933-3.43 70.97-8.346l-19.07 241.17c-22.724 7.518-35.934 9.848-54.847 11.704zm-99.694-252.874c23.038 4.916 50.077 7.747 70.971 8.346l2.948 244.528c-18.914-1.856-32.123-4.186-54.847-11.705l-19.072-241.17zm-67.974-26.975c10.732 9.112 25.3 15.466 40.23 20.262l23.464 237.956c-13.726-7.075-26.84-17.688-33.59-27.936l-30.104-230.282z"/><path fill="gold" d="M118.905 157.445c1.357 28.827 72.771 51.677 160.578 51.176 76.687-.438 140.659-18.546 156.329-42.336a22.976 22.976 0 00-14.058-7.426c.06-.7.098-1.406.095-2.122-.065-11.4-8.429-20.788-19.327-22.54.287-1.474.438-2.999.43-4.559-.072-12.696-10.426-22.928-23.124-22.856-.287.001-.568.036-.853.049a22.911 22.911 0 001.254-7.56c-.074-12.697-10.425-22.93-23.123-22.858a22.914 22.914 0 00-8.247 1.6c-3.632-6.835-10.606-11.6-18.737-12.149-1.416-11.4-11.157-20.195-22.93-20.129-7.41.042-13.963 3.6-18.136 9.065-4.233-4.605-10.3-7.494-17.047-7.456-12.698.072-22.932 10.424-22.86 23.118a22.983 22.983 0 001.115 6.946 22.918 22.918 0 00-13.07 7.459c-2.644-9.847-11.637-17.084-22.314-17.024-9.975.057-18.406 6.47-21.537 15.366-8.474 3.426-14.439 11.738-14.383 21.433.012 2.154.342 4.227.907 6.202a22.876 22.876 0 00-9.328-1.932c-10.012.058-18.47 6.516-21.574 15.465a22.83 22.83 0 00-9.788-2.149c-12.698.072-22.934 10.422-22.86 23.118a22.833 22.833 0 003.159 11.463c-.202.203-.379.426-.571.636"/><path fill="#FA320A" d="M404.161 446.278c-6.749 10.248-19.864 20.86-33.59 27.936l23.465-237.956c14.93-4.796 29.498-11.15 40.23-20.262L404.16 446.278zM347.22 484.14c-22.723 7.519-35.934 9.85-54.847 11.705l2.947-244.528c20.894-.599 47.933-3.43 70.973-8.346L347.22 484.14zm-135.47 0l-19.07-241.17c23.037 4.917 50.076 7.748 70.97 8.347l2.948 244.528c-18.914-1.856-32.123-4.186-54.847-11.705zm-56.94-37.862l-30.105-230.282c10.732 9.112 25.3 15.466 40.23 20.262l23.464 237.956c-13.726-7.075-26.84-17.688-33.588-27.936zm247.668-321.143c.298 1.453.465 2.955.473 4.498a23.018 23.018 0 01-.43 4.56c10.9 1.749 19.263 11.137 19.328 22.54a23.59 23.59 0 01-.095 2.12 22.976 22.976 0 0114.058 7.425c-15.669 23.792-79.642 41.9-156.327 42.34-87.807.502-159.221-22.346-160.58-51.175.192-.208.37-.433.57-.634-1.355-2.311-2.29-4.887-2.773-7.62-8.408 7.979-13.495 14.412-12.6 23.78.085 1.251 37.196 266.911 37.196 266.911 4.282 42.075 65.391 75.703 138.187 76.12 72.796-.417 133.907-34.045 138.187-76.12 0 0 37.11-265.66 37.197-266.912 1.777-18.736-20.15-35.745-52.39-47.833z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 560">
<g fill="none" transform="translate(33 140)">
<path fill="#FFF" d="M43.8020066,267.3152 L281.745403,290.797105 C286.539148,305.7344 292.894623,320.31421 302.004138,331.0528 L71.7380852,300.927619 C61.4905377,294.175695 50.8770689,281.050362 43.8020066,267.3152 Z M266.684852,192.017143 C267.285384,212.923048 270.116459,239.981562 275.03101,263.034133 L33.8766098,243.950705 C26.3585902,221.21181 24.03,207.991848 22.1723803,189.066133 L266.684852,192.017143 Z M275.03101,89.3083429 C270.116459,112.360914 267.285384,139.419429 266.684852,160.325333 L22.1723803,163.276343 C24.03,144.350629 26.3585902,131.130667 33.8766098,108.391771 L275.03101,89.3083429 Z M302.004138,21.2896762 C292.894623,32.030019 286.539148,46.6080762 281.745403,61.5471238 L43.8020066,85.0272762 C50.8770689,71.2921143 61.4905377,58.1685333 71.7380852,51.4148571 L302.004138,21.2896762 Z"/>
<path fill="#00641E" d="M303.565869,264.667352 C306.720846,256.846476 317.903331,252.081752 325.93259,252.63901 C334.515108,253.234819 343.631626,262.264838 345.224872,271.145905 C345.520761,270.823467 345.830656,270.518552 346.145803,270.218895 C348.901593,267.583314 352.35421,265.834438 356.132479,265.352533 C355.554708,262.790552 355.416393,260.048076 355.812079,257.233752 C357.207482,247.3328 365.145698,239.907962 374.234203,239.981562 C380.099449,240.028876 385.245108,243.032457 388.597928,247.646476 C388.897318,247.271467 389.228223,246.928 389.550374,246.577524 C393.384669,226.586362 395.814807,203.999924 396.368066,180.030857 C398.267705,97.6111238 377.375174,30.2776381 349.70522,29.6397714 C322.033515,29.0001524 298.061292,95.2962286 296.161652,177.715962 C296.161652,177.715962 294.696216,207.778057 303.565869,264.667352"/>
<path fill="#FFD700" d="M490.910577,354.797562 C492.545843,352.0656 493.45977,348.7904 493.396741,345.310171 C493.927239,334.065143 486.214879,323.871543 475.484105,325.000076 C475.794,323.713829 475.997095,322.376762 476.075882,320.997638 C476.718433,309.733333 468.957049,300.025143 458.739266,299.315429 C458.515161,299.30141 458.294557,299.2944 458.072203,299.28739 C459.134951,296.492343 459.661948,293.371352 459.47461,290.06461 C458.945862,280.692876 452.488839,272.796648 444.088407,271.242286 C441.054236,270.681524 438.111108,270.960152 435.416597,271.894171 C432.870905,265.617143 427.525652,260.961067 421.023108,259.977981 C420.508367,249.786133 413.153174,241.397486 403.68299,240.740343 C397.728452,240.326781 392.257141,243.064 388.597928,247.646476 C385.245108,243.032457 380.099449,240.030629 374.234203,239.983314 C365.145698,239.907962 357.207482,247.3328 355.812079,257.235505 C355.416393,260.048076 355.554708,262.790552 356.132479,265.354286 C352.35421,265.834438 348.901593,267.585067 346.145803,270.218895 C345.830656,270.518552 345.520761,270.823467 345.224872,271.145905 C343.631626,262.264838 334.515108,253.236571 325.93259,252.63901 C317.903331,252.081752 306.575528,256.963886 303.565869,264.667352 C304.885987,278.101105 313.275915,314.72061 343.621121,347.570743 L343.890748,347.590019 C346.816367,350.239619 350.636656,351.699352 354.709062,351.33661 C357.233744,351.110552 359.558833,350.206324 361.56177,348.811429 L362.050249,348.844724 C364.720249,350.700495 367.929502,351.671314 371.320839,351.369905 C372.616446,351.254248 373.852525,350.942324 375.027325,350.497219 C377.933685,356.51139 384.41522,360.398171 391.649607,359.760305 C397.25223,359.266133 402.014459,356.164419 404.81402,351.799238 L405.720944,351.862324 C408.517003,354.636343 412.233993,356.252038 416.24337,356.131124 C419.557672,361.149943 425.645272,364.237638 432.363167,363.647086 C434.893102,363.424533 437.254957,362.692038 439.361193,361.582781 C442.875089,365.90941 448.642289,368.481905 454.969751,367.924648 C461.22543,367.376152 466.509403,363.904686 469.384249,359.104914 C472.208321,361.374248 475.746728,362.592152 479.503987,362.257448 C483.149193,361.931505 486.38821,360.208914 488.821849,357.603124 L489.228039,357.631162 C489.781298,356.828571 490.25402,356.006705 490.693475,355.177829 C490.70398,355.162057 490.712734,355.144533 490.721489,355.128762 C490.781016,355.018362 490.854551,354.909714 490.910577,354.797562"/>
<path fill="#04A53C" d="M281.745403,61.5471238 L43.8020066,85.0272762 C50.8770689,71.2921143 61.4905377,58.1685333 71.7380852,51.4148571 L302.004138,21.2896762 C292.894623,32.030019 286.539148,46.6080762 281.745403,61.5471238 Z M302.004138,331.0528 L71.7380852,300.927619 C61.4905377,294.175695 50.8770689,281.050362 43.8020066,267.316952 L281.745403,290.797105 C286.539148,305.7344 292.894623,320.31421 302.004138,331.0528 Z M33.8766098,243.950705 C26.3585902,221.21181 24.03,207.9936 22.1723803,189.066133 L266.684852,192.017143 C267.285384,212.923048 270.116459,239.981562 275.03101,263.034133 L33.8766098,243.950705 Z M33.8766098,108.391771 L275.03101,89.3083429 C270.116459,112.360914 267.285384,139.419429 266.684852,160.327086 L22.1723803,163.276343 C24.03,144.350629 26.3585902,131.130667 33.8766098,108.391771 Z M378.597246,25.7126857 C363.342354,7.93478095 352.390977,-0.411809524 343.010085,0.672914286 C341.261016,0.895466667 76.1168852,37.8952381 76.1168852,37.8952381 C34.0429377,42.1780571 0.416695082,103.32739 0,176.172114 C0.416695082,249.015086 34.0429377,310.164419 76.1168852,314.44899 C76.1168852,314.44899 341.758249,351.583695 343.010085,351.669562 C345.228374,351.655543 347.418649,351.357638 349.57741,350.803886 C347.476426,350.178286 345.538269,349.083048 343.890748,347.590019 L343.621121,347.570743 C313.275915,314.722362 304.885987,278.101105 303.565869,264.667352 C303.56937,264.656838 303.576374,264.648076 303.579875,264.637562 C303.576374,264.648076 303.56937,264.656838 303.565869,264.667352 C294.696216,207.778057 296.161652,177.715962 296.161652,177.715962 C298.061292,95.2962286 322.033515,29.0001524 349.70522,29.638019 C377.375174,30.2776381 398.267705,97.6111238 396.368066,180.030857 C395.814807,203.999924 393.384669,226.586362 389.550374,246.577524 C393.489718,242.226362 398.773692,240.393371 403.68299,240.740343 C404.586413,240.805181 405.465325,240.957638 406.326728,241.155657 C423.131095,149.125867 405.514348,59.262019 378.597246,25.7126857 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 560"><g fill="none"><path fill="#FA320A" d="M478.29 296.976c-3.99-63.966-36.52-111.823-85.468-138.579.278 1.56-1.109 3.508-2.688 2.818-32.016-14.006-86.328 31.32-124.282 7.584.285 8.519-1.378 50.072-59.914 52.483-1.382.056-2.142-1.355-1.268-2.354 7.828-8.929 15.732-31.535 4.367-43.586-24.338 21.81-38.472 30.017-85.138 19.186-29.878 31.241-46.809 74-43.485 127.265 6.78 108.735 108.63 170.89 211.193 164.49 102.556-6.395 193.466-80.572 186.683-189.307"/><path fill="#00912D" d="M291.375 132.293c21.075-5.023 81.693-.49 101.114 25.274 1.166 1.545-.475 4.468-2.355 3.648-32.016-14.006-86.328 31.32-124.282 7.584.285 8.519-1.378 50.072-59.914 52.483-1.382.056-2.142-1.355-1.268-2.354 7.828-8.929 15.73-31.535 4.367-43.586-26.512 23.758-40.884 31.392-98.426 15.838-1.883-.508-1.241-3.535.762-4.298 10.876-4.157 35.515-22.361 58.824-30.385 4.438-1.526 8.862-2.71 13.18-3.4-25.665-2.293-37.235-5.862-53.559-3.4-1.789.27-3.004-1.813-1.895-3.241 21.995-28.332 62.513-36.888 87.512-21.837-15.41-19.094-27.48-34.321-27.48-34.321l28.601-16.246s11.817 26.4 20.414 45.614c21.275-31.435 60.86-34.336 77.585-12.033.992 1.326-.045 3.21-1.702 3.171-13.612-.331-21.107 12.05-21.675 21.466l.197.023"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 560"><path fill="#0AC855" d="M445.185 444.684c-79.369 4.167-95.587-86.652-126.726-86.006-13.268.279-23.726 14.151-19.133 30.32 2.525 8.888 9.53 21.923 13.944 30.011 15.57 28.544-7.447 60.845-34.383 63.577-44.76 4.54-63.433-21.426-62.278-48.007 1.3-29.84 26.6-60.331.65-73.305-27.194-13.597-49.301 39.572-75.325 51.439-23.553 10.741-56.248 2.413-67.872-23.741-8.164-18.379-6.68-53.768 29.67-67.27 22.706-8.433 73.305 11.029 75.9-13.623 2.992-28.416-53.155-30.812-70.06-37.626-29.912-12.055-47.567-37.85-33.734-65.522 10.378-20.757 40.915-29.203 64.223-20.11 27.922 10.892 32.404 39.853 46.71 51.897 12.324 10.38 29.19 11.68 40.22 4.543 8.135-5.265 10.843-16.828 7.774-27.39-4.07-14.023-14.875-22.773-25.415-31.346-18.758-15.249-45.24-28.36-29.222-69.983 13.13-34.11 51.642-35.34 51.642-35.34 15.3-1.72 29.002 2.9 40.167 12.875 14.927 13.335 17.834 31.16 15.336 50.176-2.283 17.358-8.426 32.56-11.63 49.759-3.717 19.966 6.954 40.086 27.249 40.869 26.694 1.031 34.698-19.486 37.964-32.492 4.782-19.028 11.058-36.694 28.718-47.82 25.346-15.97 60.552-12.47 76.886 18.222 12.92 24.284 8.772 57.715-11.047 75.97-8.892 8.188-19.584 11.075-31.148 11.156-16.585.117-33.162-.29-48.556 7.471-10.48 5.281-15.047 13.888-15.045 25.423 0 11.242 5.853 18.585 15.336 23.363 17.86 9.003 37.577 10.843 56.871 14.222 27.98 4.9 52.581 14.755 68.375 40.72.142.228.28.458.415.69 18.139 30.741-.831 75.005-36.476 76.878"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 190.24 81.52"><defs><linearGradient id="a" y1="40.76" x2="190.24" y2="40.76" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#90cea1"/><stop offset=".56" stop-color="#3cbec9"/><stop offset="1" stop-color="#00b3e5"/></linearGradient></defs><g data-name="Layer 2"><path d="M105.67 36.06h66.9a17.67 17.67 0 0017.67-17.66A17.67 17.67 0 00172.57.73h-66.9A17.67 17.67 0 0088 18.4a17.67 17.67 0 0017.67 17.66zm-88 45h76.9a17.67 17.67 0 0017.67-17.66 17.67 17.67 0 00-17.67-17.67h-76.9A17.67 17.67 0 000 63.4a17.67 17.67 0 0017.67 17.66zm-7.26-45.64h7.8V6.92h10.1V0h-28v6.9h10.1zm28.1 0h7.8V8.25h.1l9 27.15h6l9.3-27.15h.1V35.4h7.8V0H66.76l-8.2 23.1h-.1L50.31 0h-11.8zm113.92 20.25a15.07 15.07 0 00-4.52-5.52 18.57 18.57 0 00-6.68-3.08 33.54 33.54 0 00-8.07-1h-11.7v35.4h12.75a24.58 24.58 0 007.55-1.15 19.34 19.34 0 006.35-3.32 16.27 16.27 0 004.37-5.5 16.91 16.91 0 001.63-7.58 18.5 18.5 0 00-1.68-8.25zM145 68.6a8.8 8.8 0 01-2.64 3.4 10.7 10.7 0 01-4 1.82 21.57 21.57 0 01-5 .55h-4.05v-21h4.6a17 17 0 014.67.63 11.66 11.66 0 013.88 1.87A9.14 9.14 0 01145 59a9.87 9.87 0 011 4.52 11.89 11.89 0 01-1 5.08zm44.63-.13a8 8 0 00-1.58-2.62 8.38 8.38 0 00-2.42-1.85 10.31 10.31 0 00-3.17-1v-.1a9.22 9.22 0 004.42-2.82 7.43 7.43 0 001.68-5 8.42 8.42 0 00-1.15-4.65 8.09 8.09 0 00-3-2.72 12.56 12.56 0 00-4.18-1.3 32.84 32.84 0 00-4.62-.33h-13.2v35.4h14.5a22.41 22.41 0 004.72-.5 13.53 13.53 0 004.28-1.65 9.42 9.42 0 003.1-3 8.52 8.52 0 001.2-4.68 9.39 9.39 0 00-.55-3.18zm-19.42-15.75h5.3a10 10 0 011.85.18 6.18 6.18 0 011.7.57 3.39 3.39 0 011.22 1.13 3.22 3.22 0 01.48 1.82 3.63 3.63 0 01-.43 1.8 3.4 3.4 0 01-1.12 1.2 4.92 4.92 0 01-1.58.65 7.51 7.51 0 01-1.77.2h-5.65zm11.72 20a3.9 3.9 0 01-1.22 1.3 4.64 4.64 0 01-1.68.7 8.18 8.18 0 01-1.82.2h-7v-8h5.9a15.35 15.35 0 012 .15 8.47 8.47 0 012.05.55 4 4 0 011.57 1.18 3.11 3.11 0 01.63 2 3.71 3.71 0 01-.43 1.92z" fill="url(#a)" data-name="Layer 1"/></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Кинопремиера",
"DigitalRelease": "Digital Release",
"UserScore": "User Score",
"Votes": "Votes",
"Runtime": "Runtime",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Biografudgivelse",
"DigitalRelease": "Digital Release",
"UserScore": "User Score",
"Votes": "Votes",
"Runtime": "Runtime",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Kinostart",
"DigitalRelease": "Digital Release",
"UserScore": "User Score",
"Votes": "Votes",
"Runtime": "Runtime",
"Minutes": "{{runtime}} Minutes",

@ -256,9 +256,8 @@
"RootFolderOverride":"Root Folder Override",
"QualityOverride":"Quality Override",
"Genres":"Genres",
"TheatricalRelease":"Theatrical Release",
"TheatricalRelease":"Release",
"DigitalRelease":"Digital Release",
"UserScore":"User Score",
"Votes":"Votes",
"Runtime":"Runtime",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Géneros",
"TheatricalRelease": "En cines",
"DigitalRelease": "Estreno Digital",
"UserScore": "Puntuación de Usuarios",
"Votes": "Votos",
"Runtime": "Duración",
"Minutes": "{{runtime}} Minutos",

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Sortie en salle",
"DigitalRelease": "Sorti en Numérique",
"UserScore": "Note des Spectateurs",
"Votes": "Votes",
"Runtime": "Durée de visionnage",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Mozis kiadás",
"DigitalRelease": "Digital Release",
"UserScore": "User Score",
"Votes": "Votes",
"Runtime": "Runtime",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Generi",
"TheatricalRelease": "Rilascio Teatrale",
"DigitalRelease": "Rilascio Digitale",
"UserScore": "Punteggio Utente",
"Votes": "Voti",
"Runtime": "Durata",
"Minutes": "{{runtime}} Minuti",

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Bioscoop Uitgave",
"DigitalRelease": "Digital Release",
"UserScore": "User Score",
"Votes": "Votes",
"Runtime": "Runtime",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Kinopremiere",
"DigitalRelease": "Digital Release",
"UserScore": "User Score",
"Votes": "Votes",
"Runtime": "Runtime",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Premiera kinowa",
"DigitalRelease": "Digital Release",
"UserScore": "User Score",
"Votes": "Votes",
"Runtime": "Runtime",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Theatrical Release",
"DigitalRelease": "Digital Release",
"UserScore": "User Score",
"Votes": "Votes",
"Runtime": "Runtime",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Релиз в кинотеатрах",
"DigitalRelease": "Digital Release",
"UserScore": "User Score",
"Votes": "Votes",
"Runtime": "Runtime",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Genres",
"TheatricalRelease": "Kino vydanie",
"DigitalRelease": "Digital Release",
"UserScore": "User Score",
"Votes": "Votes",
"Runtime": "Runtime",
"Minutes": "{{runtime}} Minutes",

@ -257,7 +257,6 @@
"Genres": "Genrer",
"TheatricalRelease": "Biopremiär",
"DigitalRelease": "Digital release",
"UserScore": "Användarbetyg",
"Votes": "Röster",
"Runtime": "Speltid",
"Minutes": "{{runtime}} minuter",

Loading…
Cancel
Save