diff --git a/src/Ombi.Core/Engine/V2/TvSearchEngineV2.cs b/src/Ombi.Core/Engine/V2/TvSearchEngineV2.cs index 791298c6b..31fd458c5 100644 --- a/src/Ombi.Core/Engine/V2/TvSearchEngineV2.cs +++ b/src/Ombi.Core/Engine/V2/TvSearchEngineV2.cs @@ -130,6 +130,7 @@ namespace Ombi.Core.Engine.V2 item.Requested = oldModel.Requested; item.Available = oldModel.Available; item.Approved = oldModel.Approved; + item.SeasonRequests = oldModel.SeasonRequests; return await GetExtraInfo(showInfoTask, item); } diff --git a/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs b/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs index 503296400..08637ca7f 100644 --- a/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs +++ b/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs @@ -12,6 +12,14 @@ namespace Ombi.Core.Rule.Rules.Search { public static void CheckForUnairedEpisodes(SearchTvShowViewModel search) { + foreach (var season in search.SeasonRequests) + { + // If we have all the episodes for this season, then this season is available + if (season.Episodes.All(x => x.Available)) + { + season.SeasonAvailable = true; + } + } if (search.SeasonRequests.All(x => x.Episodes.All(e => e.Available))) { search.FullyAvailable = true; diff --git a/src/Ombi.Store/Entities/Requests/SeasonRequests.cs b/src/Ombi.Store/Entities/Requests/SeasonRequests.cs index 6abaa4de3..ea9f74547 100644 --- a/src/Ombi.Store/Entities/Requests/SeasonRequests.cs +++ b/src/Ombi.Store/Entities/Requests/SeasonRequests.cs @@ -16,6 +16,7 @@ namespace Ombi.Store.Repository.Requests public int ChildRequestId { get; set; } [ForeignKey(nameof(ChildRequestId))] public ChildRequests ChildRequest { get; set; } + [NotMapped] public bool SeasonAvailable { get; set; } } public class EpisodeRequests : Entity diff --git a/src/Ombi/ClientApp/src/app/discover/card/discover-card-details.component.html b/src/Ombi/ClientApp/src/app/discover/card/discover-card-details.component.html index e3148ef1c..2d326e890 100644 --- a/src/Ombi/ClientApp/src/app/discover/card/discover-card-details.component.html +++ b/src/Ombi/ClientApp/src/app/discover/card/discover-card-details.component.html @@ -107,6 +107,15 @@
+ + + + + +
+ + \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/shared/episode-request/episode-request.component.ts b/src/Ombi/ClientApp/src/app/shared/episode-request/episode-request.component.ts new file mode 100644 index 000000000..0d0c5e080 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/shared/episode-request/episode-request.component.ts @@ -0,0 +1,91 @@ +import { Component, OnInit, Inject } from "@angular/core"; +import { MatDialogRef, MAT_DIALOG_DATA, MatCheckboxChange } from "@angular/material"; +import { ISearchTvResultV2 } from "../../interfaces/ISearchTvResultV2"; +import { RequestService, NotificationService } from "../../services"; +import { ITvRequestViewModel, ISeasonsViewModel, IEpisodesRequests, INewSeasonRequests } from "../../interfaces"; + + +@Component({ + selector: "episode-request", + templateUrl: "episode-request.component.html", +}) +export class EpisodeRequestComponent implements OnInit { + + public loading: boolean; + + constructor(public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public series: ISearchTvResultV2, + private requestService: RequestService, private notificationService: NotificationService) { } + + public ngOnInit() { + this.loading = true; + + this.loading = false; + } + + public submitRequests() { + // Make sure something has been selected + const selected = this.series.seasonRequests.some((season) => { + return season.episodes.some((ep) => { + return ep.selected; + }); + }); + + if (!selected) { + this.notificationService.error("You need to select some episodes!"); + return; + } + + this.series.requested = true; + + 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 => { + ep.requested = true; + if (!this.series.latestSeason || !this.series.requestAll || !this.series.firstSeason) { + if (ep.selected) { + seasonsViewModel.episodes.push({ episodeNumber: ep.episodeNumber }); + } + } + }); + + viewModel.seasons.push(seasonsViewModel); + }); + + this.requestService.requestTv(viewModel) + .subscribe(x => { + if (x.result) { + this.notificationService.success( + `Request for ${this.series.title} has been added successfully`); + + this.series.seasonRequests.forEach((season) => { + season.episodes.forEach((ep) => { + ep.selected = false; + }); + }); + + } else { + this.notificationService.warning("Request Added", x.errorMessage ? x.errorMessage : x.message); + } + }); + } + + public addRequest(episode: IEpisodesRequests) { + episode.selected = true; + } + + public removeRequest(episode: IEpisodesRequests) { + episode.selected = false; + } + + public seasonChanged(checkbox: MatCheckboxChange, season: INewSeasonRequests) { + season.episodes.forEach((ep) => { + if (checkbox.checked) { + this.addRequest(ep) + } else { + this.removeRequest(ep); + } + }); + } +} diff --git a/src/Ombi/ClientApp/src/styles/shared.scss b/src/Ombi/ClientApp/src/styles/shared.scss index 8d6bf5bec..aa53378f7 100644 --- a/src/Ombi/ClientApp/src/styles/shared.scss +++ b/src/Ombi/ClientApp/src/styles/shared.scss @@ -17,4 +17,21 @@ .bottom-page-gap { height: 50px; -} \ No newline at end of file +} + + +/* Scrollbar */ +::-webkit-scrollbar { + width: 7px; + background: rgba(0, 0, 0, 0); + } + ::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0); + } + ::-webkit-scrollbar-thumb { + border-radius: 3px; + background: #41927b; + } + .sidenav ::-webkit-scrollbar-track { + display: none; + } \ No newline at end of file