diff --git a/src/Ombi.Core/Engine/Interfaces/ITvRequestEngine.cs b/src/Ombi.Core/Engine/Interfaces/ITvRequestEngine.cs index 30f415aad..28eb066d4 100644 --- a/src/Ombi.Core/Engine/Interfaces/ITvRequestEngine.cs +++ b/src/Ombi.Core/Engine/Interfaces/ITvRequestEngine.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Ombi.Core.Models.Requests; using Ombi.Core.Models.Search; using Ombi.Store.Entities.Requests; @@ -9,7 +10,7 @@ namespace Ombi.Core.Engine.Interfaces { Task RemoveTvRequest(int requestId); - Task RequestTvShow(SearchTvShowViewModel tv); + Task RequestTvShow(TvRequestViewModel tv); Task DenyChildRequest(int requestId); Task> SearchTvRequest(string search); Task>>> SearchTvRequestTree(string search); diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index f8fc33e9b..aaa2d353d 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -43,13 +43,13 @@ namespace Ombi.Core.Engine private IAuditRepository Audit { get; } private readonly IRepository _requestLog; - public async Task RequestTvShow(SearchTvShowViewModel tv) + public async Task RequestTvShow(TvRequestViewModel tv) { var user = await GetUser(); var tvBuilder = new TvShowRequestBuilder(TvApi); (await tvBuilder - .GetShowInfo(tv.Id)) + .GetShowInfo(tv.TvDbId)) .CreateTvList(tv) .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) { // Remove requests we already have, we just want new ones @@ -127,7 +127,7 @@ namespace Ombi.Core.Engine var newRequest = tvBuilder.CreateNewRequest(tv); return await AddRequest(newRequest.NewRequest); } - + public async Task> GetRequests(int count, int position) { var shouldHide = await HideFromOtherUsers(); diff --git a/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs b/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs index 0d5d46c54..1f92536b8 100644 --- a/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs +++ b/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; using Ombi.Api.TvMaze; using Ombi.Api.TvMaze.Models; +using Ombi.Core.Models.Requests; using Ombi.Core.Models.Search; using Ombi.Helpers; using Ombi.Store.Entities; @@ -23,7 +24,7 @@ namespace Ombi.Core.Helpers private ITvMazeApi TvApi { get; } public ChildRequests ChildRequest { get; set; } - public List TvRequests { get; protected set; } + public List TvRequests { get; protected set; } public string PosterPath { get; protected set; } public DateTime FirstAir { get; protected set; } public TvRequests NewRequest { get; protected set; } @@ -33,7 +34,7 @@ namespace Ombi.Core.Helpers { ShowInfo = await TvApi.ShowLookupByTheTvDbId(id); - DateTime.TryParse(ShowInfo.premiered, out DateTime dt); + DateTime.TryParse(ShowInfo.premiered, out var dt); FirstAir = dt; @@ -43,37 +44,29 @@ namespace Ombi.Core.Helpers return this; } - public TvShowRequestBuilder CreateChild(SearchTvShowViewModel model, string userId) + public TvShowRequestBuilder CreateChild(TvRequestViewModel model, string userId) { ChildRequest = new ChildRequests { - Id = model.Id, + Id = model.TvDbId, RequestType = RequestType.TvShow, RequestedDate = DateTime.UtcNow, Approved = false, RequestedUserId = userId, SeasonRequests = new List(), - Title = model.Title, + Title = ShowInfo.name, SeriesType = ShowInfo.type.Equals("Animation", StringComparison.CurrentCultureIgnoreCase) ? SeriesType.Anime : SeriesType.Standard }; return this; } - public TvShowRequestBuilder CreateTvList(SearchTvShowViewModel tv) + public TvShowRequestBuilder CreateTvList(TvRequestViewModel tv) { - TvRequests = new List(); + TvRequests = new List(); // 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()) { TvRequests.Add(season); @@ -81,11 +74,10 @@ namespace Ombi.Core.Helpers } return this; - } - public async Task BuildEpisodes(SearchTvShowViewModel tv) + public async Task BuildEpisodes(TvRequestViewModel tv) { if (tv.RequestAll) { @@ -173,26 +165,68 @@ namespace Ombi.Core.Helpers else { // It's a custom request - ChildRequest.SeasonRequests = TvRequests; + var seasonRequests = new List(); + 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; } - public TvShowRequestBuilder CreateNewRequest(SearchTvShowViewModel tv) + public TvShowRequestBuilder CreateNewRequest(TvRequestViewModel tv) { NewRequest = new TvRequests { - Id = tv.Id, Overview = ShowInfo.summary.RemoveHtml(), PosterPath = PosterPath, Title = ShowInfo.name, ReleaseDate = FirstAir, Status = ShowInfo.status, ImdbId = ShowInfo.externals?.imdb ?? string.Empty, - TvDbId = tv.Id, + TvDbId = tv.TvDbId, ChildRequests = new List(), - TotalSeasons = tv.SeasonRequests.Count() + TotalSeasons = tv.Seasons.Count() }; NewRequest.ChildRequests.Add(ChildRequest); diff --git a/src/Ombi.Core/Models/Requests/TvRequestViewModel.cs b/src/Ombi.Core/Models/Requests/TvRequestViewModel.cs new file mode 100644 index 000000000..78f9edd6d --- /dev/null +++ b/src/Ombi.Core/Models/Requests/TvRequestViewModel.cs @@ -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 Seasons { get; set; } = new List(); + } + + public class SeasonsViewModel + { + public int SeasonNumber { get; set; } + public List Episodes { get; set; } = new List(); + } + + public class EpisodesViewModel + { + public int EpisodeNumber { get; set; } + } + +} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/Requests/SeasonRequests.cs b/src/Ombi.Store/Entities/Requests/SeasonRequests.cs index 496f1988d..521cf5b94 100644 --- a/src/Ombi.Store/Entities/Requests/SeasonRequests.cs +++ b/src/Ombi.Store/Entities/Requests/SeasonRequests.cs @@ -10,7 +10,7 @@ namespace Ombi.Store.Repository.Requests public class SeasonRequests : Entity { public int SeasonNumber { get; set; } - public List Episodes { get; set; } + public List Episodes { get; set; } = new List(); public int ChildRequestId { get; set; } [ForeignKey(nameof(ChildRequestId))] diff --git a/src/Ombi/ClientApp/app/interfaces/ISearchTvResult.ts b/src/Ombi/ClientApp/app/interfaces/ISearchTvResult.ts index 5ed9567f5..f0afa76b2 100644 --- a/src/Ombi/ClientApp/app/interfaces/ISearchTvResult.ts +++ b/src/Ombi/ClientApp/app/interfaces/ISearchTvResult.ts @@ -30,3 +30,20 @@ export interface ISearchTvResult { firstSeason: 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; +} diff --git a/src/Ombi/ClientApp/app/requests/tvrequests.component.ts b/src/Ombi/ClientApp/app/requests/tvrequests.component.ts index 7a1e37595..a09d49bca 100644 --- a/src/Ombi/ClientApp/app/requests/tvrequests.component.ts +++ b/src/Ombi/ClientApp/app/requests/tvrequests.component.ts @@ -90,12 +90,6 @@ export class TvRequestsComponent implements OnInit { } public ngOnInit() { - - const profile = {name:"test",id:1 }; - const folder = {path:"testpath", id:1}; - - this.sonarrProfiles.push(profile); - this.sonarrRootFolders.push(folder); this.amountToLoad = 1000; this.currentlyLoaded = 1000; this.tvRequests = []; @@ -204,7 +198,7 @@ export class TvRequestsComponent implements OnInit { this.loadInit(); } 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 ("url(" + x + ")"); }); diff --git a/src/Ombi/ClientApp/app/search/seriesinformation.component.ts b/src/Ombi/ClientApp/app/search/seriesinformation.component.ts index 74fcb4b3e..c4a50ae38 100644 --- a/src/Ombi/ClientApp/app/search/seriesinformation.component.ts +++ b/src/Ombi/ClientApp/app/search/seriesinformation.component.ts @@ -5,7 +5,7 @@ import { NotificationService } from "../services"; import { RequestService } from "../services"; import { SearchService } from "../services"; -import { INewSeasonRequests, IRequestEngineResult } from "../interfaces"; +import { INewSeasonRequests, IRequestEngineResult, ISeasonsViewModel, ITvRequestViewModel } from "../interfaces"; import { IEpisodesRequests } from "../interfaces"; import { ISearchTvResult } from "../interfaces"; @@ -46,7 +46,22 @@ export class SeriesInformationComponent implements OnInit { this.series.requested = true; - this.requestService.requestTv(this.series) + const viewModel = { 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 = {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 => { this.result = x as IRequestEngineResult; if (this.result.result) { diff --git a/src/Ombi/ClientApp/app/search/tvsearch.component.ts b/src/Ombi/ClientApp/app/search/tvsearch.component.ts index aa3cf20db..961e85f63 100644 --- a/src/Ombi/ClientApp/app/search/tvsearch.component.ts +++ b/src/Ombi/ClientApp/app/search/tvsearch.component.ts @@ -7,7 +7,7 @@ import { ImageService, NotificationService, RequestService, SearchService} from import { TreeNode } from "primeng/primeng"; import { IRequestEngineResult } from "../interfaces"; -import { IIssueCategory, ISearchTvResult } from "../interfaces"; +import { IIssueCategory, ISearchTvResult, ISeasonsViewModel, ITvRequestViewModel } from "../interfaces"; @Component({ selector: "tv-search", @@ -154,7 +154,23 @@ export class TvSearchComponent implements OnInit { if (this.authService.hasRole("admin") || this.authService.hasRole("AutoApproveMovie")) { searchResult.approved = true; } - this.requestService.requestTv(searchResult) + + const viewModel = { firstSeason: searchResult.firstSeason, latestSeason: searchResult.latestSeason, requestAll: searchResult.requestAll, tvDbId: searchResult.id}; + viewModel.seasons = []; + searchResult.seasonRequests.forEach((season) => { + const seasonsViewModel = {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 => { this.result = x; if (this.result.result) { diff --git a/src/Ombi/ClientApp/app/services/request.service.ts b/src/Ombi/ClientApp/app/services/request.service.ts index 12615e776..a2757427d 100644 --- a/src/Ombi/ClientApp/app/services/request.service.ts +++ b/src/Ombi/ClientApp/app/services/request.service.ts @@ -7,7 +7,7 @@ import { Observable } from "rxjs/Rx"; import { TreeNode } from "primeng/primeng"; import { IRequestEngineResult } 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"; @Injectable() @@ -20,7 +20,7 @@ export class RequestService extends ServiceHelpers { return this.http.post(`${this.url}Movie/`, JSON.stringify(movie), {headers: this.headers}); } - public requestTv(tv: ISearchTvResult): Observable { + public requestTv(tv: ITvRequestViewModel): Observable { return this.http.post(`${this.url}TV/`, JSON.stringify(tv), {headers: this.headers}); } diff --git a/src/Ombi/Controllers/RequestController.cs b/src/Ombi/Controllers/RequestController.cs index d5c173d35..59bd75606 100644 --- a/src/Ombi/Controllers/RequestController.cs +++ b/src/Ombi/Controllers/RequestController.cs @@ -174,7 +174,7 @@ namespace Ombi.Controllers /// The tv. /// [HttpPost("tv")] - public async Task RequestTv([FromBody] SearchTvShowViewModel tv) + public async Task RequestTv([FromBody] TvRequestViewModel tv) { return await TvRequestEngine.RequestTvShow(tv); }