Changed the TV Request API. We now only require the TvDbId and the seasons and episodes that you want to request. This should make integration regarding TV a lot easier.

This commit is contained in:
Jamie 2018-03-28 14:22:16 +01:00
parent 71157052b3
commit d15e09d342
11 changed files with 146 additions and 44 deletions

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
@ -9,7 +10,7 @@ namespace Ombi.Core.Engine.Interfaces
{ {
Task RemoveTvRequest(int requestId); Task RemoveTvRequest(int requestId);
Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv); Task<RequestEngineResult> RequestTvShow(TvRequestViewModel tv);
Task<RequestEngineResult> DenyChildRequest(int requestId); Task<RequestEngineResult> DenyChildRequest(int requestId);
Task<IEnumerable<TvRequests>> SearchTvRequest(string search); Task<IEnumerable<TvRequests>> SearchTvRequest(string search);
Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> SearchTvRequestTree(string search); Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> SearchTvRequestTree(string search);

View file

@ -43,13 +43,13 @@ namespace Ombi.Core.Engine
private IAuditRepository Audit { get; } private IAuditRepository Audit { get; }
private readonly IRepository<RequestLog> _requestLog; private readonly IRepository<RequestLog> _requestLog;
public async Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv) public async Task<RequestEngineResult> RequestTvShow(TvRequestViewModel tv)
{ {
var user = await GetUser(); var user = await GetUser();
var tvBuilder = new TvShowRequestBuilder(TvApi); var tvBuilder = new TvShowRequestBuilder(TvApi);
(await tvBuilder (await tvBuilder
.GetShowInfo(tv.Id)) .GetShowInfo(tv.TvDbId))
.CreateTvList(tv) .CreateTvList(tv)
.CreateChild(tv, user.Id); .CreateChild(tv, user.Id);
@ -78,9 +78,9 @@ namespace Ombi.Core.Engine
} }
} }
await Audit.Record(AuditType.Added, AuditArea.TvRequest, $"Added Request {tv.Title}", Username); await Audit.Record(AuditType.Added, AuditArea.TvRequest, $"Added Request {tvBuilder.ChildRequest.Title}", Username);
var existingRequest = await TvRepository.Get().FirstOrDefaultAsync(x => x.TvDbId == tv.Id); var existingRequest = await TvRepository.Get().FirstOrDefaultAsync(x => x.TvDbId == tv.TvDbId);
if (existingRequest != null) if (existingRequest != null)
{ {
// Remove requests we already have, we just want new ones // Remove requests we already have, we just want new ones

View file

@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Api.TvMaze; using Ombi.Api.TvMaze;
using Ombi.Api.TvMaze.Models; using Ombi.Api.TvMaze.Models;
using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Store.Entities; using Ombi.Store.Entities;
@ -23,7 +24,7 @@ namespace Ombi.Core.Helpers
private ITvMazeApi TvApi { get; } private ITvMazeApi TvApi { get; }
public ChildRequests ChildRequest { get; set; } public ChildRequests ChildRequest { get; set; }
public List<SeasonRequests> TvRequests { get; protected set; } public List<SeasonsViewModel> TvRequests { get; protected set; }
public string PosterPath { get; protected set; } public string PosterPath { get; protected set; }
public DateTime FirstAir { get; protected set; } public DateTime FirstAir { get; protected set; }
public TvRequests NewRequest { get; protected set; } public TvRequests NewRequest { get; protected set; }
@ -33,7 +34,7 @@ namespace Ombi.Core.Helpers
{ {
ShowInfo = await TvApi.ShowLookupByTheTvDbId(id); ShowInfo = await TvApi.ShowLookupByTheTvDbId(id);
DateTime.TryParse(ShowInfo.premiered, out DateTime dt); DateTime.TryParse(ShowInfo.premiered, out var dt);
FirstAir = dt; FirstAir = dt;
@ -43,37 +44,29 @@ namespace Ombi.Core.Helpers
return this; return this;
} }
public TvShowRequestBuilder CreateChild(SearchTvShowViewModel model, string userId) public TvShowRequestBuilder CreateChild(TvRequestViewModel model, string userId)
{ {
ChildRequest = new ChildRequests ChildRequest = new ChildRequests
{ {
Id = model.Id, Id = model.TvDbId,
RequestType = RequestType.TvShow, RequestType = RequestType.TvShow,
RequestedDate = DateTime.UtcNow, RequestedDate = DateTime.UtcNow,
Approved = false, Approved = false,
RequestedUserId = userId, RequestedUserId = userId,
SeasonRequests = new List<SeasonRequests>(), SeasonRequests = new List<SeasonRequests>(),
Title = model.Title, Title = ShowInfo.name,
SeriesType = ShowInfo.type.Equals("Animation", StringComparison.CurrentCultureIgnoreCase) ? SeriesType.Anime : SeriesType.Standard SeriesType = ShowInfo.type.Equals("Animation", StringComparison.CurrentCultureIgnoreCase) ? SeriesType.Anime : SeriesType.Standard
}; };
return this; return this;
} }
public TvShowRequestBuilder CreateTvList(SearchTvShowViewModel tv) public TvShowRequestBuilder CreateTvList(TvRequestViewModel tv)
{ {
TvRequests = new List<SeasonRequests>(); TvRequests = new List<SeasonsViewModel>();
// Only have the TV requests we actually requested and not everything // Only have the TV requests we actually requested and not everything
foreach (var season in tv.SeasonRequests) foreach (var season in tv.Seasons)
{ {
for (int i = season.Episodes.Count - 1; i >= 0; i--)
{
if (!season.Episodes[i].Requested)
{
season.Episodes.RemoveAt(i); // Remove the episode since it's not requested
}
}
if (season.Episodes.Any()) if (season.Episodes.Any())
{ {
TvRequests.Add(season); TvRequests.Add(season);
@ -81,11 +74,10 @@ namespace Ombi.Core.Helpers
} }
return this; return this;
} }
public async Task<TvShowRequestBuilder> BuildEpisodes(SearchTvShowViewModel tv) public async Task<TvShowRequestBuilder> BuildEpisodes(TvRequestViewModel tv)
{ {
if (tv.RequestAll) if (tv.RequestAll)
{ {
@ -173,26 +165,68 @@ namespace Ombi.Core.Helpers
else else
{ {
// It's a custom request // It's a custom request
ChildRequest.SeasonRequests = TvRequests; var seasonRequests = new List<SeasonRequests>();
var episodes = await TvApi.EpisodeLookup(ShowInfo.id);
foreach (var ep in episodes)
{
var existingSeasonRequest = seasonRequests.FirstOrDefault(x => x.SeasonNumber == ep.season);
if (existingSeasonRequest != null)
{
var requestedSeason = tv.Seasons.FirstOrDefault(x => x.SeasonNumber == ep.season);
var requestedEpisode = requestedSeason?.Episodes?.Any(x => x.EpisodeNumber == ep.number) ?? false;
if (requestedSeason != null && requestedEpisode)
{
// We already have this, let's just add the episodes to it
existingSeasonRequest.Episodes.Add(new EpisodeRequests
{
EpisodeNumber = ep.number,
AirDate = FormatDate(ep.airdate),
Title = ep.name,
Url = ep.url,
});
}
}
else
{
var newRequest = new SeasonRequests {SeasonNumber = ep.season};
var requestedSeason = tv.Seasons.FirstOrDefault(x => x.SeasonNumber == ep.season);
var requestedEpisode = requestedSeason?.Episodes?.Any(x => x.EpisodeNumber == ep.number) ?? false;
if (requestedSeason != null && requestedEpisode)
{
newRequest.Episodes.Add(new EpisodeRequests
{
EpisodeNumber = ep.number,
AirDate = FormatDate(ep.airdate),
Title = ep.name,
Url = ep.url,
});
seasonRequests.Add(newRequest);
}
}
}
foreach (var s in seasonRequests)
{
ChildRequest.SeasonRequests.Add(s);
}
} }
return this; return this;
} }
public TvShowRequestBuilder CreateNewRequest(SearchTvShowViewModel tv) public TvShowRequestBuilder CreateNewRequest(TvRequestViewModel tv)
{ {
NewRequest = new TvRequests NewRequest = new TvRequests
{ {
Id = tv.Id,
Overview = ShowInfo.summary.RemoveHtml(), Overview = ShowInfo.summary.RemoveHtml(),
PosterPath = PosterPath, PosterPath = PosterPath,
Title = ShowInfo.name, Title = ShowInfo.name,
ReleaseDate = FirstAir, ReleaseDate = FirstAir,
Status = ShowInfo.status, Status = ShowInfo.status,
ImdbId = ShowInfo.externals?.imdb ?? string.Empty, ImdbId = ShowInfo.externals?.imdb ?? string.Empty,
TvDbId = tv.Id, TvDbId = tv.TvDbId,
ChildRequests = new List<ChildRequests>(), ChildRequests = new List<ChildRequests>(),
TotalSeasons = tv.SeasonRequests.Count() TotalSeasons = tv.Seasons.Count()
}; };
NewRequest.ChildRequests.Add(ChildRequest); NewRequest.ChildRequests.Add(ChildRequest);

View file

@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace Ombi.Core.Models.Requests
{
public class TvRequestViewModel
{
public bool RequestAll { get; set; }
public bool LatestSeason { get; set; }
public bool FirstSeason { get; set; }
public int TvDbId { get; set; }
public List<SeasonsViewModel> Seasons { get; set; } = new List<SeasonsViewModel>();
}
public class SeasonsViewModel
{
public int SeasonNumber { get; set; }
public List<EpisodesViewModel> Episodes { get; set; } = new List<EpisodesViewModel>();
}
public class EpisodesViewModel
{
public int EpisodeNumber { get; set; }
}
}

View file

@ -10,7 +10,7 @@ namespace Ombi.Store.Repository.Requests
public class SeasonRequests : Entity public class SeasonRequests : Entity
{ {
public int SeasonNumber { get; set; } public int SeasonNumber { get; set; }
public List<EpisodeRequests> Episodes { get; set; } public List<EpisodeRequests> Episodes { get; set; } = new List<EpisodeRequests>();
public int ChildRequestId { get; set; } public int ChildRequestId { get; set; }
[ForeignKey(nameof(ChildRequestId))] [ForeignKey(nameof(ChildRequestId))]

View file

@ -30,3 +30,20 @@ export interface ISearchTvResult {
firstSeason: boolean; firstSeason: boolean;
latestSeason: boolean; latestSeason: boolean;
} }
export interface ITvRequestViewModel {
requestAll: boolean;
firstSeason: boolean;
latestSeason: boolean;
tvDbId: number;
seasons: ISeasonsViewModel[];
}
export interface ISeasonsViewModel {
seasonNumber: number;
episodes: IEpisodesViewModel[];
}
export interface IEpisodesViewModel {
episodeNumber: number;
}

View file

@ -90,12 +90,6 @@ export class TvRequestsComponent implements OnInit {
} }
public ngOnInit() { public ngOnInit() {
const profile = <ISonarrProfile>{name:"test",id:1 };
const folder = <ISonarrRootFolder>{path:"testpath", id:1};
this.sonarrProfiles.push(profile);
this.sonarrRootFolders.push(folder);
this.amountToLoad = 1000; this.amountToLoad = 1000;
this.currentlyLoaded = 1000; this.currentlyLoaded = 1000;
this.tvRequests = []; this.tvRequests = [];
@ -204,7 +198,7 @@ export class TvRequestsComponent implements OnInit {
this.loadInit(); this.loadInit();
} }
private loadBackdrop(val: TreeNode): void { private loadBackdrop(val: TreeNode): void {
this.imageService.getTvBanner(val.data.id).subscribe(x => { this.imageService.getTvBanner(val.data.tvDbId).subscribe(x => {
val.data.background = this.sanitizer.bypassSecurityTrustStyle val.data.background = this.sanitizer.bypassSecurityTrustStyle
("url(" + x + ")"); ("url(" + x + ")");
}); });

View file

@ -5,7 +5,7 @@ import { NotificationService } from "../services";
import { RequestService } from "../services"; import { RequestService } from "../services";
import { SearchService } from "../services"; import { SearchService } from "../services";
import { INewSeasonRequests, IRequestEngineResult } from "../interfaces"; import { INewSeasonRequests, IRequestEngineResult, ISeasonsViewModel, ITvRequestViewModel } from "../interfaces";
import { IEpisodesRequests } from "../interfaces"; import { IEpisodesRequests } from "../interfaces";
import { ISearchTvResult } from "../interfaces"; import { ISearchTvResult } from "../interfaces";
@ -46,7 +46,22 @@ export class SeriesInformationComponent implements OnInit {
this.series.requested = true; this.series.requested = true;
this.requestService.requestTv(this.series) const viewModel = <ITvRequestViewModel>{ firstSeason: this.series.firstSeason, latestSeason: this.series.latestSeason, requestAll: this.series.requestAll, tvDbId: this.series.id};
viewModel.seasons = [];
this.series.seasonRequests.forEach((season) => {
const seasonsViewModel = <ISeasonsViewModel>{seasonNumber: season.seasonNumber, episodes: []};
season.episodes.forEach(ep => {
if(!this.series.latestSeason || !this.series.requestAll || !this.series.firstSeason) {
if(ep.requested) {
seasonsViewModel.episodes.push({episodeNumber: ep.episodeNumber});
}
}
});
viewModel.seasons.push(seasonsViewModel);
});
this.requestService.requestTv(viewModel)
.subscribe(x => { .subscribe(x => {
this.result = x as IRequestEngineResult; this.result = x as IRequestEngineResult;
if (this.result.result) { if (this.result.result) {

View file

@ -7,7 +7,7 @@ import { ImageService, NotificationService, RequestService, SearchService} from
import { TreeNode } from "primeng/primeng"; import { TreeNode } from "primeng/primeng";
import { IRequestEngineResult } from "../interfaces"; import { IRequestEngineResult } from "../interfaces";
import { IIssueCategory, ISearchTvResult } from "../interfaces"; import { IIssueCategory, ISearchTvResult, ISeasonsViewModel, ITvRequestViewModel } from "../interfaces";
@Component({ @Component({
selector: "tv-search", selector: "tv-search",
@ -154,7 +154,23 @@ export class TvSearchComponent implements OnInit {
if (this.authService.hasRole("admin") || this.authService.hasRole("AutoApproveMovie")) { if (this.authService.hasRole("admin") || this.authService.hasRole("AutoApproveMovie")) {
searchResult.approved = true; searchResult.approved = true;
} }
this.requestService.requestTv(searchResult)
const viewModel = <ITvRequestViewModel>{ firstSeason: searchResult.firstSeason, latestSeason: searchResult.latestSeason, requestAll: searchResult.requestAll, tvDbId: searchResult.id};
viewModel.seasons = [];
searchResult.seasonRequests.forEach((season) => {
const seasonsViewModel = <ISeasonsViewModel>{seasonNumber: season.seasonNumber, episodes: []};
season.episodes.forEach(ep => {
if(!searchResult.latestSeason || !searchResult.requestAll || !searchResult.firstSeason) {
if(ep.requested) {
seasonsViewModel.episodes.push({episodeNumber: ep.episodeNumber});
}
}
});
viewModel.seasons.push(seasonsViewModel);
});
this.requestService.requestTv(viewModel)
.subscribe(x => { .subscribe(x => {
this.result = x; this.result = x;
if (this.result.result) { if (this.result.result) {

View file

@ -7,7 +7,7 @@ import { Observable } from "rxjs/Rx";
import { TreeNode } from "primeng/primeng"; import { TreeNode } from "primeng/primeng";
import { IRequestEngineResult } from "../interfaces"; import { IRequestEngineResult } from "../interfaces";
import { IChildRequests, IFilter, IMovieRequestModel, IMovieRequests, IMovieUpdateModel, ITvRequests, ITvUpdateModel } from "../interfaces"; import { IChildRequests, IFilter, IMovieRequestModel, IMovieRequests, IMovieUpdateModel, ITvRequests, ITvUpdateModel } from "../interfaces";
import { ISearchTvResult } from "../interfaces"; import { ITvRequestViewModel } from "../interfaces";
import { ServiceHelpers } from "./service.helpers"; import { ServiceHelpers } from "./service.helpers";
@Injectable() @Injectable()
@ -20,7 +20,7 @@ export class RequestService extends ServiceHelpers {
return this.http.post<IRequestEngineResult>(`${this.url}Movie/`, JSON.stringify(movie), {headers: this.headers}); return this.http.post<IRequestEngineResult>(`${this.url}Movie/`, JSON.stringify(movie), {headers: this.headers});
} }
public requestTv(tv: ISearchTvResult): Observable<IRequestEngineResult> { public requestTv(tv: ITvRequestViewModel): Observable<IRequestEngineResult> {
return this.http.post<IRequestEngineResult>(`${this.url}TV/`, JSON.stringify(tv), {headers: this.headers}); return this.http.post<IRequestEngineResult>(`${this.url}TV/`, JSON.stringify(tv), {headers: this.headers});
} }

View file

@ -174,7 +174,7 @@ namespace Ombi.Controllers
/// <param name="tv">The tv.</param> /// <param name="tv">The tv.</param>
/// <returns></returns> /// <returns></returns>
[HttpPost("tv")] [HttpPost("tv")]
public async Task<RequestEngineResult> RequestTv([FromBody] SearchTvShowViewModel tv) public async Task<RequestEngineResult> RequestTv([FromBody] TvRequestViewModel tv)
{ {
return await TvRequestEngine.RequestTvShow(tv); return await TvRequestEngine.RequestTvShow(tv);
} }