stuff around episode/season searching/requesting

This commit is contained in:
Jamie.Rees 2017-05-08 13:32:04 +01:00
parent 07f5c77c3c
commit b829b10b14
24 changed files with 357 additions and 191 deletions

View file

@ -34,7 +34,7 @@ namespace Ombi.Api.TvMaze.Models
public class TvMazeCustomSeason public class TvMazeCustomSeason
{ {
public int SeasonNumber { get; set; } public int SeasonNumber { get; set; }
public int EpisodeNumber { get; set; } public List<int> EpisodeNumber { get; set; }
} }
public class Season public class Season

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -60,12 +61,26 @@ namespace Ombi.Api.TvMaze
foreach (var e in episodes) foreach (var e in episodes)
{ {
// Check if the season exists
var currentSeason = obj.Season.FirstOrDefault(x => x.SeasonNumber == e.season);
if (currentSeason == null)
{
// Create the season
obj.Season.Add(new TvMazeCustomSeason obj.Season.Add(new TvMazeCustomSeason
{ {
SeasonNumber = e.season, SeasonNumber = e.season,
EpisodeNumber = e.number EpisodeNumber = new List<int> {e.number}
}); });
} }
else
{
// Just add a new episode into that season
currentSeason.EpisodeNumber.Add(e.number);
}
}
return obj; return obj;
} }

View file

@ -2,11 +2,13 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine.Interfaces
{ {
public interface ITvSearchEngine public interface ITvSearchEngine
{ {
Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm); Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm);
Task<SearchTvShowViewModel> GetShowInformation(int tvdbId);
//Task<IEnumerable<SearchTvShowViewModel>> Popular(); //Task<IEnumerable<SearchTvShowViewModel>> Popular();
//Task<IEnumerable<SearchTvShowViewModel>> Anticipated(); //Task<IEnumerable<SearchTvShowViewModel>> Anticipated();
//Task<IEnumerable<SearchTvShowViewModel>> MostWatches(); //Task<IEnumerable<SearchTvShowViewModel>> MostWatches();

View file

@ -49,10 +49,32 @@ namespace Ombi.Core.Engine
ImdbId = showInfo.externals?.imdb ?? string.Empty, ImdbId = showInfo.externals?.imdb ?? string.Empty,
TvDbId = tv.Id.ToString(), TvDbId = tv.Id.ToString(),
ProviderId = tv.Id, ProviderId = tv.Id,
SeasonsNumbersRequested = tv.SeasonNumbersRequested,
RequestAll = tv.RequestAll RequestAll = tv.RequestAll
}; };
if (tv.LatestSeason)
{
var latest = showInfo.Season.OrderBy(x => x).FirstOrDefault();
model.SeasonRequests = showInfo.Season.Any()
? new List<SeasonRequestModel> {new SeasonRequestModel
{
SeasonNumber = latest.SeasonNumber,
Episodes = latest.EpisodeNumber
}}
: new List<SeasonRequestModel>();
}
if (tv.FirstSeason)
{
var first = showInfo.Season.OrderByDescending(x => x).FirstOrDefault();
model.SeasonRequests = showInfo.Season.Any()
? new List<SeasonRequestModel> {new SeasonRequestModel
{
SeasonNumber = first.SeasonNumber,
Episodes = first.EpisodeNumber
}}
: new List<SeasonRequestModel>();
}
var existingRequest = await TvRequestService.CheckRequestAsync(model.Id); var existingRequest = await TvRequestService.CheckRequestAsync(model.Id);
if (existingRequest != null) if (existingRequest != null)
@ -104,13 +126,13 @@ namespace Ombi.Core.Engine
private async Task<RequestEngineResult> AddExistingRequest(TvRequestModel newRequest, TvRequestModel existingRequest) private async Task<RequestEngineResult> AddExistingRequest(TvRequestModel newRequest, TvRequestModel existingRequest)
{ {
var episodeDifference = new List<EpisodesModel>(); var episodeDifference = new List<SeasonRequestModel>();
if (existingRequest.HasChildRequests) if (existingRequest.HasChildRequests)
{ {
// Let's check if this has already been requested as a child! // Let's check if this has already been requested as a child!
foreach (var children in existingRequest.ChildRequests) foreach (var children in existingRequest.ChildRequests)
{ {
var difference = GetListDifferences(children.Episodes, newRequest.Episodes).ToList(); var difference = GetListDifferences(children.SeasonRequests, newRequest.SeasonRequests).ToList();
if (difference.Any()) if (difference.Any())
{ {
episodeDifference = difference; episodeDifference = difference;
@ -121,7 +143,7 @@ namespace Ombi.Core.Engine
if (episodeDifference.Any()) if (episodeDifference.Any())
{ {
// This is where there are some episodes that have been requested, but this list contains the 'new' requests // This is where there are some episodes that have been requested, but this list contains the 'new' requests
newRequest.Episodes = episodeDifference; newRequest.SeasonRequests = episodeDifference;
} }
existingRequest.ChildRequests.Add(newRequest); existingRequest.ChildRequests.Add(newRequest);
@ -132,17 +154,17 @@ namespace Ombi.Core.Engine
{ {
// TODO Auto Approval Code // TODO Auto Approval Code
} }
return await AddRequest(newRequest); return await AfterRequest(newRequest);
} }
private IEnumerable<EpisodesModel> GetListDifferences(IEnumerable<EpisodesModel> existing, IEnumerable<EpisodesModel> request) private IEnumerable<SeasonRequestModel> GetListDifferences(IEnumerable<SeasonRequestModel> existing, IEnumerable<SeasonRequestModel> request)
{ {
var newRequest = request var newRequest = request
.Select(r => .Select(r =>
new EpisodesModel new SeasonRequestModel
{ {
SeasonNumber = r.SeasonNumber, SeasonNumber = r.SeasonNumber,
EpisodeNumber = r.EpisodeNumber Episodes = r.Episodes
}).ToList(); }).ToList();
return newRequest.Except(existing); return newRequest.Except(existing);
@ -152,6 +174,11 @@ namespace Ombi.Core.Engine
{ {
await TvRequestService.AddRequestAsync(model); await TvRequestService.AddRequestAsync(model);
return await AfterRequest(model);
}
private async Task<RequestEngineResult> AfterRequest(BaseRequestModel model)
{
if (ShouldSendNotification(model.Type)) if (ShouldSendNotification(model.Type))
{ {
var notificationModel = new NotificationModel var notificationModel = new NotificationModel

View file

@ -5,6 +5,8 @@ using System.Threading.Tasks;
using AutoMapper; using AutoMapper;
using Ombi.Api.Trakt; using Ombi.Api.Trakt;
using Ombi.Api.TvMaze; using Ombi.Api.TvMaze;
using Ombi.Api.TvMaze.Models;
using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Requests.Models; using Ombi.Core.Requests.Models;
@ -46,6 +48,12 @@ namespace Ombi.Core.Engine
return null; return null;
} }
public async Task<SearchTvShowViewModel> GetShowInformation(int tvdbId)
{
var show = await TvMazeApi.ShowLookupByTheTvDbId(tvdbId);
return Mapper.Map<SearchTvShowViewModel>(show);
}
//public async Task<IEnumerable<SearchTvShowViewModel>> Popular() //public async Task<IEnumerable<SearchTvShowViewModel>> Popular()
//{ //{
// var result = await TraktApi.GetPopularShows(); // var result = await TraktApi.GetPopularShows();
@ -113,7 +121,7 @@ namespace Ombi.Core.Engine
var dbt = existingRequests[tvdbid]; var dbt = existingRequests[tvdbid];
item.Requested = true; item.Requested = true;
item.EpisodesRequested = dbt.Episodes.ToList(); item.SeasonRequests = dbt.SeasonRequests.ToList();
item.Approved = dbt.Approved; item.Approved = dbt.Approved;
} }
//if (sonarrCached.Select(x => x.TvdbId).Contains(tvdbid) || sickRageCache.Contains(tvdbid)) //if (sonarrCached.Select(x => x.TvdbId).Contains(tvdbid) || sickRageCache.Contains(tvdbid))

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using Ombi.Store.Entities; using Ombi.Store.Entities;
namespace Ombi.Core.Models.Requests namespace Ombi.Core.Models.Requests
@ -54,4 +55,11 @@ namespace Ombi.Core.Models.Requests
return hashSeason + hashEp; return hashSeason + hashEp;
} }
} }
public class SeasonRequestModel
{
public int SeasonNumber { get; set; }
public List<int> Episodes { get; set; }
}
} }

View file

@ -6,15 +6,14 @@ namespace Ombi.Core.Models.Requests
{ {
public TvRequestModel() public TvRequestModel()
{ {
Episodes = new List<EpisodesModel>(); SeasonRequests = new List<SeasonRequestModel>();
ChildRequests = new List<TvRequestModel>(); ChildRequests = new List<TvRequestModel>();
} }
public string ImdbId { get; set; } public string ImdbId { get; set; }
public string TvDbId { get; set; } public string TvDbId { get; set; }
public bool RequestAll { get; set; } public bool RequestAll { get; set; }
public List<int> SeasonsNumbersRequested { get; set; } public List<SeasonRequestModel> SeasonRequests { get; set; }
public List<EpisodesModel> Episodes { get; set; }
/// <summary> /// <summary>
/// This is for TV requests, If there is more than 1 request for a show then it should be a child /// This is for TV requests, If there is more than 1 request for a show then it should be a child

View file

@ -39,22 +39,14 @@ namespace Ombi.Core.Models.Search
/// </value> /// </value>
public string Homepage { get; set; } public string Homepage { get; set; }
/// <summary> public List<SeasonRequestModel> SeasonRequests { get; set; } = new List<SeasonRequestModel>();
/// This is for when the users requests multiple seasons or a single season
/// </summary>
public List<int> SeasonNumbersRequested { get; set; } = new List<int>();
/// <summary>
/// If we have requested some episodes
/// </summary>
public List<EpisodesModel> EpisodesRequested { get; set; } = new List<EpisodesModel>();
/// <summary> /// <summary>
/// If we are requesting the entire series /// If we are requesting the entire series
/// </summary> /// </summary>
public bool RequestAll { get; set; } public bool RequestAll { get; set; }
public bool SpecificSeasonsRequested => SeasonNumbersRequested.Count > 0; public bool FirstSeason { get; set; }
public bool SpecificEpisodesRequested => EpisodesRequested.Count > 0; public bool LatestSeason { get; set; }
} }
} }

View file

@ -1,10 +1,6 @@
using System; using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using System.Security.Principal;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Ombi.Api.Emby; using Ombi.Api.Emby;
using Ombi.Api.Plex; using Ombi.Api.Plex;
@ -13,6 +9,7 @@ using Ombi.Api.TheMovieDb;
using Ombi.Api.TvMaze; using Ombi.Api.TvMaze;
using Ombi.Core; using Ombi.Core;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Engine.Interfaces;
using Ombi.Core.IdentityResolver; using Ombi.Core.IdentityResolver;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Requests.Models; using Ombi.Core.Requests.Models;
@ -23,14 +20,13 @@ using Ombi.Schedule.Jobs;
using Ombi.Settings.Settings; using Ombi.Settings.Settings;
using Ombi.Store.Context; using Ombi.Store.Context;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Ombi.TheMovieDbApi;
namespace Ombi.DependencyInjection namespace Ombi.DependencyInjection
{ {
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class IocExtensions public static class IocExtensions
{ {
public static IServiceCollection RegisterDependencies(this IServiceCollection services) public static void RegisterDependencies(this IServiceCollection services)
{ {
services.RegisterEngines(); services.RegisterEngines();
services.RegisterApi(); services.RegisterApi();
@ -38,30 +34,26 @@ namespace Ombi.DependencyInjection
services.RegisterStore(); services.RegisterStore();
services.RegisterIdentity(); services.RegisterIdentity();
services.RegisterJobs(); services.RegisterJobs();
return services;
} }
public static IServiceCollection RegisterEngines(this IServiceCollection services) public static void RegisterEngines(this IServiceCollection services)
{ {
services.AddTransient<IMovieEngine, MovieSearchEngine>(); services.AddTransient<IMovieEngine, MovieSearchEngine>();
services.AddTransient<IMovieRequestEngine, MovieRequestEngine>(); services.AddTransient<IMovieRequestEngine, MovieRequestEngine>();
services.AddTransient<ITvRequestEngine, TvRequestEngine>(); services.AddTransient<ITvRequestEngine, TvRequestEngine>();
services.AddTransient<ITvSearchEngine, TvSearchEngine>(); services.AddTransient<ITvSearchEngine, TvSearchEngine>();
return services;
} }
public static IServiceCollection RegisterApi(this IServiceCollection services) public static void RegisterApi(this IServiceCollection services)
{ {
services.AddTransient<IMovieDbApi, Api.TheMovieDb.TheMovieDbApi>(); services.AddTransient<IMovieDbApi, Api.TheMovieDb.TheMovieDbApi>();
services.AddTransient<IPlexApi, PlexApi>(); services.AddTransient<IPlexApi, PlexApi>();
services.AddTransient<IEmbyApi, EmbyApi>(); services.AddTransient<IEmbyApi, EmbyApi>();
services.AddTransient<ISonarrApi, SonarrApi>(); services.AddTransient<ISonarrApi, SonarrApi>();
services.AddTransient<ITvMazeApi, TvMazeApi>(); services.AddTransient<ITvMazeApi, TvMazeApi>();
return services;
} }
public static IServiceCollection RegisterStore(this IServiceCollection services) public static void RegisterStore(this IServiceCollection services)
{ {
services.AddEntityFrameworkSqlite().AddDbContext<OmbiContext>(); services.AddEntityFrameworkSqlite().AddDbContext<OmbiContext>();
@ -72,29 +64,22 @@ namespace Ombi.DependencyInjection
services.AddTransient<ISettingsResolver, SettingsResolver>(); services.AddTransient<ISettingsResolver, SettingsResolver>();
services.AddTransient<IPlexContentRepository, PlexContentRepository>(); services.AddTransient<IPlexContentRepository, PlexContentRepository>();
services.AddTransient(typeof(ISettingsService<>), typeof(SettingsServiceV2<>)); services.AddTransient(typeof(ISettingsService<>), typeof(SettingsServiceV2<>));
return services;
} }
public static IServiceCollection RegisterServices(this IServiceCollection services) public static void RegisterServices(this IServiceCollection services)
{ {
services.AddTransient<IRequestServiceMain, RequestService>(); services.AddTransient<IRequestServiceMain, RequestService>();
services.AddTransient(typeof(IRequestService<>), typeof(JsonRequestService<>)); services.AddTransient(typeof(IRequestService<>), typeof(JsonRequestService<>));
services.AddSingleton<INotificationService, NotificationService>(); services.AddSingleton<INotificationService, NotificationService>();
return services;
} }
public static IServiceCollection RegisterJobs(this IServiceCollection services) public static void RegisterJobs(this IServiceCollection services)
{ {
services.AddTransient<IPlexContentCacher, PlexContentCacher>(); services.AddTransient<IPlexContentCacher, PlexContentCacher>();
services.AddTransient<IJobSetup, JobSetup>(); services.AddTransient<IJobSetup, JobSetup>();
return services;
} }
public static IServiceCollection RegisterIdentity(this IServiceCollection services) public static void RegisterIdentity(this IServiceCollection services)
{ {
services.AddTransient<IUserIdentityManager, UserIdentityManager>(); services.AddTransient<IUserIdentityManager, UserIdentityManager>();
services.AddAuthorization(auth => services.AddAuthorization(auth =>
{ {
@ -102,7 +87,6 @@ namespace Ombi.DependencyInjection
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build()); .RequireAuthenticatedUser().Build());
}); });
return services;
} }
} }
} }

View file

@ -5,5 +5,6 @@ namespace Ombi.Helpers
public class LoggingEvents public class LoggingEvents
{ {
public static EventId ApiException => new EventId(1000); public static EventId ApiException => new EventId(1000);
public static EventId CacherException => new EventId(2000);
} }
} }

View file

@ -2,6 +2,7 @@
using System.Globalization; using System.Globalization;
using AutoMapper; using AutoMapper;
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 TraktApiSharp.Objects.Get.Shows; //using TraktApiSharp.Objects.Get.Shows;
@ -24,9 +25,26 @@ namespace Ombi.Mapping.Profiles
.ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.show.runtime.ToString())) .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.show.runtime.ToString()))
.ForMember(dest => dest.SeriesId, opts => opts.MapFrom(src => src.show.id)) .ForMember(dest => dest.SeriesId, opts => opts.MapFrom(src => src.show.id))
.ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.show.name)) .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.show.name))
.ForMember(dest => dest.Banner, opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.show.image.medium) ? src.show.image.medium.Replace("http","https") : string.Empty)) .ForMember(dest => dest.Banner, opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.show.image.medium) ? src.show.image.medium.Replace("http", "https") : string.Empty))
.ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.show.status)); .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.show.status));
CreateMap<TvMazeCustomSeason, SeasonRequestModel>()
.ConstructUsing(x => new SeasonRequestModel { Episodes = x.EpisodeNumber, SeasonNumber = x.SeasonNumber });
CreateMap<TvMazeShow, SearchTvShowViewModel>()
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.externals.thetvdb))
.ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.premiered))
.ForMember(dest => dest.ImdbId, opts => opts.MapFrom(src => src.externals.imdb))
.ForMember(dest => dest.Network, opts => opts.MapFrom(src => src.network.name))
.ForMember(dest => dest.NetworkId, opts => opts.MapFrom(src => src.network.id.ToString()))
.ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.summary.RemoveHtml()))
.ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.rating.ToString()))
.ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.runtime.ToString(CultureInfo.CurrentUICulture)))
.ForMember(dest => dest.SeriesId, opts => opts.MapFrom(src => src.id))
.ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.name))
.ForMember(dest => dest.Banner, opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.image.medium) ? src.image.medium.Replace("http", "https") : string.Empty))
.ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.status))
.ForMember(dest => dest.SeasonRequests, opts => opts.MapFrom(src => src.Season));
//CreateMap<TraktShow, SearchTvShowViewModel>() //CreateMap<TraktShow, SearchTvShowViewModel>()
// .ForMember(dest => dest.Id, opts => opts.MapFrom(src => Convert.ToInt32(src.Ids.Tvdb.ToString()))) // .ForMember(dest => dest.Id, opts => opts.MapFrom(src => Convert.ToInt32(src.Ids.Tvdb.ToString())))
// .ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.FirstAired.HasValue ? src.FirstAired.Value.ToString("yyyy-MM-ddTHH:mm:ss") : string.Empty)) // .ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.FirstAired.HasValue ? src.FirstAired.Value.ToString("yyyy-MM-ddTHH:mm:ss") : string.Empty))

View file

@ -68,13 +68,14 @@ namespace Ombi.Schedule.Jobs
} }
Logger.LogInformation("Starting Plex Content Cacher"); Logger.LogInformation("Starting Plex Content Cacher");
//TODO try
StartTheCache(plexSettings).Wait(); {
//if (libraries == null || !libraries.Any()) StartTheCache(plexSettings).Wait();
//{ }
// return; catch (Exception e) {
//} Logger.LogWarning(LoggingEvents.CacherException, e, "Exception thrown when attempting to cache the Plex Content");
}
} }
//private List<PlexLibraries> CachedLibraries(PlexSettings plexSettings) //private List<PlexLibraries> CachedLibraries(PlexSettings plexSettings)
//{ //{
@ -122,9 +123,9 @@ namespace Ombi.Schedule.Jobs
// Let's now process this. // Let's now process this.
var contentToAdd = new List<PlexContent>();
foreach (var content in allContent) foreach (var content in allContent)
{ {
var contentToAdd = new List<PlexContent>();
if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)) if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase))
{ {
// Process Shows // Process Shows
@ -188,6 +189,11 @@ namespace Ombi.Schedule.Jobs
} }
} }
} }
if (contentToAdd.Any())
{
await Repo.AddRange(contentToAdd);
}
} }
private List<Mediacontainer> GetAllContent(PlexSettings plexSettings) private List<Mediacontainer> GetAllContent(PlexSettings plexSettings)

View file

@ -7,6 +7,7 @@ namespace Ombi.Store.Repository
public interface IPlexContentRepository public interface IPlexContentRepository
{ {
Task<PlexContent> Add(PlexContent content); Task<PlexContent> Add(PlexContent content);
Task AddRange(IEnumerable<PlexContent> content);
Task<bool> ContentExists(string providerId); Task<bool> ContentExists(string providerId);
Task<IEnumerable<PlexContent>> GetAll(); Task<IEnumerable<PlexContent>> GetAll();
Task<PlexContent> Get(string providerId); Task<PlexContent> Get(string providerId);

View file

@ -48,6 +48,12 @@ namespace Ombi.Store.Repository
return await Db.PlexContent.ToListAsync(); return await Db.PlexContent.ToListAsync();
} }
public async Task AddRange(IEnumerable<PlexContent> content)
{
await Db.PlexContent.AddRangeAsync(content);
await Db.SaveChangesAsync();
}
public async Task<bool> ContentExists(string providerId) public async Task<bool> ContentExists(string providerId)
{ {
return await Db.PlexContent.AnyAsync(x => x.ProviderId == providerId); return await Db.PlexContent.AnyAsync(x => x.ProviderId == providerId);

View file

@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging;
using Ombi.Core; using Ombi.Core;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
namespace Ombi.Controllers namespace Ombi.Controllers
@ -65,6 +66,12 @@ namespace Ombi.Controllers
return await TvEngine.Search(searchTerm); return await TvEngine.Search(searchTerm);
} }
[HttpGet("tv/seasons/{tvdbId}")]
public async Task<IEnumerable<int>> GetSeasons(int tvdbId)
{
return await TvEngine.GetSeasons(tvdbId);
}
//[HttpGet("tv/popular")] //[HttpGet("tv/popular")]
//public async Task<IEnumerable<SearchTvShowViewModel>> PopularTv() //public async Task<IEnumerable<SearchTvShowViewModel>> PopularTv()
//{ //{

View file

@ -1,6 +1,5 @@
import { IEpisodeModel }from "./ISearchTvResult"; export interface IMediaBase {
imdbId: string,
export interface IMediaBase {
id: number, id: number,
providerId: number, providerId: number,
title: string, title: string,
@ -23,21 +22,27 @@ export interface IMediaBase {
} }
export interface IMovieRequestModel extends IMediaBase { export interface IMovieRequestModel extends IMediaBase {
imdbId: string,
} }
export interface ITvRequestModel extends IMediaBase { export interface ITvRequestModel extends IMediaBase {
imdbId: string, imdbId: string,
tvDbId: string, tvDbId: string,
requestAll: boolean, requestAll: boolean,
seasonNumbersRequested: number[], seasonRequests: ISeasonRequests[],
episodes: IEpisodeModel[],
childRequests: ITvRequestModel[], childRequests: ITvRequestModel[],
hasChildRequests: boolean, hasChildRequests: boolean,
rootFolderSelected: number, rootFolderSelected: number,
firstAired:string, firstAired:string,
} }
export interface ISeasonRequests
{
seasonNumber: number,
episodes:number[],
}
export enum RequestType { export enum RequestType {
movie = 1, movie = 1,
tvShow = 2 tvShow = 2

View file

@ -1,4 +1,6 @@
export interface ISearchTvResult { import { ISeasonRequests } from "./IRequestModel";
export interface ISearchTvResult {
id: number, id: number,
seriesName: string, seriesName: string,
aliases: string[], aliases: string[],
@ -19,17 +21,12 @@
siteRating: number, siteRating: number,
trailer: string, trailer: string,
homepage:string, homepage:string,
episodesRequested: IEpisodeModel[], seasonsRequested: ISeasonRequests[],
seasonNumbersRequested: number[],
requestAll:boolean, requestAll:boolean,
approved: boolean, approved: boolean,
requested: boolean, requested: boolean,
available: boolean, available: boolean,
plexUrl: string, plexUrl: string,
firstSeason: boolean,
} latestSeason:boolean,
export interface IEpisodeModel {
seasonNumber: number,
episodeNumber:number,
} }

View file

@ -1,8 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject'; import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged'; import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/debounceTime';
@ -19,18 +20,21 @@ import { IMovieRequestModel } from '../interfaces/IRequestModel';
moduleId: module.id, moduleId: module.id,
templateUrl: './movierequests.component.html' templateUrl: './movierequests.component.html'
}) })
export class MovieRequestsComponent implements OnInit { export class MovieRequestsComponent implements OnInit, OnDestroy {
constructor(private requestService: RequestService, private identityService: IdentityService) { constructor(private requestService: RequestService, private identityService: IdentityService) {
this.searchChanged this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event .debounceTime(600) // Wait Xms afterthe last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value .distinctUntilChanged() // only emit if value is different from previous value
.takeUntil(this.subscriptions)
.subscribe(x => { .subscribe(x => {
this.searchText = x as string; this.searchText = x as string;
if (this.searchText === "") { if (this.searchText === "") {
this.resetSearch(); this.resetSearch();
return; return;
} }
this.requestService.searchMovieRequests(this.searchText).subscribe(m => this.movieRequests = m); this.requestService.searchMovieRequests(this.searchText)
.takeUntil(this.subscriptions)
.subscribe(m => this.movieRequests = m);
}); });
} }
@ -39,10 +43,13 @@ export class MovieRequestsComponent implements OnInit {
searchChanged: Subject<string> = new Subject<string>(); searchChanged: Subject<string> = new Subject<string>();
searchText: string; searchText: string;
isAdmin : boolean; isAdmin: boolean;
private currentlyLoaded: number; private currentlyLoaded: number;
private amountToLoad : number; private amountToLoad: number;
private subscriptions = new Subject<void>();
ngOnInit() { ngOnInit() {
this.amountToLoad = 5; this.amountToLoad = 5;
@ -53,7 +60,9 @@ export class MovieRequestsComponent implements OnInit {
loadMore() { loadMore() {
this.requestService.getMovieRequests(this.amountToLoad, this.currentlyLoaded + 1).subscribe(x => { this.requestService.getMovieRequests(this.amountToLoad, this.currentlyLoaded + 1)
.takeUntil(this.subscriptions)
.subscribe(x => {
this.movieRequests.push.apply(this.movieRequests, x); this.movieRequests.push.apply(this.movieRequests, x);
this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad; this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad;
}); });
@ -87,11 +96,15 @@ export class MovieRequestsComponent implements OnInit {
} }
private updateRequest(request: IMovieRequestModel) { private updateRequest(request: IMovieRequestModel) {
this.requestService.updateMovieRequest(request).subscribe(x => request = x); this.requestService.updateMovieRequest(request)
.takeUntil(this.subscriptions)
.subscribe(x => request = x);
} }
private loadInit() { private loadInit() {
this.requestService.getMovieRequests(this.amountToLoad, 0).subscribe(x => this.movieRequests = x); this.requestService.getMovieRequests(this.amountToLoad, 0)
.takeUntil(this.subscriptions)
.subscribe(x => this.movieRequests = x);
this.isAdmin = this.identityService.hasRole("Admin"); this.isAdmin = this.identityService.hasRole("Admin");
} }
@ -106,4 +119,9 @@ export class MovieRequestsComponent implements OnInit {
this.movieRequests.splice(index, 1); this.movieRequests.splice(index, 1);
} }
} }
ngOnDestroy(): void {
this.subscriptions.next();
this.subscriptions.complete();
}
} }

View file

@ -84,6 +84,7 @@
<div *ngFor="let child of request.childRequests"> <div *ngFor="let child of request.childRequests">
<hr/> <hr/>
<div *ngIf="request.requestedUsers">Requested By: <span *ngFor="let user of request.requestedUsers">{{user}} </span></div> <div *ngIf="request.requestedUsers">Requested By: <span *ngFor="let user of request.requestedUsers">{{user}} </span></div>
<div>Seasons Requested: <span *ngFor="let s of request.seasonNumbersRequested">{{s}} </span> </div>
<div> <div>
<span>Request status: </span> <span>Request status: </span>
<span *ngIf="request.available" class="label label-success">Available</span> <span *ngIf="request.available" class="label label-success">Available</span>

View file

@ -1,8 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject'; import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged'; import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
import "rxjs/add/operator/takeUntil";
import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/debounceTime';
@ -19,30 +20,37 @@ import { ITvRequestModel } from '../interfaces/IRequestModel';
moduleId: module.id, moduleId: module.id,
templateUrl: './tvrequests.component.html' templateUrl: './tvrequests.component.html'
}) })
export class TvRequestsComponent implements OnInit { export class TvRequestsComponent implements OnInit, OnDestroy {
constructor(private requestService: RequestService, private identityService: IdentityService) { constructor(private requestService: RequestService, private identityService: IdentityService) {
this.searchChanged this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event .debounceTime(600) // Wait Xms afterthe last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value .distinctUntilChanged() // only emit if value is different from previous value
.takeUntil(this.subscriptions)
.subscribe(x => { .subscribe(x => {
this.searchText = x as string; this.searchText = x as string;
if (this.searchText === "") { if (this.searchText === "") {
this.resetSearch(); this.resetSearch();
return; return;
} }
this.requestService.searchTvRequests(this.searchText).subscribe(m => this.tvRequests = m); this.requestService.searchTvRequests(this.searchText)
.takeUntil(this.subscriptions)
.subscribe(m => this.tvRequests = m);
}); });
} }
private subscriptions = new Subject<void>();
tvRequests: ITvRequestModel[]; tvRequests: ITvRequestModel[];
searchChanged = new Subject<string>(); searchChanged = new Subject<string>();
searchText: string; searchText: string;
isAdmin : boolean; isAdmin: boolean;
private currentlyLoaded: number; private currentlyLoaded: number;
private amountToLoad : number; private amountToLoad: number;
ngOnInit() { ngOnInit() {
this.amountToLoad = 5; this.amountToLoad = 5;
@ -53,7 +61,9 @@ export class TvRequestsComponent implements OnInit {
loadMore() { loadMore() {
this.requestService.getTvRequests(this.amountToLoad, this.currentlyLoaded + 1).subscribe(x => { this.requestService.getTvRequests(this.amountToLoad, this.currentlyLoaded + 1)
.takeUntil(this.subscriptions)
.subscribe(x => {
this.tvRequests.push.apply(this.tvRequests, x); this.tvRequests.push.apply(this.tvRequests, x);
this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad; this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad;
}); });
@ -87,11 +97,15 @@ export class TvRequestsComponent implements OnInit {
} }
private updateRequest(request: ITvRequestModel) { private updateRequest(request: ITvRequestModel) {
this.requestService.updateTvRequest(request).subscribe(x => request = x); this.requestService.updateTvRequest(request)
.takeUntil(this.subscriptions)
.subscribe(x => request = x);
} }
private loadInit() { private loadInit() {
this.requestService.getTvRequests(this.amountToLoad, 0).subscribe(x => { this.requestService.getTvRequests(this.amountToLoad, 0)
.takeUntil(this.subscriptions)
.subscribe(x => {
this.tvRequests = x; this.tvRequests = x;
}); });
this.isAdmin = this.identityService.hasRole("Admin"); this.isAdmin = this.identityService.hasRole("Admin");
@ -108,4 +122,9 @@ export class TvRequestsComponent implements OnInit {
this.tvRequests.splice(index, 1); this.tvRequests.splice(index, 1);
} }
} }
ngOnDestroy(): void {
this.subscriptions.next();
this.subscriptions.complete();
}
} }

View file

@ -1,8 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject'; import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged'; import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
import "rxjs/add/operator/takeUntil";
import { SearchService } from '../services/search.service'; import { SearchService } from '../services/search.service';
import { RequestService } from '../services/request.service'; import { RequestService } from '../services/request.service';
@ -16,9 +17,10 @@ import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
moduleId: module.id, moduleId: module.id,
templateUrl: './moviesearch.component.html', templateUrl: './moviesearch.component.html',
}) })
export class MovieSearchComponent implements OnInit { export class MovieSearchComponent implements OnInit, OnDestroy {
searchText: string; searchText: string;
private subscriptions = new Subject<void>();
searchChanged: Subject<string> = new Subject<string>(); searchChanged: Subject<string> = new Subject<string>();
movieResults: ISearchMovieResult[]; movieResults: ISearchMovieResult[];
result: IRequestEngineResult; result: IRequestEngineResult;
@ -28,13 +30,16 @@ export class MovieSearchComponent implements OnInit {
this.searchChanged this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event .debounceTime(600) // Wait Xms afterthe last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value .distinctUntilChanged() // only emit if value is different from previous value
.takeUntil(this.subscriptions)
.subscribe(x => { .subscribe(x => {
this.searchText = x as string; this.searchText = x as string;
if (this.searchText === "") { if (this.searchText === "") {
this.clearResults(); this.clearResults();
return; return;
} }
this.searchService.searchMovie(this.searchText).subscribe(x => { this.searchService.searchMovie(this.searchText)
.takeUntil(this.subscriptions)
.subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.searchApplied = true; this.searchApplied = true;
// Now let's load some exta info including IMDBId // Now let's load some exta info including IMDBId
@ -59,7 +64,9 @@ export class MovieSearchComponent implements OnInit {
request(searchResult: ISearchMovieResult) { request(searchResult: ISearchMovieResult) {
searchResult.requested = true; searchResult.requested = true;
this.requestService.requestMovie(searchResult).subscribe(x => { this.requestService.requestMovie(searchResult)
.takeUntil(this.subscriptions)
.subscribe(x => {
this.result = x; this.result = x;
if (this.result.requestAdded) { if (this.result.requestAdded) {
@ -73,35 +80,45 @@ export class MovieSearchComponent implements OnInit {
popularMovies() { popularMovies() {
this.clearResults(); this.clearResults();
this.searchService.popularMovies().subscribe(x => { this.searchService.popularMovies()
.takeUntil(this.subscriptions)
.subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.getExtaInfo(); this.getExtaInfo();
}); });
} }
nowPlayingMovies() { nowPlayingMovies() {
this.clearResults(); this.clearResults();
this.searchService.nowPlayingMovies().subscribe(x => { this.searchService.nowPlayingMovies()
.takeUntil(this.subscriptions)
.subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.getExtaInfo(); this.getExtaInfo();
}); });
} }
topRatedMovies() { topRatedMovies() {
this.clearResults(); this.clearResults();
this.searchService.topRatedMovies().subscribe(x => { this.searchService.topRatedMovies()
.takeUntil(this.subscriptions)
.subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.getExtaInfo(); this.getExtaInfo();
}); });
} }
upcomingMovies() { upcomingMovies() {
this.clearResults(); this.clearResults();
this.searchService.upcomignMovies().subscribe(x => { this.searchService.upcomignMovies()
.takeUntil(this.subscriptions)
.subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.getExtaInfo(); this.getExtaInfo();
}); });
} }
private getExtaInfo() { private getExtaInfo() {
this.searchService.extraInfo(this.movieResults).subscribe(m => this.movieResults = m); this.searchService.extraInfo(this.movieResults)
.takeUntil(this.subscriptions)
.subscribe(m => this.movieResults = m);
} }
private clearResults() { private clearResults() {
@ -109,4 +126,9 @@ export class MovieSearchComponent implements OnInit {
this.searchApplied = false; this.searchApplied = false;
} }
ngOnDestroy(): void {
this.subscriptions.next();
this.subscriptions.complete();
}
} }

View file

@ -48,7 +48,7 @@
</a> </a>
<span *ngIf="result.status" class="label label-primary" style="font-size: 60%" target="_blank">{{result.status}}</span> <span *ngIf="result.status" class="label label-primary" target="_blank">{{result.status}}</span>
<span *ngIf="result.firstAired" class="label label-info" target="_blank">Air Date: {{result.firstAired}}</span> <span *ngIf="result.firstAired" class="label label-info" target="_blank">Air Date: {{result.firstAired}}</span>
@ -95,13 +95,13 @@
</div> </div>
</div> </div>
<div *ngIf="result.requested; then requestedBtn else notRequestedBtn"></div> <!--<div *ngIf="result.requested; then requestedBtn else notRequestedBtn"></div>
<template #requestedBtn> <template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button> <button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button>
</template> </template>
<template #notRequestedBtn> <template #notRequestedBtn>
<button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)"><i class="fa fa-plus"></i> Request</button> <button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)"><i class="fa fa-plus"></i> Request</button>
</template> </template>-->
<!--{{#if_eq type "tv"}} <!--{{#if_eq type "tv"}}
{{#if_eq tvFullyAvailable true}} {{#if_eq tvFullyAvailable true}}
@ -111,32 +111,26 @@
{{#if_eq enableTvRequestsForOnlySeries true}} {{#if_eq enableTvRequestsForOnlySeries true}}
<button id="{{id}}" style="text-align: right" class="btn {{#if available}}btn-success-outline{{else}}btn-primary-outline dropdownTv{{/if}} btn-primary-outline" season-select="0" type="button" {{#if available}} disabled{{/if}}><i class="fa fa-plus"></i> {{#if available}}@UI.Search_Available{{else}}@UI.Search_Request{{/if}}</button> <button id="{{id}}" style="text-align: right" class="btn {{#if available}}btn-success-outline{{else}}btn-primary-outline dropdownTv{{/if}} btn-primary-outline" season-select="0" type="button" {{#if available}} disabled{{/if}}><i class="fa fa-plus"></i> {{#if available}}@UI.Search_Available{{else}}@UI.Search_Request{{/if}}</button>
{{else}} {{else}}
-->
<div class="dropdown"> <div class="dropdown">
<button id="{{id}}" class="btn {{#if available}}btn-success-outline{{else}}btn-primary-outline{{/if}} dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> <button class="btn btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> {{#if available}}@UI.Search_Available{{else}}@UI.Search_Request {{/if}} <i class="fa fa-plus"></i> Request
<span class="caret"></span> <span class="caret"></span>
</button> </button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a id="{{id}}" season-select="0" class="dropdownTv " href="#">@UI.Search_AllSeasons</a></li> <li><a (click)="allSeasons(result)">All Seasons</a></li>
{{#if_eq disableTvRequestsBySeason false}} <li><a (click)="firstSeason(result)">First Season</a></li>
<li><a id="{{id}}" season-select="1" class="dropdownTv" href="#">@UI.Search_FirstSeason</a></li> <li><a (click)="latestSeason(result)">Latest Season</a></li>
<li><a id="{{id}}" season-select="2" class="dropdownTv" href="#">@UI.Search_LatestSeason</a></li> <li><a>Select Season...</a></li>
<li><a id="SeasonSelect" data-identifier="{{id}}" data-toggle="modal" data-target="#seasonsModal" href="#">@UI.Search_SelectSeason...</a></li> <li><a>Select Episode...</a></li>
{{/if_eq}}
{{#if_eq disableTvRequestsByEpisode false}}
<li><a id="EpisodeSelect" data-identifier="{{id}}" data-toggle="modal" data-target="#episodesModal" href="#">@UI.Search_SelectEpisode...</a></li>
{{/if_eq}}
</ul> </ul>
</div> </div>
{{/if_eq}}
{{#if available}} <!--
{{#if url}}
<br/> <br/>
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a> <a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>
{{/if}}
{{/if}} -->
{{/if_eq}}
{{/if_eq}}-->
<br/> <br/>

View file

@ -1,8 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject'; import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged'; import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
import "rxjs/add/operator/takeUntil";
import { SearchService } from '../services/search.service'; import { SearchService } from '../services/search.service';
import { RequestService } from '../services/request.service'; import { RequestService } from '../services/request.service';
@ -16,8 +17,9 @@ import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
moduleId: module.id, moduleId: module.id,
templateUrl: './tvsearch.component.html', templateUrl: './tvsearch.component.html',
}) })
export class TvSearchComponent implements OnInit { export class TvSearchComponent implements OnInit, OnDestroy {
private subscriptions = new Subject<void>();
searchText: string; searchText: string;
searchChanged = new Subject<string>(); searchChanged = new Subject<string>();
tvResults: ISearchTvResult[]; tvResults: ISearchTvResult[];
@ -28,13 +30,16 @@ export class TvSearchComponent implements OnInit {
this.searchChanged this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event .debounceTime(600) // Wait Xms afterthe last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value .distinctUntilChanged() // only emit if value is different from previous value
.takeUntil(this.subscriptions)
.subscribe(x => { .subscribe(x => {
this.searchText = x as string; this.searchText = x as string;
if (this.searchText === "") { if (this.searchText === "") {
this.clearResults(); this.clearResults();
return; return;
} }
this.searchService.searchTv(this.searchText).subscribe(x => { this.searchService.searchTv(this.searchText)
.takeUntil(this.subscriptions)
.subscribe(x => {
this.tvResults = x; this.tvResults = x;
this.searchApplied = true; this.searchApplied = true;
}); });
@ -57,35 +62,45 @@ export class TvSearchComponent implements OnInit {
popularShows() { popularShows() {
this.clearResults(); this.clearResults();
this.searchService.popularTv().subscribe(x => { this.searchService.popularTv()
.takeUntil(this.subscriptions)
.subscribe(x => {
this.tvResults = x; this.tvResults = x;
}); });
} }
trendingShows() { trendingShows() {
this.clearResults(); this.clearResults();
this.searchService.trendingTv().subscribe(x => { this.searchService.trendingTv()
.takeUntil(this.subscriptions)
.subscribe(x => {
this.tvResults = x; this.tvResults = x;
}); });
} }
mostWatchedShows() { mostWatchedShows() {
this.clearResults(); this.clearResults();
this.searchService.mostWatchedTv().subscribe(x => { this.searchService.mostWatchedTv()
.takeUntil(this.subscriptions)
.subscribe(x => {
this.tvResults = x; this.tvResults = x;
}); });
} }
anticipatedShows() { anticipatedShows() {
this.clearResults(); this.clearResults();
this.searchService.anticiplatedTv().subscribe(x => { this.searchService.anticiplatedTv()
.takeUntil(this.subscriptions)
.subscribe(x => {
this.tvResults = x; this.tvResults = x;
}); });
} }
request(searchResult: ISearchTvResult) { request(searchResult: ISearchTvResult) {
searchResult.requested = true; searchResult.requested = true;
this.requestService.requestTv(searchResult).subscribe(x => { this.requestService.requestTv(searchResult)
.takeUntil(this.subscriptions)
.subscribe(x => {
this.result = x; this.result = x;
if (this.result.requestAdded) { if (this.result.requestAdded) {
@ -98,9 +113,30 @@ export class TvSearchComponent implements OnInit {
} }
allSeasons(searchResult: ISearchTvResult) {
searchResult.requestAll = true;
this.request(searchResult);
}
firstSeason(searchResult: ISearchTvResult) {
searchResult.firstSeason = true;
this.request(searchResult);
}
latestSeason(searchResult: ISearchTvResult) {
searchResult.latestSeason = true;
this.request(searchResult);
}
private clearResults() { private clearResults() {
this.tvResults = []; this.tvResults = [];
this.searchApplied = false; this.searchApplied = false;
} }
ngOnDestroy(): void {
this.subscriptions.next();
this.subscriptions.complete();
}
} }

View file

@ -127,7 +127,7 @@
</div> </div>
</div> </div>
<div id="lightbox"> <div>
<div class="modal fade in " *ngIf="showCreateDialogue" style="display: block;"> <div class="modal fade in " *ngIf="showCreateDialogue" style="display: block;">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">