From d15e09d34284bd480e5bd780f8452f271981775a Mon Sep 17 00:00:00 2001 From: Jamie Date: Wed, 28 Mar 2018 14:22:16 +0100 Subject: [PATCH 01/32] 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. --- .../Engine/Interfaces/ITvRequestEngine.cs | 3 +- src/Ombi.Core/Engine/TvRequestEngine.cs | 10 +-- src/Ombi.Core/Helpers/TvShowRequestBuilder.cs | 80 +++++++++++++------ .../Models/Requests/TvRequestViewModel.cs | 25 ++++++ .../Entities/Requests/SeasonRequests.cs | 2 +- .../app/interfaces/ISearchTvResult.ts | 17 ++++ .../app/requests/tvrequests.component.ts | 8 +- .../app/search/seriesinformation.component.ts | 19 ++++- .../app/search/tvsearch.component.ts | 20 ++++- .../ClientApp/app/services/request.service.ts | 4 +- src/Ombi/Controllers/RequestController.cs | 2 +- 11 files changed, 146 insertions(+), 44 deletions(-) create mode 100644 src/Ombi.Core/Models/Requests/TvRequestViewModel.cs 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); } From f760a1927e8b66d9d8732df7e3f79f5fee14a08a Mon Sep 17 00:00:00 2001 From: Jamie Date: Wed, 28 Mar 2018 20:44:38 +0100 Subject: [PATCH 02/32] Fixed the issue where movies were not appearing in the newsletter for users with Emby #2111 --- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index e9ec159e1..4448e922c 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -300,8 +300,14 @@ namespace Ombi.Schedule.Jobs.Ombi var ordered = embyContent.OrderByDescending(x => x.AddedAt); foreach (var content in ordered) { - int.TryParse(content.ProviderId, out var movieDbId); - var info = await _movieApi.GetMovieInformationWithExtraInfo(movieDbId); + var imdbId = content.ProviderId; + var findResult = await _movieApi.Find(imdbId, ExternalSource.imdb_id); + var result = findResult.movie_results?.FirstOrDefault(); + if(result == null) + { + continue; + } + var info = await _movieApi.GetMovieInformationWithExtraInfo(result.id); if (info == null) { continue; From 15d19ef3e82b6e3c4ebc4bd0fad8afec90ab0108 Mon Sep 17 00:00:00 2001 From: goldenpipes Date: Wed, 28 Mar 2018 18:44:03 -0500 Subject: [PATCH 03/32] Update _Layout.cshtml added "og" metadata tags for link previews. uses default ombi logo and @appName --- src/Ombi/Views/Shared/_Layout.cshtml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Ombi/Views/Shared/_Layout.cshtml b/src/Ombi/Views/Shared/_Layout.cshtml index 104481024..6cc93ffc1 100644 --- a/src/Ombi/Views/Shared/_Layout.cshtml +++ b/src/Ombi/Views/Shared/_Layout.cshtml @@ -63,8 +63,10 @@ O:::::::OOO:::::::Om::::m m::::m m::::mb:::::bbbbbb::::::bi::::::i @appName + + + - From 9ae62d5545c21707c5678583900bd29078196dbc Mon Sep 17 00:00:00 2001 From: goldenpipes Date: Wed, 28 Mar 2018 18:46:17 -0500 Subject: [PATCH 04/32] Update _Layout.cshtml --- src/Ombi/Views/Shared/_Layout.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ombi/Views/Shared/_Layout.cshtml b/src/Ombi/Views/Shared/_Layout.cshtml index 6cc93ffc1..cd7dd5596 100644 --- a/src/Ombi/Views/Shared/_Layout.cshtml +++ b/src/Ombi/Views/Shared/_Layout.cshtml @@ -64,7 +64,7 @@ O:::::::OOO:::::::Om::::m m::::m m::::mb:::::bbbbbb::::::bi::::::i @appName - + From b82c43356f00bd8c079a4ed5523cae1bcb5d5f52 Mon Sep 17 00:00:00 2001 From: Anojh Date: Sat, 31 Mar 2018 17:22:43 -0700 Subject: [PATCH 05/32] Adding wrappers and classes for LC and toggling active style for UI elements. --- .../app/requests/movierequests.component.html | 93 ++++++++++-------- .../app/requests/movierequests.component.ts | 13 ++- .../app/requests/tvrequests.component.ts | 14 ++- .../usermanagement-edit.component.html | 98 ++++++++++--------- .../usermanagement.component.html | 10 +- .../usermanagement.component.ts | 16 ++- 6 files changed, 143 insertions(+), 101 deletions(-) diff --git a/src/Ombi/ClientApp/app/requests/movierequests.component.html b/src/Ombi/ClientApp/app/requests/movierequests.component.html index f798e4b70..6b2300f38 100644 --- a/src/Ombi/ClientApp/app/requests/movierequests.component.html +++ b/src/Ombi/ClientApp/app/requests/movierequests.component.html @@ -14,32 +14,32 @@