mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-16 02:02:55 -07:00
stuff around episode/season searching/requesting
This commit is contained in:
parent
07f5c77c3c
commit
b829b10b14
24 changed files with 357 additions and 191 deletions
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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))
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()
|
||||||
//{
|
//{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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/>
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue