mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-12 08:16:05 -07:00
This commit is contained in:
parent
385d206287
commit
3cc45b3022
30 changed files with 317 additions and 126 deletions
|
@ -5,10 +5,10 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.7.10" />
|
||||
<PackageReference Include="xunit" Version="2.2.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.0-beta4-build3742" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta4-build3742" />
|
||||
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.0-beta4-build3742" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -26,8 +26,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, true);
|
||||
Assert.True(result.Success);
|
||||
Assert.True(request.Approved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -37,8 +37,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, true);
|
||||
Assert.True(result.Success);
|
||||
Assert.True(request.Approved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -48,8 +48,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, true);
|
||||
Assert.True(result.Success);
|
||||
Assert.True(request.Approved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -59,8 +59,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, true);
|
||||
Assert.True(result.Success);
|
||||
Assert.True(request.Approved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -69,8 +69,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, false);
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -79,8 +79,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, false);
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
Approved = true
|
||||
};
|
||||
|
||||
MovieMock.Setup(x => x.GetRequest(123)).ReturnsAsync(list);
|
||||
MovieMock.Setup(x => x.GetRequest(123)).Returns(list);
|
||||
var search = new SearchMovieViewModel
|
||||
{
|
||||
Id = 123,
|
||||
|
@ -42,7 +42,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
var result = await Rule.Execute(search);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.Equal(search.Approved, true);
|
||||
Assert.False(search.Approved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -54,7 +54,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
Approved = true
|
||||
};
|
||||
|
||||
MovieMock.Setup(x => x.GetRequest(123)).ReturnsAsync(list);
|
||||
MovieMock.Setup(x => x.GetRequest(123)).Returns(list);
|
||||
var search = new SearchMovieViewModel
|
||||
{
|
||||
Id = 999,
|
||||
|
@ -63,7 +63,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
var result = await Rule.Execute(search);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.Equal(search.Approved, false);
|
||||
Assert.False(search.Approved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -82,7 +82,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
}
|
||||
};
|
||||
|
||||
TvMock.Setup(x => x.GetRequest(123)).ReturnsAsync(list);
|
||||
TvMock.Setup(x => x.GetRequest(123)).Returns(list);
|
||||
var search = new SearchTvShowViewModel
|
||||
{
|
||||
Id = 123,
|
||||
|
@ -91,7 +91,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
var result = await Rule.Execute(search);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.Equal(search.Approved, true);
|
||||
Assert.True(search.Approved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -111,7 +111,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
};
|
||||
|
||||
|
||||
TvMock.Setup(x => x.GetRequest(123)).ReturnsAsync(list);
|
||||
TvMock.Setup(x => x.GetRequest(123)).Returns(list);
|
||||
var search = new SearchTvShowViewModel()
|
||||
{
|
||||
Id = 999,
|
||||
|
@ -120,7 +120,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
var result = await Rule.Execute(search);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.Equal(search.Approved, false);
|
||||
Assert.False(search.Approved);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -148,10 +148,18 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
var showInfo = await MovieApi.GetMovieInformation(viewMovie.Id);
|
||||
viewMovie.Id = showInfo.Id; // TheMovieDbId
|
||||
viewMovie.ImdbId = showInfo.ImdbId;
|
||||
}
|
||||
|
||||
// So when we run the rule to check if it's available in Plex we need the ImdbId
|
||||
// But we only pass down the SearchViewModel that doesn't contain this
|
||||
// So set the ImdbId to viewMovie.Id and then set it back afterwards
|
||||
var oldId = viewMovie.Id;
|
||||
viewMovie.CustomId = viewMovie.ImdbId ?? string.Empty;
|
||||
|
||||
await RunSearchRules(viewMovie);
|
||||
|
||||
viewMovie.Id = oldId;
|
||||
return viewMovie;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace Ombi.Core.Models.Search
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Ombi.Core.Models.Search
|
||||
{
|
||||
public class SearchViewModel
|
||||
{
|
||||
|
@ -7,5 +9,16 @@
|
|||
public bool Requested { get; set; }
|
||||
public bool Available { get; set; }
|
||||
public string PlexUrl { get; set; }
|
||||
public string Quality { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This is used for the PlexAvailabilityCheck rule
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The custom identifier.
|
||||
/// </value>
|
||||
[NotMapped]
|
||||
public string CustomId { get; set; }
|
||||
}
|
||||
}
|
|
@ -19,9 +19,9 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
private IMovieRequestRepository Movie { get; }
|
||||
private ITvRequestRepository Tv { get; }
|
||||
|
||||
public async Task<RuleResult> Execute(SearchViewModel obj)
|
||||
public Task<RuleResult> Execute(SearchViewModel obj)
|
||||
{
|
||||
var movieRequests = await Movie.GetRequest(obj.Id);
|
||||
var movieRequests = Movie.GetRequest(obj.Id);
|
||||
if (movieRequests != null) // Do we already have a request for this?
|
||||
{
|
||||
|
||||
|
@ -29,10 +29,10 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
obj.Approved = movieRequests.Approved;
|
||||
obj.Available = movieRequests.Available;
|
||||
|
||||
return Success();
|
||||
return Task.FromResult(Success());
|
||||
}
|
||||
|
||||
var tvRequests = await Tv.GetRequest(obj.Id);
|
||||
var tvRequests = Tv.GetRequest(obj.Id);
|
||||
if (tvRequests != null) // Do we already have a request for this?
|
||||
{
|
||||
|
||||
|
@ -40,9 +40,9 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
obj.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
|
||||
obj.Available = tvRequests.ChildRequests.Any(x => x.Available);
|
||||
|
||||
return Success();
|
||||
return Task.FromResult(Success());
|
||||
}
|
||||
return Success();
|
||||
return Task.FromResult(Success());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,11 +16,12 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
|
||||
public async Task<RuleResult> Execute(SearchViewModel obj)
|
||||
{
|
||||
var item = await PlexContentRepository.Get(obj.Id.ToString());
|
||||
var item = await PlexContentRepository.Get(obj.CustomId);
|
||||
if (item != null)
|
||||
{
|
||||
obj.Available = true;
|
||||
obj.PlexUrl = item.Url;
|
||||
obj.Quality = item.Quality;
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Store.Context;
|
||||
|
@ -15,16 +16,16 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
|
||||
private readonly IOmbiContext _ctx;
|
||||
|
||||
public Task<RuleResult> Execute(SearchViewModel obj)
|
||||
public async Task<RuleResult> Execute(SearchViewModel obj)
|
||||
{
|
||||
// Check if it's in Radarr
|
||||
var result = _ctx.RadarrCache.FirstOrDefault(x => x.TheMovieDbId == obj.Id);
|
||||
var result = await _ctx.RadarrCache.FirstOrDefaultAsync(x => x.TheMovieDbId == obj.Id);
|
||||
if (result != null)
|
||||
{
|
||||
obj.Approved = true; // It's in radarr so it's approved... Maybe have a new property called "Processing" or something?
|
||||
}
|
||||
|
||||
return Task.FromResult(Success());
|
||||
return Success();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using Ombi.Api.Discord;
|
||||
|
@ -89,18 +90,18 @@ namespace Ombi.DependencyInjection
|
|||
{
|
||||
services.AddEntityFrameworkSqlite().AddDbContext<OmbiContext>();
|
||||
|
||||
services.AddScoped<IOmbiContext, OmbiContext>();
|
||||
services.AddScoped<ISettingsRepository, SettingsJsonRepository>();
|
||||
services.AddScoped<ISettingsResolver, SettingsResolver>();
|
||||
services.AddScoped<IPlexContentRepository, PlexContentRepository>();
|
||||
services.AddScoped<INotificationTemplatesRepository, NotificationTemplatesRepository>();
|
||||
services.AddScoped<IOmbiContext, OmbiContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
||||
services.AddTransient<ISettingsRepository, SettingsJsonRepository>();
|
||||
services.AddTransient<ISettingsResolver, SettingsResolver>();
|
||||
services.AddTransient<IPlexContentRepository, PlexContentRepository>();
|
||||
services.AddTransient<INotificationTemplatesRepository, NotificationTemplatesRepository>();
|
||||
|
||||
services.AddScoped<ITvRequestRepository, TvRequestRepository>();
|
||||
services.AddScoped<IMovieRequestRepository, MovieRequestRepository>();
|
||||
services.AddScoped<IAuditRepository, AuditRepository>();
|
||||
services.AddScoped<IApplicationConfigRepository, ApplicationConfigRepository>();
|
||||
services.AddScoped<ITokenRepository, TokenRepository>();
|
||||
services.AddScoped(typeof(ISettingsService<>), typeof(SettingsService<>));
|
||||
services.AddTransient<ITvRequestRepository, TvRequestRepository>();
|
||||
services.AddTransient<IMovieRequestRepository, MovieRequestRepository>();
|
||||
services.AddTransient<IAuditRepository, AuditRepository>();
|
||||
services.AddTransient<IApplicationConfigRepository, ApplicationConfigRepository>();
|
||||
services.AddTransient<ITokenRepository, TokenRepository>();
|
||||
services.AddTransient(typeof(ISettingsService<>), typeof(SettingsService<>));
|
||||
}
|
||||
public static void RegisterServices(this IServiceCollection services)
|
||||
{
|
||||
|
|
21
src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj
Normal file
21
src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj
Normal file
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
|
||||
<PackageReference Include="Moq" Version="4.7.99" />
|
||||
<PackageReference Include="Nunit" Version="3.7.1" />
|
||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.7.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.8.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.0.0"></packagereference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Schedule\Ombi.Schedule.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
110
src/Ombi.Schedule.Tests/PlexAvailabilityCheckerTests.cs
Normal file
110
src/Ombi.Schedule.Tests/PlexAvailabilityCheckerTests.cs
Normal file
|
@ -0,0 +1,110 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Castle.Components.DictionaryAdapter;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Schedule.Jobs.Plex;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Schedule.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class PlexAvailabilityCheckerTests
|
||||
{
|
||||
public PlexAvailabilityCheckerTests()
|
||||
{
|
||||
_repo = new Mock<IPlexContentRepository>();
|
||||
_tv = new Mock<ITvRequestRepository>();
|
||||
_movie = new Mock<IMovieRequestRepository>();
|
||||
Checker = new PlexAvailabilityChecker(_repo.Object, _tv.Object, _movie.Object);
|
||||
}
|
||||
|
||||
private readonly Mock<IPlexContentRepository> _repo;
|
||||
private readonly Mock<ITvRequestRepository> _tv;
|
||||
private readonly Mock<IMovieRequestRepository> _movie;
|
||||
private PlexAvailabilityChecker Checker { get; }
|
||||
|
||||
[Test]
|
||||
public async Task ProcessMovies_ShouldMarkAvailable_WhenInPlex()
|
||||
{
|
||||
var request = new MovieRequests
|
||||
{
|
||||
ImdbId = "test"
|
||||
};
|
||||
_movie.Setup(x => x.Get()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
||||
_repo.Setup(x => x.Get("test")).ReturnsAsync(new PlexContent());
|
||||
|
||||
await Checker.Start();
|
||||
|
||||
_movie.Verify(x => x.Save(), Times.Once);
|
||||
|
||||
Assert.True(request.Available);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ProcessMovies_ShouldNotBeAvailable_WhenInNotPlex()
|
||||
{
|
||||
var request = new MovieRequests
|
||||
{
|
||||
ImdbId = "test"
|
||||
};
|
||||
_movie.Setup(x => x.Get()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
||||
|
||||
await Checker.Start();
|
||||
|
||||
_movie.Verify(x => x.Save(), Times.Once);
|
||||
Assert.False(request.Available);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("EF IAsyncQueryProvider")]
|
||||
public async Task ProcessTv_ShouldMark_Episode_Available_WhenInPlex()
|
||||
{
|
||||
var request = new ChildRequests
|
||||
{
|
||||
ParentRequest = new TvRequests {TvDbId = 1},
|
||||
SeasonRequests = new EditableList<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new EditableList<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
EpisodeNumber = 1,
|
||||
Season = new SeasonRequests
|
||||
{
|
||||
SeasonNumber = 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
_tv.Setup(x => x.GetChild()).Returns(new List<ChildRequests> { request }.AsQueryable());
|
||||
_repo.Setup(x => x.GetAllEpisodes()).Returns(new List<PlexEpisode>
|
||||
{
|
||||
new PlexEpisode
|
||||
{
|
||||
Series = new PlexContent
|
||||
{
|
||||
ProviderId = 1.ToString(),
|
||||
},
|
||||
EpisodeNumber = 1,
|
||||
SeasonNumber = 2
|
||||
}
|
||||
}.AsQueryable);
|
||||
|
||||
await Checker.Start();
|
||||
|
||||
_tv.Verify(x => x.Save(), Times.Once);
|
||||
|
||||
Assert.True(request.SeasonRequests[0].Episodes[0].Available);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
27
src/Ombi.Schedule.Tests/Properties/launchSettings.json
Normal file
27
src/Ombi.Schedule.Tests/Properties/launchSettings.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:62604/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Ombi.Schedule.Tests": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "http://localhost:62605/"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
|
||||
private async Task ProcessTv()
|
||||
{
|
||||
var tv = _tvRepo.GetChild();
|
||||
var tv = _tvRepo.GetChild().Where(x => !x.Available);
|
||||
var plexEpisodes = _repo.GetAllEpisodes().Include(x => x.Series);
|
||||
|
||||
foreach (var child in tv)
|
||||
|
|
|
@ -187,7 +187,8 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
Type = PlexMediaTypeEntity.Movie,
|
||||
Title = movie.title,
|
||||
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey),
|
||||
Seasons = new List<PlexSeasonsContent>()
|
||||
Seasons = new List<PlexSeasonsContent>(),
|
||||
Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty
|
||||
};
|
||||
|
||||
contentToAdd.Add(item);
|
||||
|
|
|
@ -102,24 +102,24 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
var currentPosition = 0;
|
||||
var ResultCount = 50;
|
||||
var episodes = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition, ResultCount);
|
||||
|
||||
var currentData = _repo.GetAllEpisodes();
|
||||
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Total Epsiodes found for {episodes.MediaContainer.librarySectionTitle} = {episodes.MediaContainer.totalSize}");
|
||||
|
||||
await ProcessEpsiodes(episodes);
|
||||
await ProcessEpsiodes(episodes, currentData);
|
||||
currentPosition += ResultCount;
|
||||
|
||||
while (currentPosition < episodes.MediaContainer.totalSize)
|
||||
{
|
||||
var ep = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition,
|
||||
ResultCount);
|
||||
await ProcessEpsiodes(ep);
|
||||
await ProcessEpsiodes(ep, currentData);
|
||||
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Processed {ResultCount} more episodes. Total Remaining {currentPosition - episodes.MediaContainer.totalSize}");
|
||||
currentPosition += ResultCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async Task ProcessEpsiodes(PlexContainer episodes)
|
||||
private async Task ProcessEpsiodes(PlexContainer episodes, IQueryable<PlexEpisode> currentEpisodes)
|
||||
{
|
||||
var ep = new HashSet<PlexEpisode>();
|
||||
foreach (var episode in episodes.MediaContainer.Metadata)
|
||||
|
@ -128,6 +128,13 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
// We have the parent and grandparent rating keys to link up to the season and series
|
||||
//var metadata = _api.GetEpisodeMetaData(server.PlexAuthToken, server.FullUri, episode.ratingKey);
|
||||
|
||||
var epExists = currentEpisodes.Any(x => episode.ratingKey == x.Key &&
|
||||
episode.grandparentRatingKey == x.GrandparentKey);
|
||||
if (epExists)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ep.Add(new PlexEpisode
|
||||
{
|
||||
EpisodeNumber = episode.index,
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace Ombi.Store.Entities
|
|||
/// </summary>
|
||||
public int Key { get; set; }
|
||||
public DateTime AddedAt { get; set; }
|
||||
public string Quality { get; set; }
|
||||
}
|
||||
|
||||
[Table("PlexSeasonsContent")]
|
||||
|
|
|
@ -10,7 +10,7 @@ using Ombi.Helpers;
|
|||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
[DbContext(typeof(OmbiContext))]
|
||||
[Migration("20170824133349_Inital")]
|
||||
[Migration("20170825114646_Inital")]
|
||||
partial class Inital
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
|
@ -258,6 +258,8 @@ namespace Ombi.Store.Migrations
|
|||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<string>("Quality");
|
||||
|
||||
b.Property<string>("ReleaseYear");
|
||||
|
||||
b.Property<string>("Title");
|
|
@ -134,6 +134,7 @@ namespace Ombi.Store.Migrations
|
|||
AddedAt = table.Column<DateTime>(nullable: false),
|
||||
Key = table.Column<int>(nullable: false),
|
||||
ProviderId = table.Column<string>(nullable: true),
|
||||
Quality = table.Column<string>(nullable: true),
|
||||
ReleaseYear = table.Column<string>(nullable: true),
|
||||
Title = table.Column<string>(nullable: true),
|
||||
Type = table.Column<int>(nullable: false),
|
|
@ -257,6 +257,8 @@ namespace Ombi.Store.Migrations
|
|||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<string>("Quality");
|
||||
|
||||
b.Property<string>("ReleaseYear");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
|
|
@ -9,7 +9,8 @@ namespace Ombi.Store.Repository
|
|||
Task<MovieRequests> Add(MovieRequests request);
|
||||
Task Delete(MovieRequests request);
|
||||
IQueryable<MovieRequests> Get();
|
||||
Task<MovieRequests> GetRequest(int theMovieDbId);
|
||||
Task<MovieRequests> GetRequestAsync(int theMovieDbId);
|
||||
MovieRequests GetRequest(int theMovieDbId);
|
||||
Task Update(MovieRequests request);
|
||||
Task Save();
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ namespace Ombi.Store.Repository.Requests
|
|||
Task Delete(TvRequests request);
|
||||
Task DeleteChild(ChildRequests request);
|
||||
IQueryable<TvRequests> Get();
|
||||
Task<TvRequests> GetRequest(int tvDbId);
|
||||
Task<TvRequests> GetRequestAsync(int tvDbId);
|
||||
TvRequests GetRequest(int tvDbId);
|
||||
Task Update(TvRequests request);
|
||||
Task UpdateChild(ChildRequests request);
|
||||
IQueryable<ChildRequests> GetChild();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -16,11 +17,27 @@ namespace Ombi.Store.Repository.Requests
|
|||
|
||||
private IOmbiContext Db { get; }
|
||||
|
||||
public async Task<MovieRequests> GetRequest(int theMovieDbId)
|
||||
public async Task<MovieRequests> GetRequestAsync(int theMovieDbId)
|
||||
{
|
||||
return await Db.MovieRequests.Where(x => x.TheMovieDbId == theMovieDbId)
|
||||
try
|
||||
{
|
||||
return await Db.MovieRequests.Where(x => x.TheMovieDbId == theMovieDbId)
|
||||
.Include(x => x.RequestedUser)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public MovieRequests GetRequest(int theMovieDbId)
|
||||
{
|
||||
return Db.MovieRequests.Where(x => x.TheMovieDbId == theMovieDbId)
|
||||
.Include(x => x.RequestedUser)
|
||||
.FirstOrDefaultAsync();
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public IQueryable<MovieRequests> Get()
|
||||
|
|
|
@ -15,17 +15,28 @@ namespace Ombi.Store.Repository.Requests
|
|||
|
||||
private IOmbiContext Db { get; }
|
||||
|
||||
public async Task<TvRequests> GetRequest(int tvDbId)
|
||||
public async Task<TvRequests> GetRequestAsync(int tvDbId)
|
||||
{
|
||||
return await Db.TvRequests.Where(x => x.TvDbId == tvDbId)
|
||||
.Include(x => x.ChildRequests)
|
||||
.ThenInclude(x => x.RequestedUser)
|
||||
.ThenInclude(x => x.RequestedUser)
|
||||
.Include(x => x.ChildRequests)
|
||||
.ThenInclude(x => x.SeasonRequests)
|
||||
.ThenInclude(x => x.Episodes)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public TvRequests GetRequest(int tvDbId)
|
||||
{
|
||||
return Db.TvRequests.Where(x => x.TvDbId == tvDbId)
|
||||
.Include(x => x.ChildRequests)
|
||||
.ThenInclude(x => x.RequestedUser)
|
||||
.Include(x => x.ChildRequests)
|
||||
.ThenInclude(x => x.SeasonRequests)
|
||||
.ThenInclude(x => x.Episodes)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public IQueryable<TvRequests> Get()
|
||||
{
|
||||
return Db.TvRequests
|
||||
|
@ -40,6 +51,7 @@ namespace Ombi.Store.Repository.Requests
|
|||
{
|
||||
return Db.ChildRequests
|
||||
.Include(x => x.RequestedUser)
|
||||
.Include(x => x.ParentRequest)
|
||||
.Include(x => x.SeasonRequests)
|
||||
.ThenInclude(x => x.Episodes)
|
||||
.AsQueryable();
|
||||
|
|
13
src/Ombi.sln
13
src/Ombi.sln
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26730.8
|
||||
VisualStudioVersion = 15.0.26730.3
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi", "Ombi\Ombi.csproj", "{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}"
|
||||
EndProject
|
||||
|
@ -76,9 +76,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Pushbullet", "Ombi
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Slack", "Ombi.Api.Slack\Ombi.Api.Slack.csproj", "{71708256-9152-4E81-9FCA-E3181A185806}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Mattermost", "Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj", "{737B2620-FE5A-4135-A017-79C269A7D36C}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Mattermost", "Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj", "{737B2620-FE5A-4135-A017-79C269A7D36C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Pushover", "Ombi.Api.Pushover\Ombi.Api.Pushover.csproj", "{CA55DD4F-4EFF-4906-A848-35FCC7BD5654}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Pushover", "Ombi.Api.Pushover\Ombi.Api.Pushover.csproj", "{CA55DD4F-4EFF-4906-A848-35FCC7BD5654}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Schedule.Tests", "Ombi.Schedule.Tests\Ombi.Schedule.Tests.csproj", "{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -198,6 +200,10 @@ Global
|
|||
{CA55DD4F-4EFF-4906-A848-35FCC7BD5654}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CA55DD4F-4EFF-4906-A848-35FCC7BD5654}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CA55DD4F-4EFF-4906-A848-35FCC7BD5654}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -225,6 +231,7 @@ Global
|
|||
{71708256-9152-4E81-9FCA-E3181A185806} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||
{737B2620-FE5A-4135-A017-79C269A7D36C} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||
{CA55DD4F-4EFF-4906-A848-35FCC7BD5654} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||
{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C} = {6F42AB98-9196-44C4-B888-D5E409F415A1}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869}
|
||||
|
|
|
@ -20,5 +20,6 @@
|
|||
approved: boolean,
|
||||
requested: boolean,
|
||||
available: boolean,
|
||||
plexUrl: string
|
||||
plexUrl: string,
|
||||
quality:string
|
||||
}
|
|
@ -43,15 +43,7 @@
|
|||
<span class="label label-success">{{node.data.status}}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Request status: </span>
|
||||
<span *ngIf="node.data.available" class="label label-success">Available</span>
|
||||
<span *ngIf="node.data.approved && !node.data.available" class="label label-info">Processing Request</span>
|
||||
<span *ngIf="node.data.denied" class="label label-danger">Request Denied</span>
|
||||
<span *ngIf="node.data.deniedReason" title="{{node.data.deniedReason}}"><i class="fa fa-info-circle"></i></span>
|
||||
<span *ngIf="!node.data.approved && !node.data.availble && !node.data.denied" class="label label-warning">Pending Approval</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div>Release Date: {{node.data.releaseDate | date}}</div>
|
||||
<br />
|
||||
</div>
|
||||
|
|
|
@ -214,6 +214,7 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
|
|||
this.requestService.getTvRequests(this.amountToLoad, 0)
|
||||
.takeUntil(this.subscriptions)
|
||||
.subscribe(x => {
|
||||
debugger;
|
||||
this.tvRequests = this.transformData(x);
|
||||
});
|
||||
this.isAdmin = this.identityService.hasRole("Admin");
|
||||
|
|
|
@ -46,7 +46,11 @@
|
|||
|
||||
<span *ngIf="result.releaseDate" class="label label-info" target="_blank">Release Date: {{result.releaseDate | date: 'dd/MM/yyyy'}}</span>
|
||||
|
||||
<a *ngIf="result.homepage" href="{{result.homepage}}" target="_blank"><span class="label label-info">HomePage</span></a>
|
||||
|
||||
<a *ngIf="result.trailer" href="{{result.trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
|
||||
<span *ngIf="result.available" class="label label-success">Available</span>
|
||||
<span *ngIf="result.quality" class="label label-success">{{result.quality}}p</span>
|
||||
<span *ngIf="result.approved && !result.available" class="label label-info">Processing Request</span>
|
||||
<div *ngIf="result.requested && !result.available; then requested else notRequested"></div>
|
||||
<ng-template #requested>
|
||||
|
@ -58,11 +62,7 @@
|
|||
</ng-template>
|
||||
|
||||
|
||||
<span id="{{id}}netflixTab"></span>
|
||||
|
||||
<a *ngIf="result.homepage" href="{{result.homepage}}" target="_blank"><span class="label label-info">HomePage</span></a>
|
||||
|
||||
<a *ngIf="result.trailer" href="{{result.trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
|
||||
|
||||
|
||||
<br/>
|
||||
|
@ -132,11 +132,12 @@
|
|||
|
||||
<br/>
|
||||
<div *ngIf="result.available">
|
||||
<input name="providerId" type="text" value="{{id}}" hidden="hidden"/>
|
||||
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}" target="_blank"><i class="fa fa-eye"></i> View On Plex</a>
|
||||
<!--<input name="providerId" type="text" value="{{id}}" hidden="hidden"/>
|
||||
<input name="type" type="text" value="{{type}}" hidden="hidden"/>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<i class="fa fa-exclamation"></i> @UI.Search_ReportIssue
|
||||
<i class="fa fa-exclamation"></i> Report Issue
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
|
@ -146,7 +147,7 @@
|
|||
<li><a issue-select="3" class="dropdownIssue" href="#">Playback</a></li>
|
||||
<li><a issue-select="4" class="dropdownIssue" href="#" data-toggle="modal" data-target="#issuesModal">Other</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -9,21 +9,10 @@
|
|||
<li role="presentation" class="active">
|
||||
<a id="movieTabButton" href="#MoviesTab" aria-controls="home" role="tab" data-toggle="tab" (click)="selectTab()"><i class="fa fa-film"></i> Movies</a>
|
||||
</li>
|
||||
|
||||
<!--<li role="presentation">
|
||||
<a id="actorTabButton" href="#ActorsTab" aria-controls="profile" role="tab" data-toggle="tab"><i class="fa fa-users"></i> Actors</a>
|
||||
|
||||
</li>-->
|
||||
|
||||
|
||||
<li role="presentation">
|
||||
<a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTab()"><i class="fa fa-television"></i> TV Shows</a>
|
||||
|
||||
</li>
|
||||
<!--
|
||||
<li role="presentation">
|
||||
<a href="#MusicTab" aria-controls="profile" role="tab" data-toggle="tab"><i class="fa fa-music"></i> Albums</a>
|
||||
</li>-->
|
||||
|
||||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
|
@ -33,28 +22,8 @@
|
|||
<movie-search></movie-search>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div role="tabpanel" class="tab-pane" id="ActorsTab">
|
||||
<div class="input-group">
|
||||
<input id="actorSearchContent" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons">
|
||||
<div class="input-group-addon">
|
||||
<i id="actorSearchButton" class="fa fa-search"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="actorsSearchNew" name="actorsSearchNew"><label for="actorsSearchNew">@UI.Search_NewOnly</label>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<div id="actorMovieList">
|
||||
</div>
|
||||
</div>-->
|
||||
|
||||
|
||||
<div [hidden]="!showTv">
|
||||
<tv-search></tv-search>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
<div>
|
||||
|
||||
<a href="http://www.imdb.com/title/{{result.imdbId}}/" target="_blank">
|
||||
<h4>{{result.title}} ({{result.firstAired}})</h4>
|
||||
<h4>{{result.title}} ({{result.firstAired | date: 'yyyy'}})</h4>
|
||||
|
||||
</a>
|
||||
|
||||
|
@ -85,16 +85,7 @@
|
|||
<div class="col-sm-2">
|
||||
<input name="{{type}}Id" type="text" value="{{result.id}}" hidden="hidden"/>
|
||||
|
||||
<div *ngIf="result.available">
|
||||
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> Available</button>
|
||||
|
||||
<div *ngIf="result.url">
|
||||
<br/>
|
||||
<br/>
|
||||
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{result.url}}" target="_blank"><i class="fa fa-eye"></i> View In Plex</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--<div *ngIf="result.requested; then requestedBtn else notRequestedBtn"></div>
|
||||
<template #requestedBtn>
|
||||
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button>
|
||||
|
@ -134,11 +125,13 @@
|
|||
|
||||
<br/>
|
||||
<div *ngIf="result.available">
|
||||
<input name="providerId" type="text" value="{{id}}" hidden="hidden"/>
|
||||
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}" target="_blank"><i class="fa fa-eye"></i> View On Plex</a>
|
||||
|
||||
<!--<input name="providerId" type="text" value="{{id}}" hidden="hidden"/>
|
||||
<input name="type" type="text" value="{{type}}" hidden="hidden"/>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<i class="fa fa-exclamation"></i> @UI.Search_ReportIssue
|
||||
<i class="fa fa-exclamation"></i> Report Issue
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||
|
@ -148,7 +141,7 @@
|
|||
<li><a issue-select="3" class="dropdownIssue" href="#">Playback</a></li>
|
||||
<li><a issue-select="4" class="dropdownIssue" href="#" data-toggle="modal" data-target="#issuesModal">Other</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue