mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-19 21:03:17 -07:00
Merge
This commit is contained in:
commit
f16b33c437
367 changed files with 12069 additions and 3073 deletions
36
src/Ombi.Api.Gotify/GotifyApi.cs
Normal file
36
src/Ombi.Api.Gotify/GotifyApi.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Api.Gotify
|
||||
{
|
||||
public class GotifyApi : IGotifyApi
|
||||
{
|
||||
public GotifyApi(IApi api)
|
||||
{
|
||||
_api = api;
|
||||
}
|
||||
|
||||
private readonly IApi _api;
|
||||
|
||||
public async Task PushAsync(string baseUrl, string accessToken, string subject, string body, sbyte priority)
|
||||
{
|
||||
var request = new Request("/message", baseUrl, HttpMethod.Post);
|
||||
request.AddQueryString("token", accessToken);
|
||||
|
||||
request.AddHeader("Access-Token", accessToken);
|
||||
request.ApplicationJsonContentType();
|
||||
|
||||
|
||||
var jsonBody = new
|
||||
{
|
||||
message = body,
|
||||
title = subject,
|
||||
priority = priority
|
||||
};
|
||||
|
||||
request.AddJsonBody(jsonBody);
|
||||
|
||||
await _api.Request(request);
|
||||
}
|
||||
}
|
||||
}
|
9
src/Ombi.Api.Gotify/IGotifyApi.cs
Normal file
9
src/Ombi.Api.Gotify/IGotifyApi.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Api.Gotify
|
||||
{
|
||||
public interface IGotifyApi
|
||||
{
|
||||
Task PushAsync(string endpoint, string accessToken, string subject, string body, sbyte priority);
|
||||
}
|
||||
}
|
15
src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj
Normal file
15
src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj
Normal file
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<AssemblyVersion>3.0.0.0</AssemblyVersion>
|
||||
<FileVersion>3.0.0.0</FileVersion>
|
||||
<Version></Version>
|
||||
<PackageVersion></PackageVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -12,5 +12,6 @@ namespace Ombi.Api.Trakt
|
|||
Task<IEnumerable<TraktMostWatchedShow>> GetMostWatchesShows(TraktTimePeriod period = null, int? page = default(int?), int? limitPerPage = default(int?));
|
||||
Task<IEnumerable<TraktShow>> GetPopularShows(int? page = default(int?), int? limitPerPage = default(int?));
|
||||
Task<IEnumerable<TraktTrendingShow>> GetTrendingShows(int? page = default(int?), int? limitPerPage = default(int?));
|
||||
Task<TraktShow> GetTvExtendedInfo(string imdbId);
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ namespace Ombi.Api.Trakt
|
|||
|
||||
public async Task<IEnumerable<TraktShow>> GetPopularShows(int? page = null, int? limitPerPage = null)
|
||||
{
|
||||
var popular = await Client.Shows.GetPopularShowsAsync(new TraktExtendedInfo { Full = true, Images = true}, null, page ?? 1, limitPerPage ?? 10);
|
||||
var popular = await Client.Shows.GetPopularShowsAsync(new TraktExtendedInfo { Full = true, Images = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||
return popular.Value;
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,11 @@ namespace Ombi.Api.Trakt
|
|||
var anticipatedShows = await Client.Shows.GetMostWatchedShowsAsync(period ?? TraktTimePeriod.Monthly, new TraktExtendedInfo { Full = true, Images = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||
return anticipatedShows.Value;
|
||||
}
|
||||
|
||||
public async Task<TraktShow> GetTvExtendedInfo(string imdbId)
|
||||
{
|
||||
return await Client.Shows.GetShowAsync(imdbId, new TraktExtendedInfo { Full = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Api.TvMaze.Models;
|
||||
using Ombi.Api.TvMaze.Models.V2;
|
||||
|
||||
namespace Ombi.Api.TvMaze
|
||||
{
|
||||
|
@ -11,5 +12,6 @@ namespace Ombi.Api.TvMaze
|
|||
Task<List<TvMazeSearch>> Search(string searchTerm);
|
||||
Task<TvMazeShow> ShowLookup(int showId);
|
||||
Task<TvMazeShow> ShowLookupByTheTvDbId(int theTvDbId);
|
||||
Task<FullSearch> GetTvFullInformation(int id);
|
||||
}
|
||||
}
|
144
src/Ombi.Api.TvMaze/Models/V2/FullSearch.cs
Normal file
144
src/Ombi.Api.TvMaze/Models/V2/FullSearch.cs
Normal file
|
@ -0,0 +1,144 @@
|
|||
using System;
|
||||
|
||||
namespace Ombi.Api.TvMaze.Models.V2
|
||||
{
|
||||
public class FullSearch
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string url { get; set; }
|
||||
public string name { get; set; }
|
||||
public string type { get; set; }
|
||||
public string language { get; set; }
|
||||
public string[] genres { get; set; }
|
||||
public string status { get; set; }
|
||||
public int runtime { get; set; }
|
||||
public string premiered { get; set; }
|
||||
public string officialSite { get; set; }
|
||||
public Schedule schedule { get; set; }
|
||||
public Rating rating { get; set; }
|
||||
public int weight { get; set; }
|
||||
public Network network { get; set; }
|
||||
public object webChannel { get; set; }
|
||||
public Externals externals { get; set; }
|
||||
public Image image { get; set; }
|
||||
public string summary { get; set; }
|
||||
public int updated { get; set; }
|
||||
public _Links _links { get; set; }
|
||||
public _Embedded _embedded { get; set; }
|
||||
}
|
||||
|
||||
public class Schedule
|
||||
{
|
||||
public string time { get; set; }
|
||||
public string[] days { get; set; }
|
||||
}
|
||||
|
||||
public class Rating
|
||||
{
|
||||
public float average { get; set; }
|
||||
}
|
||||
|
||||
public class Network
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string name { get; set; }
|
||||
public Country country { get; set; }
|
||||
}
|
||||
|
||||
public class Country
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string code { get; set; }
|
||||
public string timezone { get; set; }
|
||||
}
|
||||
|
||||
public class Externals
|
||||
{
|
||||
public int tvrage { get; set; }
|
||||
public int thetvdb { get; set; }
|
||||
public string imdb { get; set; }
|
||||
}
|
||||
|
||||
public class Image
|
||||
{
|
||||
public string medium { get; set; }
|
||||
public string original { get; set; }
|
||||
}
|
||||
|
||||
public class _Links
|
||||
{
|
||||
public Self self { get; set; }
|
||||
public Previousepisode previousepisode { get; set; }
|
||||
}
|
||||
|
||||
public class Self
|
||||
{
|
||||
public string href { get; set; }
|
||||
}
|
||||
|
||||
public class Previousepisode
|
||||
{
|
||||
public string href { get; set; }
|
||||
}
|
||||
|
||||
public class _Embedded
|
||||
{
|
||||
public Cast[] cast { get; set; }
|
||||
public Crew[] crew { get; set; }
|
||||
public Episode[] episodes { get; set; }
|
||||
}
|
||||
|
||||
public class Cast
|
||||
{
|
||||
public Person person { get; set; }
|
||||
public Character character { get; set; }
|
||||
public bool self { get; set; }
|
||||
public bool voice { get; set; }
|
||||
}
|
||||
|
||||
public class Person
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string url { get; set; }
|
||||
public string name { get; set; }
|
||||
public Country country { get; set; }
|
||||
public string birthday { get; set; }
|
||||
public object deathday { get; set; }
|
||||
public string gender { get; set; }
|
||||
public Image image { get; set; }
|
||||
public _Links _links { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class Character
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string url { get; set; }
|
||||
public string name { get; set; }
|
||||
public Image image { get; set; }
|
||||
public _Links _links { get; set; }
|
||||
}
|
||||
|
||||
public class Crew
|
||||
{
|
||||
public string type { get; set; }
|
||||
public Person person { get; set; }
|
||||
}
|
||||
|
||||
public class Episode
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string url { get; set; }
|
||||
public string name { get; set; }
|
||||
public int season { get; set; }
|
||||
public int number { get; set; }
|
||||
public string airdate { get; set; }
|
||||
public string airtime { get; set; }
|
||||
public DateTime airstamp { get; set; }
|
||||
public int runtime { get; set; }
|
||||
public Image image { get; set; }
|
||||
public string summary { get; set; }
|
||||
public _Links _links { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.TvMaze.Models;
|
||||
using Ombi.Api.TvMaze.Models.V2;
|
||||
using Ombi.Helpers;
|
||||
|
||||
namespace Ombi.Api.TvMaze
|
||||
|
@ -15,7 +15,6 @@ namespace Ombi.Api.TvMaze
|
|||
{
|
||||
Api = api;
|
||||
Logger = logger;
|
||||
//Mapper = mapper;
|
||||
}
|
||||
private string Uri = "http://api.tvmaze.com";
|
||||
private IApi Api { get; }
|
||||
|
@ -75,5 +74,17 @@ namespace Ombi.Api.TvMaze
|
|||
return await Api.Request<List<TvMazeSeasons>>(request);
|
||||
}
|
||||
|
||||
public async Task<FullSearch> GetTvFullInformation(int id)
|
||||
{
|
||||
var request = new Request($"shows/{id}", Uri, HttpMethod.Get);
|
||||
|
||||
request.AddQueryString("embed[]", "cast");
|
||||
request.AddQueryString("embed[]", "crew");
|
||||
request.AddQueryString("embed[]", "episodes");
|
||||
|
||||
request.AddContentHeader("Content-Type", "application/json");
|
||||
|
||||
return await Api.Request<FullSearch>(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
106
src/Ombi.Core.Tests/Authentication/OmbiUserManagerTests.cs
Normal file
106
src/Ombi.Core.Tests/Authentication/OmbiUserManagerTests.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
using Microsoft.AspNetCore.Identity;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Api.Plex;
|
||||
using Ombi.Api.Plex.Models;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Test.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Core.Tests.Authentication
|
||||
{
|
||||
[TestFixture]
|
||||
public class OmbiUserManagerTests
|
||||
{
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
|
||||
UserStore = new Mock<IUserStore<OmbiUser>>();
|
||||
PlexApi = new Mock<IPlexApi>();
|
||||
AuthenticationSettings = new Mock<ISettingsService<AuthenticationSettings>>();
|
||||
|
||||
AuthenticationSettings.Setup(x => x.GetSettingsAsync())
|
||||
.ReturnsAsync(new AuthenticationSettings());
|
||||
_um = new OmbiUserManager(UserStore.Object, null, null, null, null, null, null, null, null,
|
||||
PlexApi.Object, null, null, AuthenticationSettings.Object);
|
||||
}
|
||||
|
||||
public OmbiUserManager _um { get; set; }
|
||||
private Mock<IUserStore<OmbiUser>> UserStore { get; set; }
|
||||
private Mock<IPlexApi> PlexApi { get; set; }
|
||||
private Mock<ISettingsService<AuthenticationSettings>> AuthenticationSettings { get; set; }
|
||||
|
||||
[Test]
|
||||
public async Task CheckPassword_PlexUser_EmailLogin_ValidPassword()
|
||||
{
|
||||
var user = new OmbiUser
|
||||
{
|
||||
UserType = UserType.PlexUser,
|
||||
EmailLogin = true,
|
||||
Email = "MyEmail@email.com"
|
||||
};
|
||||
PlexApi.Setup(x => x.SignIn(It.IsAny<UserRequest>()))
|
||||
.ReturnsAsync(new PlexAuthentication
|
||||
{
|
||||
user = new User
|
||||
{
|
||||
authentication_token = "abc"
|
||||
}
|
||||
});
|
||||
var result = await _um.CheckPasswordAsync(user, "pass");
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
PlexApi.Verify(x => x.SignIn(It.Is<UserRequest>(c => c.login == "MyEmail@email.com")), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CheckPassword_PlexUser_UserNameLogin_ValidPassword()
|
||||
{
|
||||
var user = new OmbiUser
|
||||
{
|
||||
UserType = UserType.PlexUser,
|
||||
EmailLogin = false,
|
||||
Email = "MyEmail@email.com",
|
||||
UserName = "heyhey"
|
||||
};
|
||||
PlexApi.Setup(x => x.SignIn(It.IsAny<UserRequest>()))
|
||||
.ReturnsAsync(new PlexAuthentication
|
||||
{
|
||||
user = new User
|
||||
{
|
||||
authentication_token = "abc"
|
||||
}
|
||||
});
|
||||
var result = await _um.CheckPasswordAsync(user, "pass");
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
PlexApi.Verify(x => x.SignIn(It.Is<UserRequest>(c => c.login == "heyhey")), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CheckPassword_PlexUser_UserNameLogin_InvalidPassword()
|
||||
{
|
||||
var user = new OmbiUser
|
||||
{
|
||||
UserType = UserType.PlexUser,
|
||||
EmailLogin = false,
|
||||
Email = "MyEmail@email.com",
|
||||
UserName = "heyhey"
|
||||
};
|
||||
PlexApi.Setup(x => x.SignIn(It.IsAny<UserRequest>()))
|
||||
.ReturnsAsync(new PlexAuthentication());
|
||||
var result = await _um.CheckPasswordAsync(user, "pass");
|
||||
|
||||
Assert.That(result, Is.False);
|
||||
PlexApi.Verify(x => x.SignIn(It.Is<UserRequest>(c => c.login == "heyhey")), Times.Once);
|
||||
}
|
||||
}
|
||||
}
|
195
src/Ombi.Core.Tests/Engine/CalendarEngineTests.cs
Normal file
195
src/Ombi.Core.Tests/Engine/CalendarEngineTests.cs
Normal file
|
@ -0,0 +1,195 @@
|
|||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Engine.V2;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Core.Tests.Engine
|
||||
{
|
||||
[TestFixture]
|
||||
public class CalendarEngineTests
|
||||
{
|
||||
public Mock<IMovieRequestRepository> MovieRepo { get; set; }
|
||||
public Mock<ITvRequestRepository> TvRepo { get; set; }
|
||||
public CalendarEngine CalendarEngine { get; set; }
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
MovieRepo = new Mock<IMovieRequestRepository>();
|
||||
TvRepo = new Mock<ITvRequestRepository>();
|
||||
var principle = new Mock<IPrincipal>();
|
||||
var identity = new Mock<IIdentity>();
|
||||
identity.Setup(x => x.Name).Returns("UnitTest");
|
||||
principle.Setup(x => x.Identity).Returns(identity.Object);
|
||||
CalendarEngine = new CalendarEngine(principle.Object, null, null, MovieRepo.Object, TvRepo.Object);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Calendar_Movies_OnlyGet_PreviousAndFuture_90_Days()
|
||||
{
|
||||
var movies = new List<MovieRequests>
|
||||
{
|
||||
new MovieRequests
|
||||
{
|
||||
Title="Invalid",
|
||||
ReleaseDate = new DateTime(2018,10,01)
|
||||
},
|
||||
new MovieRequests
|
||||
{
|
||||
Title="Invalid",
|
||||
ReleaseDate = DateTime.Now.AddDays(91)
|
||||
},
|
||||
|
||||
new MovieRequests
|
||||
{
|
||||
Title="Valid",
|
||||
ReleaseDate = DateTime.Now
|
||||
}
|
||||
};
|
||||
MovieRepo.Setup(x => x.GetAll()).Returns(movies.AsQueryable());
|
||||
var data = await CalendarEngine.GetCalendarData();
|
||||
|
||||
Assert.That(data.Count, Is.EqualTo(1));
|
||||
Assert.That(data[0].Title, Is.EqualTo("Valid"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Calendar_Episodes_OnlyGet_PreviousAndFuture_90_Days()
|
||||
{
|
||||
var tv = new List<ChildRequests>
|
||||
{
|
||||
new ChildRequests
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Title = "Invalid",
|
||||
AirDate = new DateTime(2018,01,01)
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Title = "Invalid",
|
||||
AirDate = DateTime.Now.AddDays(91)
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Title = "Valid",
|
||||
AirDate = DateTime.Now
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
TvRepo.Setup(x => x.GetChild()).Returns(tv.AsQueryable());
|
||||
var data = await CalendarEngine.GetCalendarData();
|
||||
|
||||
Assert.That(data.Count, Is.EqualTo(1));
|
||||
Assert.That(data[0].Title, Is.EqualTo("Valid"));
|
||||
}
|
||||
|
||||
|
||||
[TestCaseSource(nameof(StatusTvColorData))]
|
||||
public async Task<string> Calendar_Tv_StatusColor(AvailabilityTestModel model)
|
||||
{
|
||||
var tv = new List<ChildRequests>
|
||||
{
|
||||
new ChildRequests
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Title = "Valid",
|
||||
AirDate = DateTime.Now,
|
||||
Approved = model.Approved,
|
||||
Available = model.Available
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
TvRepo.Setup(x => x.GetChild()).Returns(tv.AsQueryable());
|
||||
var data = await CalendarEngine.GetCalendarData();
|
||||
|
||||
return data[0].BackgroundColor;
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(StatusColorData))]
|
||||
public async Task<string> Calendar_Movie_StatusColor(AvailabilityTestModel model)
|
||||
{
|
||||
var movies = new List<MovieRequests>
|
||||
{
|
||||
new MovieRequests
|
||||
{
|
||||
Title="Valid",
|
||||
ReleaseDate = DateTime.Now,
|
||||
Denied = model.Denied,
|
||||
Approved = model.Approved,
|
||||
Available = model.Available
|
||||
},
|
||||
};
|
||||
MovieRepo.Setup(x => x.GetAll()).Returns(movies.AsQueryable());
|
||||
var data = await CalendarEngine.GetCalendarData();
|
||||
|
||||
return data[0].BackgroundColor;
|
||||
}
|
||||
|
||||
public static IEnumerable<TestCaseData> StatusColorData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(new AvailabilityTestModel
|
||||
{
|
||||
Approved = true,
|
||||
Denied = true
|
||||
}).Returns("red").SetName("Calendar_DeniedRequest");
|
||||
foreach (var testCaseData in StatusTvColorData)
|
||||
{
|
||||
yield return testCaseData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<TestCaseData> StatusTvColorData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(new AvailabilityTestModel
|
||||
{
|
||||
Available = true,
|
||||
Approved = true
|
||||
}).Returns("#469c83").SetName("Calendar_AvailableRequest");
|
||||
yield return new TestCaseData(new AvailabilityTestModel
|
||||
{
|
||||
Approved = true
|
||||
}).Returns("blue").SetName("Calendar_ApprovedRequest");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AvailabilityTestModel
|
||||
{
|
||||
public bool Available { get; set; }
|
||||
public bool Denied { get; set; }
|
||||
public bool Approved { get; set; }
|
||||
}
|
||||
}
|
|
@ -3,16 +3,19 @@ using System.Linq;
|
|||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using AutoFixture;
|
||||
using MockQueryable.Moq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Core.Engine.Interfaces;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Test.Common;
|
||||
|
||||
namespace Ombi.Core.Tests.Engine
|
||||
{
|
||||
|
@ -30,12 +33,17 @@ namespace Ombi.Core.Tests.Engine
|
|||
MovieRequestEngine = new Mock<IMovieRequestEngine>();
|
||||
MovieRequestEngine = new Mock<IMovieRequestEngine>();
|
||||
User = new Mock<IPrincipal>();
|
||||
UserManager = new Mock<OmbiUserManager>();
|
||||
UserManager.Setup(x => x.Users)
|
||||
.Returns(new EnumerableQuery<OmbiUser>(new List<OmbiUser> {new OmbiUser {Id = "abc"}}));
|
||||
User.Setup(x => x.Identity.Name).Returns("abc");
|
||||
UserManager = MockHelper.MockUserManager(new List<OmbiUser> { new OmbiUser { Id = "abc", UserName = "abc" } });
|
||||
Rule = new Mock<IRuleEvaluator>();
|
||||
Engine = new VoteEngine(VoteRepository.Object, User.Object, UserManager.Object, Rule.Object, VoteSettings.Object, MusicRequestEngine.Object,
|
||||
TvRequestEngine.Object, MovieRequestEngine.Object);
|
||||
|
||||
F.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
|
||||
.ForEach(b => F.Behaviors.Remove(b));
|
||||
F.Behaviors.Add(new OmitOnRecursionBehavior());
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Fixture F { get; set; }
|
||||
|
@ -49,25 +57,160 @@ namespace Ombi.Core.Tests.Engine
|
|||
public Mock<ITvRequestEngine> TvRequestEngine { get; set; }
|
||||
public Mock<IMovieRequestEngine> MovieRequestEngine { get; set; }
|
||||
|
||||
[Test]
|
||||
[Ignore("Need to mock the user manager")]
|
||||
public async Task New_Upvote()
|
||||
[TestCaseSource(nameof(VoteData))]
|
||||
public async Task Vote(VoteType type, RequestType request)
|
||||
{
|
||||
VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings());
|
||||
VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings
|
||||
{
|
||||
Enabled = true,
|
||||
MovieVoteMax = 10
|
||||
});
|
||||
var votes = F.CreateMany<Votes>().ToList();
|
||||
|
||||
VoteRepository.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Votes>(votes)
|
||||
.AsQueryable()
|
||||
.BuildMock().Object);
|
||||
var result = new VoteEngineResult();
|
||||
if (type == VoteType.Downvote)
|
||||
{
|
||||
result = await Engine.DownVote(1, request);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await Engine.UpVote(1, request);
|
||||
}
|
||||
|
||||
Assert.That(result.Result, Is.True);
|
||||
VoteRepository.Verify(x => x.Add(It.Is<Votes>(c => c.UserId == "abc" && c.VoteType == type)), Times.Once);
|
||||
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Never);
|
||||
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
|
||||
}
|
||||
public static IEnumerable<TestCaseData> VoteData
|
||||
{
|
||||
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(VoteType.Upvote, RequestType.Movie).SetName("Movie_Upvote");
|
||||
yield return new TestCaseData(VoteType.Downvote, RequestType.Movie).SetName("Movie_Downvote");
|
||||
yield return new TestCaseData(VoteType.Upvote, RequestType.TvShow).SetName("Tv_Upvote");
|
||||
yield return new TestCaseData(VoteType.Downvote, RequestType.TvShow).SetName("Tv_Downvote");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TestCaseSource(nameof(AttemptedTwiceData))]
|
||||
public async Task Attempted_Twice(VoteType type, RequestType request)
|
||||
{
|
||||
VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings
|
||||
{
|
||||
Enabled = true,
|
||||
MovieVoteMax = 10
|
||||
});
|
||||
var votes = F.CreateMany<Votes>().ToList();
|
||||
votes.Add(new Votes
|
||||
{
|
||||
RequestId = 1,
|
||||
RequestType = RequestType.Movie,
|
||||
UserId = "abc"
|
||||
UserId = "abc",
|
||||
VoteType = type
|
||||
});
|
||||
VoteRepository.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Votes>(votes));
|
||||
var result = await Engine.UpVote(1, RequestType.Movie);
|
||||
VoteRepository.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Votes>(votes)
|
||||
.AsQueryable()
|
||||
.BuildMock().Object);
|
||||
var result = new VoteEngineResult();
|
||||
if (type == VoteType.Downvote)
|
||||
{
|
||||
result = await Engine.DownVote(1, request);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await Engine.UpVote(1, request);
|
||||
}
|
||||
|
||||
Assert.That(result.Result, Is.False);
|
||||
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Never);
|
||||
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
|
||||
}
|
||||
public static IEnumerable<TestCaseData> AttemptedTwiceData
|
||||
{
|
||||
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(VoteType.Upvote, RequestType.Movie).SetName("Upvote_Attemped_Twice_Movie");
|
||||
yield return new TestCaseData(VoteType.Downvote, RequestType.Movie).SetName("Downvote_Attempted_Twice_Movie");
|
||||
yield return new TestCaseData(VoteType.Upvote, RequestType.TvShow).SetName("Upvote_Attemped_Twice_Tv");
|
||||
yield return new TestCaseData(VoteType.Downvote, RequestType.TvShow).SetName("Downvote_Attempted_Twice_Tv");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(VoteConvertData))]
|
||||
public async Task Downvote_Converted_To_Upvote(VoteType type, RequestType request)
|
||||
{
|
||||
VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings
|
||||
{
|
||||
Enabled = true,
|
||||
MovieVoteMax = 10
|
||||
});
|
||||
var votes = F.CreateMany<Votes>().ToList();
|
||||
votes.Add(new Votes
|
||||
{
|
||||
RequestId = 1,
|
||||
RequestType = request,
|
||||
UserId = "abc",
|
||||
VoteType = type == VoteType.Upvote ? VoteType.Downvote : VoteType.Upvote
|
||||
});
|
||||
VoteRepository.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Votes>(votes)
|
||||
.AsQueryable()
|
||||
.BuildMock().Object);
|
||||
|
||||
var result = new VoteEngineResult();
|
||||
if (type == VoteType.Downvote)
|
||||
{
|
||||
result = await Engine.DownVote(1, request);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await Engine.UpVote(1, request);
|
||||
}
|
||||
Assert.That(result.Result, Is.True);
|
||||
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Once);
|
||||
VoteRepository.Verify(x => x.Add(It.Is<Votes>(v => v.VoteType == type)), Times.Once);
|
||||
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
|
||||
}
|
||||
public static IEnumerable<TestCaseData> VoteConvertData
|
||||
{
|
||||
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(VoteType.Upvote, RequestType.Movie).SetName("Downvote_Converted_To_UpVote_Movie");
|
||||
yield return new TestCaseData(VoteType.Downvote, RequestType.Movie).SetName("UpVote_Converted_To_DownVote_Movie");
|
||||
yield return new TestCaseData(VoteType.Upvote, RequestType.TvShow).SetName("Downvote_Converted_To_UpVote_TvShow");
|
||||
yield return new TestCaseData(VoteType.Downvote, RequestType.TvShow).SetName("UpVote_Converted_To_DownVote_TvShow");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TestCaseSource(nameof(VotingDisabledData))]
|
||||
public async Task Voting_Disabled(RequestType type)
|
||||
{
|
||||
VoteSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new VoteSettings
|
||||
{
|
||||
Enabled = false,
|
||||
MovieVoteMax = 10
|
||||
});
|
||||
|
||||
var result = await Engine.UpVote(1, type);
|
||||
|
||||
Assert.That(result.Result, Is.True);
|
||||
VoteRepository.Verify(x => x.Add(It.Is<Votes>(c => c.UserId == "abc" && c.VoteType == VoteType.Upvote)), Times.Once);
|
||||
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Once);
|
||||
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
|
||||
VoteRepository.Verify(x => x.Add(It.IsAny<Votes>()), Times.Never);
|
||||
}
|
||||
public static IEnumerable<TestCaseData> VotingDisabledData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(RequestType.Movie).SetName("Voting_Disabled_Movie");
|
||||
yield return new TestCaseData(RequestType.TvShow).SetName("Voting_Disabled_TV");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,14 +7,16 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="AutoFixture" Version="4.5.0" />
|
||||
<PackageReference Include="Moq" Version="4.10.0" />
|
||||
<PackageReference Include="Nunit" Version="3.10.1" />
|
||||
<PackageReference Include="Nunit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.9.0"></packagereference>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="16.0.1"></packagereference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Test.Common\Ombi.Test.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -4,29 +4,43 @@ using Moq;
|
|||
using Ombi.Core.Rule.Rules.Request;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Test.Common;
|
||||
using System.Collections.Generic;
|
||||
using Ombi.Store.Entities;
|
||||
using System;
|
||||
|
||||
namespace Ombi.Core.Tests.Rule.Request
|
||||
{
|
||||
[TestFixture]
|
||||
public class AutoApproveRuleTests
|
||||
{
|
||||
private List<OmbiUser> _users = new List<OmbiUser>
|
||||
{
|
||||
new OmbiUser { Id = Guid.NewGuid().ToString("N"), UserName="abc" }
|
||||
};
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
|
||||
PrincipalMock = new Mock<IPrincipal>();
|
||||
Rule = new AutoApproveRule(PrincipalMock.Object);
|
||||
PrincipalMock.Setup(x => x.Identity.Name).Returns("abc");
|
||||
|
||||
UserManager = MockHelper.MockUserManager(_users);
|
||||
Rule = new AutoApproveRule(PrincipalMock.Object, UserManager.Object);
|
||||
}
|
||||
|
||||
|
||||
private AutoApproveRule Rule { get; set; }
|
||||
private Mock<IPrincipal> PrincipalMock { get; set; }
|
||||
private Mock<OmbiUserManager> UserManager { get; set; }
|
||||
|
||||
[Test]
|
||||
public async Task Should_ReturnSuccess_WhenAdminAndRequestMovie()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.Admin)).Returns(true);
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(true);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
@ -37,7 +51,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
[Test]
|
||||
public async Task Should_ReturnSuccess_WhenAdminAndRequestTV()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.Admin)).Returns(true);
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(true);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
@ -48,7 +62,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
[Test]
|
||||
public async Task Should_ReturnSuccess_WhenAutoApproveMovieAndRequestMovie()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.AutoApproveMovie)).Returns(true);
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveMovie)).ReturnsAsync(true);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
@ -56,10 +70,21 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
Assert.True(request.Approved);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Should_ReturnFail_WhenAutoApproveMovie_And_RequestTV()
|
||||
{
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveMovie)).ReturnsAsync(true);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Should_ReturnSuccess_WhenAutoApproveTVAndRequestTV()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.AutoApproveTv)).Returns(true);
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveTv)).ReturnsAsync(true);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
@ -67,9 +92,21 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
Assert.True(request.Approved);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Should_ReturnFail_WhenAutoApproveTV_And_RequestMovie()
|
||||
{
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveTv)).ReturnsAsync(true);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Should_ReturnFail_WhenNoClaimsAndRequestMovie()
|
||||
{
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), It.IsAny<string>())).ReturnsAsync(false);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
@ -80,6 +117,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
[Test]
|
||||
public async Task Should_ReturnFail_WhenNoClaimsAndRequestTV()
|
||||
{
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), It.IsAny<string>())).ReturnsAsync(false);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
|
|
@ -1,31 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Rule.Rules;
|
||||
using Ombi.Core.Rule.Rules.Request;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Test.Common;
|
||||
|
||||
namespace Ombi.Core.Tests.Rule.Request
|
||||
{
|
||||
public class CanRequestRuleTests
|
||||
{
|
||||
private List<OmbiUser> _users = new List<OmbiUser>
|
||||
{
|
||||
new OmbiUser { Id = Guid.NewGuid().ToString("N"), UserName="abc" }
|
||||
};
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
|
||||
PrincipalMock = new Mock<IPrincipal>();
|
||||
Rule = new CanRequestRule(PrincipalMock.Object);
|
||||
PrincipalMock.Setup(x => x.Identity.Name).Returns("abc");
|
||||
|
||||
UserManager = MockHelper.MockUserManager(_users);
|
||||
Rule = new CanRequestRule(PrincipalMock.Object, UserManager.Object);
|
||||
}
|
||||
|
||||
|
||||
private CanRequestRule Rule { get; set; }
|
||||
private Mock<IPrincipal> PrincipalMock { get; set; }
|
||||
private Mock<OmbiUserManager> UserManager { get; set; }
|
||||
|
||||
[Test]
|
||||
public async Task Should_ReturnSuccess_WhenRequestingMovieWithMovieRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.RequestMovie)).Returns(true);
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestMovie)).ReturnsAsync(true);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
@ -35,7 +50,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
[Test]
|
||||
public async Task Should_ReturnFail_WhenRequestingMovieWithoutMovieRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.RequestMovie)).Returns(false);
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestMovie)).ReturnsAsync(false);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
@ -46,7 +61,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
[Test]
|
||||
public async Task Should_ReturnSuccess_WhenRequestingMovieWithAdminRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.Admin)).Returns(true);
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(true);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
@ -56,7 +71,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
[Test]
|
||||
public async Task Should_ReturnSuccess_WhenRequestingTVWithAdminRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.Admin)).Returns(true);
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(true);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
@ -66,7 +81,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
[Test]
|
||||
public async Task Should_ReturnSuccess_WhenRequestingTVWithTVRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.RequestTv)).Returns(true);
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestTv)).ReturnsAsync(true);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
@ -76,7 +91,7 @@ namespace Ombi.Core.Tests.Rule.Request
|
|||
[Test]
|
||||
public async Task Should_ReturnFail_WhenRequestingTVWithoutTVRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiRoles.RequestTv)).Returns(false);
|
||||
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.RequestTv)).ReturnsAsync(false);
|
||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using MockQueryable.Moq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Rule.Rules;
|
||||
using Ombi.Core.Rule.Rules.Request;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using Ombi.Test.Common;
|
||||
|
||||
namespace Ombi.Core.Tests.Rule.Request
|
||||
{
|
||||
public class ExistingMovieRequestRuleTests
|
||||
{
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
ContextMock = new Mock<IMovieRequestRepository>();
|
||||
Rule = new ExistingMovieRequestRule(ContextMock.Object);
|
||||
}
|
||||
|
||||
|
||||
private ExistingMovieRequestRule Rule { get; set; }
|
||||
private Mock<IMovieRequestRepository> ContextMock { get; set; }
|
||||
|
||||
[Test]
|
||||
public async Task ExistingRequestRule_Movie_Has_Been_Requested_With_TheMovieDBId()
|
||||
{
|
||||
ContextMock.Setup(x => x.GetAll()).Returns(new List<MovieRequests>
|
||||
{
|
||||
new MovieRequests
|
||||
{
|
||||
TheMovieDbId = 1,
|
||||
RequestType = RequestType.Movie
|
||||
}
|
||||
}.AsQueryable().BuildMock().Object);
|
||||
var o = new MovieRequests
|
||||
{
|
||||
TheMovieDbId = 1,
|
||||
};
|
||||
var result = await Rule.Execute(o);
|
||||
|
||||
Assert.That(result.Success, Is.False);
|
||||
Assert.That(result.Message, Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ExistingRequestRule_Movie_Has_Been_Requested_With_ImdbId()
|
||||
{
|
||||
ContextMock.Setup(x => x.GetAll()).Returns(new List<MovieRequests>
|
||||
{
|
||||
new MovieRequests
|
||||
{
|
||||
TheMovieDbId = 11111,
|
||||
ImdbId = 1.ToString(),
|
||||
RequestType = RequestType.Movie
|
||||
}
|
||||
}.AsQueryable().BuildMock().Object);
|
||||
var o = new MovieRequests
|
||||
{
|
||||
ImdbId = 1.ToString(),
|
||||
};
|
||||
var result = await Rule.Execute(o);
|
||||
|
||||
Assert.That(result.Success, Is.False);
|
||||
Assert.That(result.Message, Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ExistingRequestRule_Movie_HasNot_Been_Requested()
|
||||
{
|
||||
ContextMock.Setup(x => x.GetAll()).Returns(new List<MovieRequests>
|
||||
{
|
||||
new MovieRequests
|
||||
{
|
||||
TheMovieDbId = 2,
|
||||
ImdbId = "2",
|
||||
RequestType = RequestType.Movie
|
||||
}
|
||||
}.AsQueryable().BuildMock().Object);
|
||||
var o = new MovieRequests
|
||||
{
|
||||
TheMovieDbId = 1,
|
||||
ImdbId = "1"
|
||||
};
|
||||
var result = await Rule.Execute(o);
|
||||
|
||||
Assert.That(result.Success, Is.True);
|
||||
Assert.That(result.Message, Is.Null.Or.Empty);
|
||||
}
|
||||
}
|
||||
}
|
201
src/Ombi.Core.Tests/Rule/Search/AvailabilityRuleHelperTests.cs
Normal file
201
src/Ombi.Core.Tests/Rule/Search/AvailabilityRuleHelperTests.cs
Normal file
|
@ -0,0 +1,201 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Rule.Rules.Search;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Core.Tests.Rule.Search
|
||||
{
|
||||
public class AvailabilityRuleHelperTests
|
||||
{
|
||||
|
||||
|
||||
[Test]
|
||||
public void Is_Available_When_All_We_Have_All_Aired_Episodes()
|
||||
{
|
||||
var episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||
Available = true
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.Now.AddDays(1), // Tomorrow!
|
||||
Available = false
|
||||
}
|
||||
};
|
||||
|
||||
var model = new SearchTvShowViewModel
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests> { new SeasonRequests { Episodes = episodes } }
|
||||
};
|
||||
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||
Assert.That(model.FullyAvailable, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Is_Available_When_All_We_Have_All_Aired_Episodes_With_Unknown_Dates()
|
||||
{
|
||||
var episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||
Available = true
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.MinValue, // Unknown date!
|
||||
Available = false
|
||||
}
|
||||
};
|
||||
|
||||
var model = new SearchTvShowViewModel
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests> { new SeasonRequests { Episodes = episodes } }
|
||||
};
|
||||
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||
Assert.That(model.FullyAvailable, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Is_PartlyAvailable_When_All_We_Have_Some_Aired_Episodes()
|
||||
{
|
||||
var episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||
Available = true
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.Now.AddDays(-14), // Yesterday
|
||||
Available = false
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.MinValue, // Unknown date!
|
||||
Available = false
|
||||
}
|
||||
};
|
||||
|
||||
var model = new SearchTvShowViewModel
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests> { new SeasonRequests { Episodes = episodes } }
|
||||
};
|
||||
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||
Assert.That(model.FullyAvailable, Is.False);
|
||||
Assert.That(model.PartlyAvailable, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Is_SeasonAvailable_When_All_We_Have_All_Aired_Episodes_In_A_Season()
|
||||
{
|
||||
var episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||
Available = true
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.Now.AddDays(-14), // Yesterday
|
||||
Available = false
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.MinValue, // Unknown date!
|
||||
Available = false
|
||||
}
|
||||
};
|
||||
|
||||
var availableEpisodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||
Available = true
|
||||
},
|
||||
};
|
||||
|
||||
var model = new SearchTvShowViewModel
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests { Episodes = episodes },
|
||||
new SeasonRequests { Episodes = availableEpisodes },
|
||||
}
|
||||
};
|
||||
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||
Assert.That(model.FullyAvailable, Is.False);
|
||||
Assert.That(model.PartlyAvailable, Is.True);
|
||||
Assert.That(model.SeasonRequests[1].SeasonAvailable, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Is_NotAvailable_When_All_We_Have_No_Aired_Episodes()
|
||||
{
|
||||
var episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.Now.AddDays(-1), // Yesterday
|
||||
Available = false
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.Now.AddDays(-14),
|
||||
Available = false
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.MinValue, // Unknown date!
|
||||
Available = false
|
||||
}
|
||||
};
|
||||
|
||||
var model = new SearchTvShowViewModel
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests> { new SeasonRequests { Episodes = episodes } }
|
||||
};
|
||||
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||
Assert.That(model.FullyAvailable, Is.False);
|
||||
Assert.That(model.PartlyAvailable, Is.False);
|
||||
}
|
||||
[Test]
|
||||
public void Is_NotAvailable_When_All_Episodes_Are_Unknown()
|
||||
{
|
||||
var episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.MinValue,
|
||||
Available = false
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.MinValue,
|
||||
Available = false
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
AirDate = DateTime.MinValue, // Unknown date!
|
||||
Available = false
|
||||
}
|
||||
};
|
||||
|
||||
var model = new SearchTvShowViewModel
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests> { new SeasonRequests { Episodes = episodes } }
|
||||
};
|
||||
AvailabilityRuleHelper.CheckForUnairedEpisodes(model);
|
||||
Assert.That(model.FullyAvailable, Is.False);
|
||||
Assert.That(model.PartlyAvailable, Is.False);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ using Moq;
|
|||
using NUnit.Framework;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Rule.Rules.Search;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
@ -16,15 +18,18 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
public void Setup()
|
||||
{
|
||||
ContextMock = new Mock<IEmbyContentRepository>();
|
||||
Rule = new EmbyAvailabilityRule(ContextMock.Object);
|
||||
SettingsMock = new Mock<ISettingsService<EmbySettings>>();
|
||||
Rule = new EmbyAvailabilityRule(ContextMock.Object, SettingsMock.Object);
|
||||
}
|
||||
|
||||
private EmbyAvailabilityRule Rule { get; set; }
|
||||
private Mock<IEmbyContentRepository> ContextMock { get; set; }
|
||||
private Mock<ISettingsService<EmbySettings>> SettingsMock { get; set; }
|
||||
|
||||
[Test]
|
||||
public async Task Movie_ShouldBe_Available_WhenFoundInEmby()
|
||||
{
|
||||
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new EmbySettings());
|
||||
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent
|
||||
{
|
||||
ProviderId = "123"
|
||||
|
@ -39,6 +44,64 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
Assert.True(search.Available);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Movie_Has_Custom_Url_When_Specified_In_Settings()
|
||||
{
|
||||
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new EmbySettings
|
||||
{
|
||||
Enable = true,
|
||||
Servers = new List<EmbyServers>
|
||||
{
|
||||
new EmbyServers
|
||||
{
|
||||
ServerHostname = "http://test.com/"
|
||||
}
|
||||
}
|
||||
});
|
||||
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent
|
||||
{
|
||||
ProviderId = "123",
|
||||
EmbyId = 1.ToString()
|
||||
});
|
||||
var search = new SearchMovieViewModel()
|
||||
{
|
||||
TheMovieDbId = "123",
|
||||
};
|
||||
var result = await Rule.Execute(search);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.That(search.EmbyUrl, Is.EqualTo("http://test.com/#!/itemdetails.html?id=1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Movie_Uses_Default_Url_When()
|
||||
{
|
||||
SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new EmbySettings
|
||||
{
|
||||
Enable = true,
|
||||
Servers = new List<EmbyServers>
|
||||
{
|
||||
new EmbyServers
|
||||
{
|
||||
ServerHostname = string.Empty
|
||||
}
|
||||
}
|
||||
});
|
||||
ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny<string>())).ReturnsAsync(new EmbyContent
|
||||
{
|
||||
ProviderId = "123",
|
||||
EmbyId = 1.ToString()
|
||||
});
|
||||
var search = new SearchMovieViewModel()
|
||||
{
|
||||
TheMovieDbId = "123",
|
||||
};
|
||||
var result = await Rule.Execute(search);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.That(search.EmbyUrl, Is.EqualTo("https://app.emby.media/#!/itemdetails.html?id=1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Movie_ShouldBe_NotAvailable_WhenNotFoundInEmby()
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@ using Ombi.Store.Repository.Requests;
|
|||
|
||||
namespace Ombi.Core.Tests.Rule.Search
|
||||
{
|
||||
public class ExistignRequestRuleTests
|
||||
public class ExistingRequestRuleTests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
|
@ -39,18 +39,16 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
RequestType = RequestType.Movie
|
||||
};
|
||||
|
||||
MovieMock.Setup(x => x.GetRequest(123)).Returns(list);
|
||||
MovieMock.Setup(x => x.GetRequestAsync(123)).ReturnsAsync(list);
|
||||
var search = new SearchMovieViewModel
|
||||
{
|
||||
Id = 123,
|
||||
|
||||
|
||||
};
|
||||
var result = await Rule.Execute(search);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.True(search.Approved);
|
||||
Assert.True(search.Requested);
|
||||
Assert.That(result.Success, Is.True);
|
||||
Assert.That(search.Approved, Is.True);
|
||||
Assert.That(search.Requested, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -62,7 +60,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
Approved = true
|
||||
};
|
||||
|
||||
MovieMock.Setup(x => x.GetRequest(123)).Returns(list);
|
||||
MovieMock.Setup(x => x.GetRequestAsync(123)).ReturnsAsync(list);
|
||||
var search = new SearchMovieViewModel
|
||||
{
|
||||
Id = 999,
|
||||
|
|
126
src/Ombi.Core.Tests/Rule/Search/LidarrAlbumCacheRuleTests.cs
Normal file
126
src/Ombi.Core.Tests/Rule/Search/LidarrAlbumCacheRuleTests.cs
Normal file
|
@ -0,0 +1,126 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Rule.Rules.Search;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Core.Tests.Rule.Search
|
||||
{
|
||||
public class LidarrAlbumCacheRuleTests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
ContextMock = new Mock<IExternalRepository<LidarrAlbumCache>>();
|
||||
Rule = new LidarrAlbumCacheRule(ContextMock.Object);
|
||||
|
||||
}
|
||||
|
||||
private LidarrAlbumCacheRule Rule { get; set; }
|
||||
private Mock<IExternalRepository<LidarrAlbumCache>> ContextMock { get; set; }
|
||||
|
||||
[Test]
|
||||
public async Task Should_Not_Be_Monitored_Or_Available()
|
||||
{
|
||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
Assert.False(request.Monitored);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Should_Be_Monitored_But_Not_Available()
|
||||
{
|
||||
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrAlbumCache>
|
||||
{
|
||||
new LidarrAlbumCache
|
||||
{
|
||||
ForeignAlbumId = "abc",
|
||||
PercentOfTracks = 0
|
||||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
Assert.True(request.Monitored);
|
||||
Assert.That(request.PartiallyAvailable, Is.EqualTo(false));
|
||||
Assert.That(request.Available, Is.EqualTo(false));
|
||||
Assert.That(request.FullyAvailable, Is.EqualTo(false));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Should_Be_Monitored_And_Partly_Available()
|
||||
{
|
||||
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrAlbumCache>
|
||||
{
|
||||
new LidarrAlbumCache
|
||||
{
|
||||
ForeignAlbumId = "abc",
|
||||
PercentOfTracks = 1
|
||||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
Assert.True(request.Monitored);
|
||||
Assert.That(request.PartiallyAvailable, Is.EqualTo(true));
|
||||
Assert.That(request.Available, Is.EqualTo(false));
|
||||
Assert.That(request.FullyAvailable, Is.EqualTo(false));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Should_Be_Monitored_And_Fully_Available()
|
||||
{
|
||||
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrAlbumCache>
|
||||
{
|
||||
new LidarrAlbumCache
|
||||
{
|
||||
ForeignAlbumId = "abc",
|
||||
PercentOfTracks = 100
|
||||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
Assert.True(request.Monitored);
|
||||
Assert.That(request.PartiallyAvailable, Is.EqualTo(false));
|
||||
Assert.That(request.FullyAvailable, Is.EqualTo(true));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Should_Be_Monitored_And_Fully_Available_Casing()
|
||||
{
|
||||
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrAlbumCache>
|
||||
{
|
||||
new LidarrAlbumCache
|
||||
{
|
||||
ForeignAlbumId = "abc",
|
||||
PercentOfTracks = 100
|
||||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "ABC" };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
Assert.True(request.Monitored);
|
||||
Assert.That(request.PartiallyAvailable, Is.EqualTo(false));
|
||||
Assert.That(request.FullyAvailable, Is.EqualTo(true));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Rule.Rules.Search;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Core.Tests.Rule.Search
|
||||
{
|
||||
public class LidarrArtistCacheRuleTests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
ContextMock = new Mock<IExternalRepository<LidarrArtistCache>>();
|
||||
Rule = new LidarrArtistCacheRule(ContextMock.Object);
|
||||
}
|
||||
|
||||
private LidarrArtistCacheRule Rule { get; set; }
|
||||
private Mock<IExternalRepository<LidarrArtistCache>> ContextMock { get; set; }
|
||||
|
||||
[Test]
|
||||
public async Task Should_Not_Be_Monitored()
|
||||
{
|
||||
var request = new SearchArtistViewModel { ForignArtistId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Monitored);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Should_Be_Monitored()
|
||||
{
|
||||
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrArtistCache>
|
||||
{
|
||||
new LidarrArtistCache
|
||||
{
|
||||
ForeignArtistId = "abc",
|
||||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchArtistViewModel { ForignArtistId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.True(request.Monitored);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async Task Should_Be_Monitored_Casing()
|
||||
{
|
||||
ContextMock.Setup(x => x.GetAll()).Returns(new List<LidarrArtistCache>
|
||||
{
|
||||
new LidarrArtistCache
|
||||
{
|
||||
ForeignArtistId = "abc",
|
||||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchArtistViewModel { ForignArtistId = "ABC" };
|
||||
var result = await Rule.Execute(request);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.True(request.Monitored);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Rule.Rules.Search;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Core.Tests.Rule.Search
|
||||
{
|
||||
public class PlexAvailabilityRuleTests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
ContextMock = new Mock<IPlexContentRepository>();
|
||||
Rule = new PlexAvailabilityRule(ContextMock.Object);
|
||||
}
|
||||
|
||||
private PlexAvailabilityRule Rule { get; set; }
|
||||
private Mock<IPlexContentRepository> ContextMock { get; set; }
|
||||
|
||||
[Test]
|
||||
public async Task ShouldBe_Available_WhenFoundInPlex()
|
||||
{
|
||||
ContextMock.Setup(x => x.Get(It.IsAny<string>())).ReturnsAsync(new PlexServerContent
|
||||
{
|
||||
Url = "TestUrl",
|
||||
ImdbId = "132"
|
||||
});
|
||||
|
||||
var search = new SearchMovieViewModel
|
||||
{
|
||||
ImdbId = "123",
|
||||
};
|
||||
var result = await Rule.Execute(search);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.AreEqual("TestUrl", search.PlexUrl);
|
||||
Assert.True(search.Available);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ShouldBe_NotAvailable_WhenNotFoundInPlex()
|
||||
{
|
||||
ContextMock.Setup(x => x.Get(It.IsAny<string>())).Returns(Task.FromResult(default(PlexServerContent)));
|
||||
var search = new SearchMovieViewModel();
|
||||
var result = await Rule.Execute(search);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.Null(search.PlexUrl);
|
||||
Assert.False(search.Available);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace Ombi.Core.Tests
|
|||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("this!is^a*string",new []{'!','^','*'}).Returns("thisisastring").SetName("Basic Strip Multipe Chars");
|
||||
yield return new TestCaseData("this!is^a*string",new []{'!','^','*'}).Returns("thisisastring").SetName("Basic Strip Multiple Chars");
|
||||
yield return new TestCaseData("What is this madness'",new []{'\'','^','*'}).Returns("What is this madness").SetName("Basic Strip Multipe Chars");
|
||||
}
|
||||
}
|
||||
|
|
106
src/Ombi.Core/Engine/Demo/DemoMovieSearchEngine.cs
Normal file
106
src/Ombi.Core/Engine/Demo/DemoMovieSearchEngine.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Ombi.Api.TheMovieDb;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Config;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Core.Engine.Demo
|
||||
{
|
||||
public class DemoMovieSearchEngine : MovieSearchEngine, IDemoMovieSearchEngine
|
||||
{
|
||||
public DemoMovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
|
||||
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s,
|
||||
IRepository<RequestSubscription> sub, IOptions<DemoLists> lists)
|
||||
: base(identity, service, movApi, mapper, logger, r, um, mem, s, sub)
|
||||
{
|
||||
_demoLists = lists.Value;
|
||||
}
|
||||
|
||||
private readonly DemoLists _demoLists;
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> Search(string search)
|
||||
{
|
||||
var result = await MovieApi.SearchMovie(search, null, "en");
|
||||
|
||||
for (var i = 0; i < result.Count; i++)
|
||||
{
|
||||
if (!_demoLists.Movies.Contains(result[i].Id))
|
||||
{
|
||||
result.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
if(result.Count > 0)
|
||||
return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
|
||||
{
|
||||
var rand = new Random();
|
||||
var responses = new List<SearchMovieViewModel>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var item = rand.Next(_demoLists.Movies.Length);
|
||||
var movie = _demoLists.Movies[item];
|
||||
if (responses.Any(x => x.Id == movie))
|
||||
{
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
var movieResult = await MovieApi.GetMovieInformationWithExtraInfo(movie);
|
||||
var viewMovie = Mapper.Map<SearchMovieViewModel>(movieResult);
|
||||
|
||||
responses.Add(await ProcessSingleMovie(viewMovie));
|
||||
}
|
||||
|
||||
return responses;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
|
||||
{
|
||||
return await NowPlayingMovies();
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
|
||||
{
|
||||
return await NowPlayingMovies();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
|
||||
{
|
||||
|
||||
return await NowPlayingMovies();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IDemoMovieSearchEngine
|
||||
{
|
||||
Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies();
|
||||
|
||||
Task<IEnumerable<SearchMovieViewModel>> PopularMovies();
|
||||
|
||||
Task<IEnumerable<SearchMovieViewModel>> Search(string search);
|
||||
|
||||
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies();
|
||||
|
||||
Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies();
|
||||
|
||||
}
|
||||
}
|
96
src/Ombi.Core/Engine/Demo/DemoTvSearchEngine.cs
Normal file
96
src/Ombi.Core/Engine/Demo/DemoTvSearchEngine.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using AutoMapper;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Ombi.Api.Trakt;
|
||||
using Ombi.Api.TvMaze;
|
||||
using Ombi.Config;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Core.Engine.Demo
|
||||
{
|
||||
public class DemoTvSearchEngine : TvSearchEngine, IDemoTvSearchEngine
|
||||
{
|
||||
|
||||
public DemoTvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
|
||||
ISettingsService<PlexSettings> plexSettings, ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo,
|
||||
IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache,
|
||||
ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, IOptions<DemoLists> lists)
|
||||
: base(identity, service, tvMaze, mapper, plexSettings, embySettings, repo, embyRepo, trakt, r, um, memCache, s, sub)
|
||||
{
|
||||
_demoLists = lists.Value;
|
||||
}
|
||||
|
||||
private readonly DemoLists _demoLists;
|
||||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Search(string search)
|
||||
{
|
||||
var searchResult = await TvMazeApi.Search(search);
|
||||
|
||||
for (var i = 0; i < searchResult.Count; i++)
|
||||
{
|
||||
if (!_demoLists.TvShows.Contains(searchResult[i].show?.externals?.thetvdb ?? 0))
|
||||
{
|
||||
searchResult.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (searchResult != null)
|
||||
{
|
||||
var retVal = new List<SearchTvShowViewModel>();
|
||||
foreach (var tvMazeSearch in searchResult)
|
||||
{
|
||||
if (tvMazeSearch.show.externals == null || !(tvMazeSearch.show.externals?.thetvdb.HasValue ?? false))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
retVal.Add(ProcessResult(tvMazeSearch));
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> NowPlayingMovies()
|
||||
{
|
||||
var rand = new Random();
|
||||
var responses = new List<SearchTvShowViewModel>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var item = rand.Next(_demoLists.TvShows.Length);
|
||||
var tv = _demoLists.TvShows[item];
|
||||
if (responses.Any(x => x.Id == tv))
|
||||
{
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
var movieResult = await TvMazeApi.ShowLookup(tv);
|
||||
responses.Add(ProcessResult(movieResult));
|
||||
}
|
||||
|
||||
return responses;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public interface IDemoTvSearchEngine
|
||||
{
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Search(string search);
|
||||
Task<IEnumerable<SearchTvShowViewModel>> NowPlayingMovies();
|
||||
}
|
||||
}
|
|
@ -1,12 +1,24 @@
|
|||
using Ombi.Core.Models.Search;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
|
||||
namespace Ombi.Core
|
||||
namespace Ombi.Core.Engine.Interfaces
|
||||
{
|
||||
public interface IMovieEngineV2
|
||||
{
|
||||
Task<MovieFullInfoViewModel> GetFullMovieInformation(int theMovieDbId, string langCode = null);
|
||||
Task<IEnumerable<SearchMovieViewModel>> SimilarMovies(int theMovieDbId, string langCode);
|
||||
Task<IEnumerable<SearchMovieViewModel>> PopularMovies();
|
||||
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies();
|
||||
Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies();
|
||||
Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies();
|
||||
Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies(int currentPosition, int amountToLoad);
|
||||
Task<MovieCollectionsViewModel> GetCollection(int collectionId, string langCode = null);
|
||||
Task<int> GetTvDbId(int theMovieDbId);
|
||||
Task<IEnumerable<SearchMovieViewModel>> PopularMovies(int currentlyLoaded, int toLoad);
|
||||
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies(int currentlyLoaded, int toLoad);
|
||||
Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies(int currentlyLoaded, int toLoad);
|
||||
int ResultLimit { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.UI;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
|
||||
namespace Ombi.Core.Engine.Interfaces
|
||||
|
@ -13,10 +14,11 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
|
||||
Task RemoveMovieRequest(int requestId);
|
||||
Task RemoveAllMovieRequests();
|
||||
|
||||
Task<MovieRequests> GetRequest(int requestId);
|
||||
Task<MovieRequests> UpdateMovieRequest(MovieRequests request);
|
||||
Task<RequestEngineResult> ApproveMovie(MovieRequests request);
|
||||
Task<RequestEngineResult> ApproveMovieById(int requestId);
|
||||
Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason);
|
||||
Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder);
|
||||
}
|
||||
}
|
|
@ -23,5 +23,6 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
Task<IEnumerable<TvRequests>> GetRequestsLite();
|
||||
Task UpdateQualityProfile(int requestId, int profileId);
|
||||
Task UpdateRootPath(int requestId, int rootPath);
|
||||
Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder);
|
||||
}
|
||||
}
|
|
@ -9,9 +9,13 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm);
|
||||
Task<SearchTvShowViewModel> GetShowInformation(int tvdbid);
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Popular();
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Popular(int currentlyLoaded, int amountToLoad);
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Anticipated();
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Anticipated(int currentlyLoaded, int amountToLoad);
|
||||
Task<IEnumerable<SearchTvShowViewModel>> MostWatches();
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Trending();
|
||||
Task<IEnumerable<SearchTvShowViewModel>> MostWatches(int currentlyLoaded, int amountToLoad);
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Trending(int currentlyLoaded, int amountToLoad);
|
||||
int ResultLimit { get; set; }
|
||||
}
|
||||
}
|
10
src/Ombi.Core/Engine/Interfaces/ITvSearchEngineV2.cs
Normal file
10
src/Ombi.Core/Engine/Interfaces/ITvSearchEngineV2.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
|
||||
namespace Ombi.Core
|
||||
{
|
||||
public interface ITVSearchEngineV2
|
||||
{
|
||||
Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using Ombi.Helpers;
|
|||
using Ombi.Store.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
|
@ -200,6 +201,54 @@ namespace Ombi.Core.Engine
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
IQueryable<MovieRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests =
|
||||
MovieRepository.GetWithUser(shouldHide
|
||||
.UserId);
|
||||
}
|
||||
else
|
||||
{
|
||||
allRequests =
|
||||
MovieRepository
|
||||
.GetWithUser();
|
||||
}
|
||||
|
||||
var prop = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(sortProperty, true);
|
||||
|
||||
if (sortProperty.Contains('.'))
|
||||
{
|
||||
// This is a navigation property currently not supported
|
||||
prop = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find("RequestedDate", true);
|
||||
//var properties = sortProperty.Split(new []{'.'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
//var firstProp = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(properties[0], true);
|
||||
//var propType = firstProp.PropertyType;
|
||||
//var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true);
|
||||
}
|
||||
|
||||
allRequests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
|
||||
? allRequests.OrderBy(x => prop.GetValue(x))
|
||||
: allRequests.OrderByDescending(x => prop.GetValue(x));
|
||||
var total = await allRequests.CountAsync();
|
||||
var requests = await allRequests.Skip(position).Take(count)
|
||||
.ToListAsync();
|
||||
requests.ForEach(async x =>
|
||||
{
|
||||
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
|
||||
await CheckForSubscription(shouldHide, x);
|
||||
});
|
||||
return new RequestsViewModel<MovieRequests>
|
||||
{
|
||||
Collection = requests,
|
||||
Total = total
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private IQueryable<MovieRequests> OrderMovies(IQueryable<MovieRequests> allRequests, OrderType type)
|
||||
{
|
||||
switch (type)
|
||||
|
@ -259,6 +308,15 @@ namespace Ombi.Core.Engine
|
|||
return allRequests;
|
||||
}
|
||||
|
||||
public async Task<MovieRequests> GetRequest(int requestId)
|
||||
{
|
||||
var request = await MovieRepository.GetWithUser().Where(x => x.Id == requestId).FirstOrDefaultAsync();
|
||||
request.PosterPath = PosterPathHelper.FixPosterPath(request.PosterPath);
|
||||
await CheckForSubscription(new HideResult(), request);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private async Task CheckForSubscription(HideResult shouldHide, MovieRequests x)
|
||||
{
|
||||
if (shouldHide.UserId == x.RequestedUserId)
|
||||
|
@ -493,7 +551,7 @@ namespace Ombi.Core.Engine
|
|||
RequestType = RequestType.Movie,
|
||||
});
|
||||
|
||||
return new RequestEngineResult {Result = true, Message = $"{movieName} has been successfully added!", RequestId = model.Id};
|
||||
return new RequestEngineResult { Result = true, Message = $"{movieName} has been successfully added!", RequestId = model.Id };
|
||||
}
|
||||
|
||||
public async Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user)
|
||||
|
@ -533,7 +591,7 @@ namespace Ombi.Core.Engine
|
|||
|
||||
return new RequestQuotaCountModel()
|
||||
{
|
||||
HasLimit = true,
|
||||
HasLimit = true,
|
||||
Limit = limit,
|
||||
Remaining = count,
|
||||
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
|
||||
|
|
|
@ -31,10 +31,11 @@ namespace Ombi.Core.Engine
|
|||
Logger = logger;
|
||||
}
|
||||
|
||||
private IMovieDbApi MovieApi { get; }
|
||||
private IMapper Mapper { get; }
|
||||
protected IMovieDbApi MovieApi { get; }
|
||||
protected IMapper Mapper { get; }
|
||||
private ILogger<MovieSearchEngine> Logger { get; }
|
||||
|
||||
protected const int MovieLimit = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Lookups the imdb information.
|
||||
|
@ -185,7 +186,7 @@ namespace Ombi.Core.Engine
|
|||
return null;
|
||||
}
|
||||
|
||||
private async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(
|
||||
protected async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(
|
||||
IEnumerable<MovieSearchResult> movies)
|
||||
{
|
||||
var viewMovies = new List<SearchMovieViewModel>();
|
||||
|
@ -196,7 +197,7 @@ namespace Ombi.Core.Engine
|
|||
return viewMovies;
|
||||
}
|
||||
|
||||
private async Task<SearchMovieViewModel> ProcessSingleMovie(SearchMovieViewModel viewMovie, bool lookupExtraInfo = false)
|
||||
protected async Task<SearchMovieViewModel> ProcessSingleMovie(SearchMovieViewModel viewMovie, bool lookupExtraInfo = false)
|
||||
{
|
||||
if (lookupExtraInfo && viewMovie.ImdbId.IsNullOrEmpty())
|
||||
{
|
||||
|
@ -214,7 +215,7 @@ namespace Ombi.Core.Engine
|
|||
|
||||
// This requires the rules to be run first to populate the RequestId property
|
||||
await CheckForSubscription(viewMovie);
|
||||
|
||||
|
||||
return viewMovie;
|
||||
}
|
||||
|
||||
|
@ -228,7 +229,7 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
var request = await RequestService.MovieRequestService.GetAll()
|
||||
.AnyAsync(x => x.RequestedUserId.Equals(user.Id) && x.TheMovieDbId == viewModel.Id);
|
||||
if (request)
|
||||
if (request || viewModel.Available)
|
||||
{
|
||||
viewModel.ShowSubscribe = false;
|
||||
}
|
||||
|
|
|
@ -69,6 +69,12 @@ namespace Ombi.Core.Engine
|
|||
};
|
||||
}
|
||||
|
||||
if(album?.artist == null)
|
||||
{
|
||||
// Lookup the artist
|
||||
//album.artist = await _lidarrApi.ArtistLookup(album.artist, s.ApiKey, s.FullUri);
|
||||
}
|
||||
|
||||
var userDetails = await GetUser();
|
||||
|
||||
var requestModel = new AlbumRequest
|
||||
|
@ -83,7 +89,7 @@ namespace Ombi.Core.Engine
|
|||
Title = album.title,
|
||||
Disk = album.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url,
|
||||
Cover = album.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url,
|
||||
ForeignArtistId = album?.artist?.foreignArtistId ?? string.Empty,
|
||||
ForeignArtistId = album?.artist?.foreignArtistId ?? string.Empty, // This needs to be populated to send to Lidarr for new requests
|
||||
RequestedByAlias = model.RequestedByAlias
|
||||
};
|
||||
if (requestModel.Cover.IsNullOrEmpty())
|
||||
|
|
|
@ -7,6 +7,7 @@ using Ombi.Core.Models.Search;
|
|||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
|
@ -31,14 +32,13 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user,
|
||||
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager,
|
||||
ITvSender sender, IAuditRepository audit, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache,
|
||||
ITvSender sender, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache,
|
||||
IRepository<RequestSubscription> sub) : base(user, requestService, rule, manager, cache, settings, sub)
|
||||
{
|
||||
TvApi = tvApi;
|
||||
MovieDbApi = movApi;
|
||||
NotificationHelper = helper;
|
||||
TvSender = sender;
|
||||
Audit = audit;
|
||||
_requestLog = rl;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,6 @@ namespace Ombi.Core.Engine
|
|||
private ITvMazeApi TvApi { get; }
|
||||
private IMovieDbApi MovieDbApi { get; }
|
||||
private ITvSender TvSender { get; }
|
||||
private IAuditRepository Audit { get; }
|
||||
private readonly IRepository<RequestLog> _requestLog;
|
||||
|
||||
public async Task<RequestEngineResult> RequestTvShow(TvRequestViewModel tv)
|
||||
|
@ -84,8 +83,6 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
}
|
||||
|
||||
await Audit.Record(AuditType.Added, AuditArea.TvRequest, $"Added Request {tvBuilder.ChildRequest.Title}", Username);
|
||||
|
||||
var existingRequest = await TvRepository.Get().FirstOrDefaultAsync(x => x.TvDbId == tv.TvDbId);
|
||||
if (existingRequest != null)
|
||||
{
|
||||
|
@ -160,7 +157,7 @@ namespace Ombi.Core.Engine
|
|||
.ThenInclude(x => x.Episodes)
|
||||
.OrderByDescending(x => x.ChildRequests.Select(y => y.RequestedDate).FirstOrDefault())
|
||||
.Skip(position).Take(count).ToListAsync();
|
||||
|
||||
|
||||
}
|
||||
|
||||
allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
||||
|
@ -225,6 +222,59 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
|
||||
|
||||
public async Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
List<ChildRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests = await TvRepository.GetChild(shouldHide.UserId).ToListAsync();
|
||||
|
||||
// Filter out children
|
||||
|
||||
FilterChildren(allRequests, shouldHide);
|
||||
}
|
||||
else
|
||||
{
|
||||
allRequests = await TvRepository.GetChild().ToListAsync();
|
||||
|
||||
}
|
||||
|
||||
if (allRequests == null)
|
||||
{
|
||||
return new RequestsViewModel<ChildRequests>();
|
||||
}
|
||||
|
||||
var total = allRequests.Count;
|
||||
|
||||
|
||||
var prop = TypeDescriptor.GetProperties(typeof(ChildRequests)).Find(sortProperty, true);
|
||||
|
||||
if (sortProperty.Contains('.'))
|
||||
{
|
||||
// This is a navigation property currently not supported
|
||||
prop = TypeDescriptor.GetProperties(typeof(ChildRequests)).Find("Title", true);
|
||||
//var properties = sortProperty.Split(new []{'.'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
//var firstProp = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(properties[0], true);
|
||||
//var propType = firstProp.PropertyType;
|
||||
//var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true);
|
||||
}
|
||||
allRequests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
|
||||
? allRequests.OrderBy(x => prop.GetValue(x)).ToList()
|
||||
: allRequests.OrderByDescending(x => prop.GetValue(x)).ToList();
|
||||
allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
|
||||
|
||||
// Make sure we do not show duplicate child requests
|
||||
allRequests = allRequests.DistinctBy(x => x.ParentRequest.Title).ToList();
|
||||
|
||||
return new RequestsViewModel<ChildRequests>
|
||||
{
|
||||
Collection = allRequests,
|
||||
Total = total,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<TvRequests>> GetRequestsLite()
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
|
@ -282,17 +332,22 @@ namespace Ombi.Core.Engine
|
|||
private static void FilterChildren(TvRequests t, HideResult shouldHide)
|
||||
{
|
||||
// Filter out children
|
||||
FilterChildren(t.ChildRequests, shouldHide);
|
||||
}
|
||||
|
||||
for (var j = 0; j < t.ChildRequests.Count; j++)
|
||||
private static void FilterChildren(List<ChildRequests> t, HideResult shouldHide)
|
||||
{
|
||||
// Filter out children
|
||||
|
||||
for (var j = 0; j < t.Count; j++)
|
||||
{
|
||||
var child = t.ChildRequests[j];
|
||||
var child = t[j];
|
||||
if (child.RequestedUserId != shouldHide.UserId)
|
||||
{
|
||||
t.ChildRequests.RemoveAt(j);
|
||||
t.RemoveAt(j);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId)
|
||||
|
@ -351,7 +406,6 @@ namespace Ombi.Core.Engine
|
|||
|
||||
public async Task<TvRequests> UpdateTvRequest(TvRequests request)
|
||||
{
|
||||
await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username);
|
||||
var allRequests = TvRepository.Get();
|
||||
var results = await allRequests.FirstOrDefaultAsync(x => x.Id == request.Id);
|
||||
|
||||
|
@ -385,6 +439,7 @@ namespace Ombi.Core.Engine
|
|||
foreach (var ep in s.Episodes)
|
||||
{
|
||||
ep.Approved = true;
|
||||
ep.Requested = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,7 +448,6 @@ namespace Ombi.Core.Engine
|
|||
if (request.Approved)
|
||||
{
|
||||
NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
||||
await Audit.Record(AuditType.Approved, AuditArea.TvRequest, $"Approved Request {request.Title}", Username);
|
||||
// Autosend
|
||||
await TvSender.Send(request);
|
||||
}
|
||||
|
@ -425,9 +479,7 @@ namespace Ombi.Core.Engine
|
|||
|
||||
public async Task<ChildRequests> UpdateChildRequest(ChildRequests request)
|
||||
{
|
||||
await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username);
|
||||
|
||||
await TvRepository.UpdateChild(request);
|
||||
await TvRepository.UpdateChild(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
@ -445,16 +497,14 @@ namespace Ombi.Core.Engine
|
|||
// Delete the parent
|
||||
TvRepository.Db.TvRequests.Remove(parent);
|
||||
}
|
||||
await Audit.Record(AuditType.Deleted, AuditArea.TvRequest, $"Deleting Request {request.Title}", Username);
|
||||
|
||||
|
||||
await TvRepository.Db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task RemoveTvRequest(int requestId)
|
||||
{
|
||||
var request = await TvRepository.Get().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||
await Audit.Record(AuditType.Deleted, AuditArea.TvRequest, $"Deleting Request {request.Title}", Username);
|
||||
await TvRepository.Delete(request);
|
||||
await TvRepository.Delete(request);
|
||||
}
|
||||
|
||||
public async Task<bool> UserHasRequest(string userId)
|
||||
|
@ -569,7 +619,7 @@ namespace Ombi.Core.Engine
|
|||
return await AfterRequest(model.ChildRequests.FirstOrDefault());
|
||||
}
|
||||
|
||||
private static List<ChildRequests> SortEpisodes(List<ChildRequests> items)
|
||||
private static List<ChildRequests> SortEpisodes(List<ChildRequests> items)
|
||||
{
|
||||
foreach (var value in items)
|
||||
{
|
||||
|
@ -606,7 +656,7 @@ namespace Ombi.Core.Engine
|
|||
var result = await TvSender.Send(model);
|
||||
if (result.Success)
|
||||
{
|
||||
return new RequestEngineResult { Result = true, RequestId = model.Id};
|
||||
return new RequestEngineResult { Result = true, RequestId = model.Id };
|
||||
}
|
||||
return new RequestEngineResult
|
||||
{
|
||||
|
@ -659,10 +709,10 @@ namespace Ombi.Core.Engine
|
|||
DateTime oldestRequestedAt = await log.OrderBy(x => x.RequestDate)
|
||||
.Select(x => x.RequestDate)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
|
||||
return new RequestQuotaCountModel()
|
||||
{
|
||||
HasLimit = true,
|
||||
HasLimit = true,
|
||||
Limit = limit,
|
||||
Remaining = count,
|
||||
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
|
||||
|
|
|
@ -21,6 +21,8 @@ using Ombi.Core.Authentication;
|
|||
using Ombi.Helpers;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using TraktApiSharp.Objects.Get.Shows;
|
||||
using TraktApiSharp.Objects.Get.Shows.Common;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
|
@ -40,8 +42,8 @@ namespace Ombi.Core.Engine
|
|||
EmbyContentRepo = embyRepo;
|
||||
}
|
||||
|
||||
private ITvMazeApi TvMazeApi { get; }
|
||||
private IMapper Mapper { get; }
|
||||
protected ITvMazeApi TvMazeApi { get; }
|
||||
protected IMapper Mapper { get; }
|
||||
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||
private IPlexContentRepository PlexContentRepo { get; }
|
||||
|
@ -99,7 +101,7 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
Url = e.url,
|
||||
Title = e.name,
|
||||
AirDate = DateTime.Parse(e.airstamp ?? DateTime.MinValue.ToString()),
|
||||
AirDate = e.airstamp.HasValue() ? DateTime.Parse(e.airstamp) : DateTime.MinValue,
|
||||
EpisodeNumber = e.number,
|
||||
|
||||
});
|
||||
|
@ -112,7 +114,7 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
Url = e.url,
|
||||
Title = e.name,
|
||||
AirDate = DateTime.Parse(e.airstamp ?? DateTime.MinValue.ToString()),
|
||||
AirDate = e.airstamp.HasValue() ? DateTime.Parse(e.airstamp) : DateTime.MinValue,
|
||||
EpisodeNumber = e.number,
|
||||
});
|
||||
}
|
||||
|
@ -127,6 +129,19 @@ namespace Ombi.Core.Engine
|
|||
return processed;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Popular(int currentlyLoaded, int amountToLoad)
|
||||
{
|
||||
var pages = PaginationHelper.GetNextPages(currentlyLoaded, amountToLoad, ResultLimit);
|
||||
var results = new List<TraktShow>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await TraktApi.GetPopularShows(pagesToLoad.Page, ResultLimit);
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
var processed = ProcessResults(results);
|
||||
return processed;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated()
|
||||
{
|
||||
|
||||
|
@ -135,6 +150,19 @@ namespace Ombi.Core.Engine
|
|||
return processed;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated(int currentlyLoaded, int amountToLoad)
|
||||
{
|
||||
var pages = PaginationHelper.GetNextPages(currentlyLoaded, amountToLoad, ResultLimit);
|
||||
var results = new List<TraktMostAnticipatedShow>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await TraktApi.GetAnticipatedShows(pagesToLoad.Page, ResultLimit);
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
var processed = ProcessResults(results);
|
||||
return processed;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(null, ResultLimit), DateTime.Now.AddHours(12));
|
||||
|
@ -149,7 +177,33 @@ namespace Ombi.Core.Engine
|
|||
return processed;
|
||||
}
|
||||
|
||||
private IEnumerable<SearchTvShowViewModel> ProcessResults<T>(IEnumerable<T> items)
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches(int currentlyLoaded, int amountToLoad)
|
||||
{
|
||||
var pages = PaginationHelper.GetNextPages(currentlyLoaded, amountToLoad, ResultLimit);
|
||||
var results = new List<TraktMostWatchedShow>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await TraktApi.GetMostWatchesShows(null, pagesToLoad.Page, ResultLimit);
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
var processed = ProcessResults(results);
|
||||
return processed;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Trending(int currentlyLoaded, int amountToLoad)
|
||||
{
|
||||
var pages = PaginationHelper.GetNextPages(currentlyLoaded, amountToLoad, ResultLimit);
|
||||
var results = new List<TraktTrendingShow>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await TraktApi.GetTrendingShows(pagesToLoad.Page, ResultLimit);
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
var processed = ProcessResults(results);
|
||||
return processed;
|
||||
}
|
||||
|
||||
protected IEnumerable<SearchTvShowViewModel> ProcessResults<T>(IEnumerable<T> items)
|
||||
{
|
||||
var retVal = new List<SearchTvShowViewModel>();
|
||||
foreach (var tvMazeSearch in items)
|
||||
|
@ -159,7 +213,7 @@ namespace Ombi.Core.Engine
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private SearchTvShowViewModel ProcessResult<T>(T tvMazeSearch)
|
||||
protected SearchTvShowViewModel ProcessResult<T>(T tvMazeSearch)
|
||||
{
|
||||
return Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
||||
}
|
||||
|
|
127
src/Ombi.Core/Engine/V2/CalendarEngine.cs
Normal file
127
src/Ombi.Core/Engine/V2/CalendarEngine.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Api.Sonarr.Models;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Engine.Interfaces;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Core.Engine.V2
|
||||
{
|
||||
public class CalendarEngine : BaseEngine, ICalendarEngine
|
||||
{
|
||||
public DateTime DaysAgo => DateTime.Now.AddDays(-90);
|
||||
public DateTime DaysAhead => DateTime.Now.AddDays(90);
|
||||
public CalendarEngine(IPrincipal user, OmbiUserManager um, IRuleEvaluator rules, IMovieRequestRepository movieRepo,
|
||||
ITvRequestRepository tvRequestRepo) : base(user, um, rules)
|
||||
{
|
||||
_movieRepo = movieRepo;
|
||||
_tvRepo = tvRequestRepo;
|
||||
}
|
||||
|
||||
private readonly IMovieRequestRepository _movieRepo;
|
||||
private readonly ITvRequestRepository _tvRepo;
|
||||
|
||||
public async Task<List<CalendarViewModel>> GetCalendarData()
|
||||
{
|
||||
var viewModel = new List<CalendarViewModel>();
|
||||
var movies = _movieRepo.GetAll().Where(x =>
|
||||
x.ReleaseDate > DaysAgo && x.ReleaseDate < DaysAhead);
|
||||
var episodes = _tvRepo.GetChild().SelectMany(x => x.SeasonRequests.SelectMany(e => e.Episodes
|
||||
.Where(w => w.AirDate > DaysAgo && w.AirDate < DaysAhead)));
|
||||
foreach (var e in episodes)
|
||||
{
|
||||
viewModel.Add(new CalendarViewModel
|
||||
{
|
||||
Title = e.Title,
|
||||
Start = e.AirDate.Date,
|
||||
Type = RequestType.TvShow,
|
||||
BackgroundColor = GetBackgroundColor(e),
|
||||
ExtraParams = new List<ExtraParams>
|
||||
{
|
||||
new ExtraParams { Overview = e.Season?.ChildRequest?.ParentRequest?.Overview ?? string.Empty, ProviderId = e.Season?.ChildRequest?.ParentRequest?.TvDbId ?? 0}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var m in movies)
|
||||
{
|
||||
viewModel.Add(new CalendarViewModel
|
||||
{
|
||||
Title = m.Title,
|
||||
Start = m.ReleaseDate.Date,
|
||||
BackgroundColor = GetBackgroundColor(m),
|
||||
Type = RequestType.Movie,
|
||||
ExtraParams = new List<ExtraParams>
|
||||
{
|
||||
new ExtraParams { Overview = m.Overview, ProviderId = m.TheMovieDbId}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
private string GetBackgroundColor(BaseRequest req)
|
||||
{
|
||||
if (req.Available)
|
||||
{
|
||||
return "#469c83";
|
||||
}
|
||||
|
||||
if (!req.Available)
|
||||
{
|
||||
if (req.Denied ?? false)
|
||||
{
|
||||
return "red";
|
||||
}
|
||||
if (req.Approved)
|
||||
{
|
||||
// We are approved state
|
||||
return "blue";
|
||||
}
|
||||
|
||||
if (!req.Approved)
|
||||
{
|
||||
// Processing
|
||||
return "teal";
|
||||
}
|
||||
}
|
||||
|
||||
return "gray";
|
||||
}
|
||||
|
||||
private string GetBackgroundColor(EpisodeRequests req)
|
||||
{
|
||||
if (req.Available)
|
||||
{
|
||||
return "#469c83";
|
||||
}
|
||||
|
||||
if (!req.Available)
|
||||
{
|
||||
if (req.Approved)
|
||||
{
|
||||
// We are approved state
|
||||
return "blue";
|
||||
}
|
||||
|
||||
if (!req.Approved)
|
||||
{
|
||||
// Processing
|
||||
return "teal";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return "gray";
|
||||
}
|
||||
}
|
||||
}
|
11
src/Ombi.Core/Engine/V2/ICalendarEngine.cs
Normal file
11
src/Ombi.Core/Engine/V2/ICalendarEngine.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using Ombi.Core.Models.Search.V2;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Core.Engine.V2
|
||||
{
|
||||
public interface ICalendarEngine
|
||||
{
|
||||
Task<List<CalendarViewModel>> GetCalendarData();
|
||||
}
|
||||
}
|
|
@ -4,8 +4,10 @@ using Microsoft.Extensions.Logging;
|
|||
using Ombi.Api.TheMovieDb;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Engine.Interfaces;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
|
@ -17,9 +19,8 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
namespace Ombi.Core.Engine.V2
|
||||
{
|
||||
public class MovieSearchEngineV2 : BaseMediaEngine, IMovieEngineV2
|
||||
{
|
||||
|
@ -45,6 +46,198 @@ namespace Ombi.Core.Engine
|
|||
return await ProcessSingleMovie(movieInfo);
|
||||
}
|
||||
|
||||
public async Task<MovieCollectionsViewModel> GetCollection(int collectionId, string langCode = null)
|
||||
{
|
||||
langCode = await DefaultLanguageCode(langCode);
|
||||
var collections = await MovieApi.GetCollection(langCode, collectionId);
|
||||
|
||||
var c = await ProcessCollection(collections);
|
||||
c.Collection = c.Collection.OrderBy(x => x.ReleaseDate).ToList();
|
||||
return c;
|
||||
}
|
||||
|
||||
public async Task<int> GetTvDbId(int theMovieDbId)
|
||||
{
|
||||
var result = await MovieApi.GetTvExternals(theMovieDbId);
|
||||
return result.tvdb_id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get similar movies to the id passed in
|
||||
/// </summary>
|
||||
/// <param name="theMovieDbId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> SimilarMovies(int theMovieDbId, string langCode)
|
||||
{
|
||||
langCode = await DefaultLanguageCode(langCode);
|
||||
var result = await MovieApi.SimilarMovies(theMovieDbId, langCode);
|
||||
if (result != null)
|
||||
{
|
||||
Logger.LogDebug("Search Result: {result}", result);
|
||||
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets popular movies.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
|
||||
{
|
||||
|
||||
var result = await Cache.GetOrAdd(CacheKeys.PopularMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.PopularMovies(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private const int _theMovieDbMaxPageItems = 20;
|
||||
|
||||
/// <summary>
|
||||
/// Gets popular movies by paging
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies(int currentlyLoaded, int toLoad)
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
|
||||
var pages = PaginationHelper.GetNextPages(currentlyLoaded, toLoad, _theMovieDbMaxPageItems);
|
||||
|
||||
var results = new List<MovieSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await MovieApi.PopularMovies(langCode, pagesToLoad.Page);
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
return await TransformMovieResultsToResponse(results);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets top rated movies.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.TopRatedMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.TopRated(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies(int currentPosition, int amountToLoad)
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
|
||||
var pages = PaginationHelper.GetNextPages(currentPosition, amountToLoad, _theMovieDbMaxPageItems);
|
||||
|
||||
var results = new List<MovieSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await MovieApi.TopRated(langCode, pagesToLoad.Page);
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
return await TransformMovieResultsToResponse(results);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies(int currentPosition, int amountToLoad)
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
|
||||
var pages = PaginationHelper.GetNextPages(currentPosition, amountToLoad, _theMovieDbMaxPageItems);
|
||||
|
||||
var results = new List<MovieSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await MovieApi.NowPlaying(langCode, pagesToLoad.Page);
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
return await TransformMovieResultsToResponse(results);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets upcoming movies.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.UpcomingMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.Upcoming(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
Logger.LogDebug("Search Result: {result}", result);
|
||||
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies(int currentPosition, int amountToLoad)
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
|
||||
var pages = PaginationHelper.GetNextPages(currentPosition, amountToLoad, _theMovieDbMaxPageItems);
|
||||
|
||||
var results = new List<MovieSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await MovieApi.Upcoming(langCode, pagesToLoad.Page);
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
return await TransformMovieResultsToResponse(results);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets now playing movies.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.NowPlayingMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.NowPlaying(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(
|
||||
IEnumerable<MovieSearchResult> movies)
|
||||
{
|
||||
var viewMovies = new List<SearchMovieViewModel>();
|
||||
foreach (var movie in movies)
|
||||
{
|
||||
viewMovies.Add(await ProcessSingleMovie(movie));
|
||||
}
|
||||
return viewMovies;
|
||||
}
|
||||
|
||||
private async Task<SearchMovieViewModel> ProcessSingleMovie(MovieSearchResult movie)
|
||||
{
|
||||
var viewMovie = Mapper.Map<SearchMovieViewModel>(movie);
|
||||
return await ProcessSingleMovie(viewMovie);
|
||||
}
|
||||
|
||||
private async Task<MovieFullInfoViewModel> ProcessSingleMovie(FullMovieInfo movie)
|
||||
{
|
||||
var viewMovie = Mapper.Map<SearchMovieViewModel>(movie);
|
||||
|
@ -65,6 +258,50 @@ namespace Ombi.Core.Engine
|
|||
return mapped;
|
||||
}
|
||||
|
||||
|
||||
private async Task<MovieCollectionsViewModel> ProcessCollection(Collections collection)
|
||||
{
|
||||
var viewMovie = Mapper.Map<MovieCollectionsViewModel>(collection);
|
||||
foreach (var movie in viewMovie.Collection)
|
||||
{
|
||||
var mappedMovie = Mapper.Map<SearchMovieViewModel>(movie);
|
||||
await RunSearchRules(mappedMovie);
|
||||
|
||||
// This requires the rules to be run first to populate the RequestId property
|
||||
await CheckForSubscription(mappedMovie);
|
||||
var mapped = Mapper.Map<MovieCollection>(movie);
|
||||
|
||||
mapped.Available = movie.Available;
|
||||
mapped.RequestId = movie.RequestId;
|
||||
mapped.Requested = movie.Requested;
|
||||
mapped.PlexUrl = movie.PlexUrl;
|
||||
mapped.EmbyUrl = movie.EmbyUrl;
|
||||
mapped.Subscribed = movie.Subscribed;
|
||||
mapped.ShowSubscribe = movie.ShowSubscribe;
|
||||
mapped.ReleaseDate = movie.ReleaseDate;
|
||||
}
|
||||
return viewMovie;
|
||||
}
|
||||
|
||||
private async Task<SearchMovieViewModel> ProcessSingleMovie(SearchMovieViewModel viewMovie)
|
||||
{
|
||||
if (viewMovie.ImdbId.IsNullOrEmpty())
|
||||
{
|
||||
var showInfo = await MovieApi.GetMovieInformation(viewMovie.Id);
|
||||
viewMovie.Id = showInfo.Id; // TheMovieDbId
|
||||
viewMovie.ImdbId = showInfo.ImdbId;
|
||||
}
|
||||
|
||||
viewMovie.TheMovieDbId = viewMovie.Id.ToString();
|
||||
|
||||
await RunSearchRules(viewMovie);
|
||||
|
||||
// This requires the rules to be run first to populate the RequestId property
|
||||
await CheckForSubscription(viewMovie);
|
||||
|
||||
return viewMovie;
|
||||
}
|
||||
|
||||
private async Task CheckForSubscription(SearchViewModel viewModel)
|
||||
{
|
||||
// Check if this user requested it
|
||||
|
|
154
src/Ombi.Core/Engine/V2/TvSearchEngineV2.cs
Normal file
154
src/Ombi.Core/Engine/V2/TvSearchEngineV2.cs
Normal file
|
@ -0,0 +1,154 @@
|
|||
using AutoMapper;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using TraktApiSharp.Objects.Get.Shows;
|
||||
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Api.Trakt;
|
||||
using Ombi.Api.TvMaze;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Core.Engine.V2
|
||||
{
|
||||
public class TvSearchEngineV2 : BaseMediaEngine, ITVSearchEngineV2
|
||||
{
|
||||
public TvSearchEngineV2(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings,
|
||||
ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo, IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um,
|
||||
ICacheService memCache, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub)
|
||||
: base(identity, service, r, um, memCache, s, sub)
|
||||
{
|
||||
TvMazeApi = tvMaze;
|
||||
Mapper = mapper;
|
||||
PlexSettings = plexSettings;
|
||||
EmbySettings = embySettings;
|
||||
PlexContentRepo = repo;
|
||||
TraktApi = trakt;
|
||||
EmbyContentRepo = embyRepo;
|
||||
}
|
||||
|
||||
private ITvMazeApi TvMazeApi { get; }
|
||||
private IMapper Mapper { get; }
|
||||
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||
private IPlexContentRepository PlexContentRepo { get; }
|
||||
private IEmbyContentRepository EmbyContentRepo { get; }
|
||||
private ITraktApi TraktApi { get; }
|
||||
|
||||
|
||||
public async Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid)
|
||||
{
|
||||
var tvdbshow = await TvMazeApi.ShowLookupByTheTvDbId(tvdbid);
|
||||
var show = await TvMazeApi.GetTvFullInformation(tvdbshow.id);
|
||||
if (show == null)
|
||||
{
|
||||
// We don't have enough information
|
||||
return null;
|
||||
}
|
||||
|
||||
// Setup the task so we can get the data later on if we have a IMDBID
|
||||
Task<TraktShow> traktInfoTask = new Task<TraktShow>(() => null);
|
||||
if (show.externals?.imdb.HasValue() ?? false)
|
||||
{
|
||||
traktInfoTask = TraktApi.GetTvExtendedInfo(show.externals?.imdb);
|
||||
}
|
||||
|
||||
var mapped = Mapper.Map<SearchFullInfoTvShowViewModel>(show);
|
||||
|
||||
foreach (var e in show._embedded.episodes)
|
||||
{
|
||||
var season = mapped.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == e.season);
|
||||
if (season == null)
|
||||
{
|
||||
var newSeason = new SeasonRequests
|
||||
{
|
||||
SeasonNumber = e.season,
|
||||
Episodes = new List<EpisodeRequests>()
|
||||
};
|
||||
newSeason.Episodes.Add(new EpisodeRequests
|
||||
{
|
||||
Url = e.url,
|
||||
Title = e.name,
|
||||
AirDate = e.airstamp,
|
||||
EpisodeNumber = e.number,
|
||||
|
||||
});
|
||||
mapped.SeasonRequests.Add(newSeason);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We already have the season, so just add the episode
|
||||
season.Episodes.Add(new EpisodeRequests
|
||||
{
|
||||
Url = e.url,
|
||||
Title = e.name,
|
||||
AirDate = e.airstamp,
|
||||
EpisodeNumber = e.number,
|
||||
});
|
||||
}
|
||||
}
|
||||
return await ProcessResult(mapped, traktInfoTask);
|
||||
}
|
||||
|
||||
private IEnumerable<SearchTvShowViewModel> ProcessResults<T>(IEnumerable<T> items)
|
||||
{
|
||||
var retVal = new List<SearchTvShowViewModel>();
|
||||
foreach (var tvMazeSearch in items)
|
||||
{
|
||||
retVal.Add(ProcessResult(tvMazeSearch));
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private SearchTvShowViewModel ProcessResult<T>(T tvMazeSearch)
|
||||
{
|
||||
return Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
||||
}
|
||||
|
||||
private async Task<SearchFullInfoTvShowViewModel> ProcessResult(SearchFullInfoTvShowViewModel item, Task<TraktShow> showInfoTask)
|
||||
{
|
||||
item.TheTvDbId = item.Id.ToString();
|
||||
|
||||
var oldModel = Mapper.Map<SearchTvShowViewModel>(item);
|
||||
await RunSearchRules(oldModel);
|
||||
|
||||
item.Available = oldModel.Available;
|
||||
item.FullyAvailable = oldModel.FullyAvailable;
|
||||
item.PartlyAvailable = oldModel.PartlyAvailable;
|
||||
item.Requested = oldModel.Requested;
|
||||
item.Available = oldModel.Available;
|
||||
item.Approved = oldModel.Approved;
|
||||
item.SeasonRequests = oldModel.SeasonRequests;
|
||||
item.RequestId = oldModel.RequestId;
|
||||
|
||||
return await GetExtraInfo(showInfoTask, item);
|
||||
}
|
||||
|
||||
private async Task<SearchFullInfoTvShowViewModel> GetExtraInfo(Task<TraktShow> showInfoTask, SearchFullInfoTvShowViewModel model)
|
||||
{
|
||||
var result = await showInfoTask;
|
||||
if(result == null)
|
||||
{
|
||||
return model;
|
||||
}
|
||||
|
||||
model.Trailer = result.Trailer;
|
||||
model.Certification = result.Certification;
|
||||
model.Homepage = result.Homepage;
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
}
|
39
src/Ombi.Core/Models/Search/V2/CalendarViewModel.cs
Normal file
39
src/Ombi.Core/Models/Search/V2/CalendarViewModel.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Core.Models.Search.V2
|
||||
{
|
||||
public class CalendarViewModel
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public DateTime Start { get; set; }
|
||||
public string BackgroundColor { get; set; }
|
||||
public RequestType Type { get; set; }
|
||||
public List<ExtraParams> ExtraParams { get; set; }
|
||||
|
||||
public string BorderColor
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case RequestType.TvShow:
|
||||
return "#ff0000";
|
||||
case RequestType.Movie:
|
||||
return "#0d5a3e";
|
||||
case RequestType.Album:
|
||||
return "#797979";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ExtraParams
|
||||
{
|
||||
public int ProviderId { get; set; }
|
||||
public string Overview { get; set; }
|
||||
}
|
||||
}
|
25
src/Ombi.Core/Models/Search/V2/MovieCollectionsViewModel.cs
Normal file
25
src/Ombi.Core/Models/Search/V2/MovieCollectionsViewModel.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Core.Models.Search.V2
|
||||
{
|
||||
public class MovieCollectionsViewModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public List<MovieCollection> Collection { get; set; }
|
||||
}
|
||||
|
||||
public class MovieCollection : SearchViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public string PosterPath { get; set; }
|
||||
public string Title { get; set; }
|
||||
public DateTime ReleaseDate { get; set; }
|
||||
|
||||
|
||||
public override RequestType Type => RequestType.Movie;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ namespace Ombi.Core.Models.Search.V2
|
|||
public class MovieFullInfoViewModel : SearchViewModel
|
||||
{
|
||||
public bool Adult { get; set; }
|
||||
public CollectionsViewModel BelongsToCollection { get; set; }
|
||||
public string BackdropPath { get; set; }
|
||||
public string OriginalLanguage { get; set; }
|
||||
public int Budget { get; set; }
|
||||
|
@ -39,8 +40,26 @@ namespace Ombi.Core.Models.Search.V2
|
|||
public Similar Similar { get; set; }
|
||||
public Recommendations Recommendations { get; set; }
|
||||
public ExternalIds ExternalIds { get; set; }
|
||||
public Keywords Keywords { get; set; }
|
||||
}
|
||||
public class Keywords
|
||||
{
|
||||
public List<KeywordsValue> KeywordsValue { get; set; }
|
||||
}
|
||||
|
||||
public class KeywordsValue
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class CollectionsViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string PosterPath { get; set; }
|
||||
public string BackdropPath { get; set; }
|
||||
}
|
||||
public class ExternalIds
|
||||
{
|
||||
public string ImdbId { get; set; }
|
||||
|
|
114
src/Ombi.Core/Models/Search/V2/SearchFullInfoTvShowViewModel.cs
Normal file
114
src/Ombi.Core/Models/Search/V2/SearchFullInfoTvShowViewModel.cs
Normal file
|
@ -0,0 +1,114 @@
|
|||
using Ombi.Store.Repository.Requests;
|
||||
using System.Collections.Generic;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Core.Models.Search.V2
|
||||
{
|
||||
public class SearchFullInfoTvShowViewModel : SearchViewModel
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public List<string> Aliases { get; set; }
|
||||
public string Banner { get; set; }
|
||||
public int SeriesId { get; set; }
|
||||
public string Status { get; set; }
|
||||
public string FirstAired { get; set; }
|
||||
public string NetworkId { get; set; }
|
||||
public string Runtime { get; set; }
|
||||
public List<string> Genre { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public int LastUpdated { get; set; }
|
||||
public string AirsDayOfWeek { get; set; }
|
||||
public string AirsTime { get; set; }
|
||||
public string Rating { get; set; }
|
||||
public int SiteRating { get; set; }
|
||||
public NetworkViewModel Network { get; set; }
|
||||
public Images Images { get; set; }
|
||||
public List<CastViewModel> Cast { get; set; }
|
||||
public List<CrewViewModel> Crew { get; set; }
|
||||
public string Certification { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is used from the Trakt API
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The trailer.
|
||||
/// </value>
|
||||
public string Trailer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is used from the Trakt API
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The trailer.
|
||||
/// </value>
|
||||
public string Homepage { get; set; }
|
||||
|
||||
public List<SeasonRequests> SeasonRequests { get; set; } = new List<SeasonRequests>();
|
||||
|
||||
/// <summary>
|
||||
/// If we are requesting the entire series
|
||||
/// </summary>
|
||||
public bool RequestAll { get; set; }
|
||||
|
||||
public bool FirstSeason { get; set; }
|
||||
public bool LatestSeason { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is where we have EVERY Episode for that series
|
||||
/// </summary>
|
||||
public bool FullyAvailable { get; set; }
|
||||
// We only have some episodes
|
||||
public bool PartlyAvailable { get; set; }
|
||||
public override RequestType Type => RequestType.TvShow;
|
||||
}
|
||||
|
||||
public class NetworkViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public Country Country { get; set; }
|
||||
}
|
||||
|
||||
public class Country
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Code { get; set; }
|
||||
public string Timezone { get; set; }
|
||||
}
|
||||
|
||||
public class Images
|
||||
{
|
||||
public string Medium { get; set; }
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class CastViewModel
|
||||
{
|
||||
public PersonViewModel Person { get; set; }
|
||||
public CharacterViewModel Character { get; set; }
|
||||
public bool Self { get; set; }
|
||||
public bool Voice { get; set; }
|
||||
}
|
||||
|
||||
public class PersonViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string Name { get; set; }
|
||||
public Images Image { get; set; }
|
||||
}
|
||||
|
||||
public class CharacterViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string Name { get; set; }
|
||||
public Images Image { get; set; }
|
||||
}
|
||||
|
||||
public class CrewViewModel
|
||||
{
|
||||
public string Type { get; set; }
|
||||
public PersonViewModel Person { get; set; }
|
||||
}
|
||||
}
|
23
src/Ombi.Core/Models/UI/GotifyNotificationViewModel.cs
Normal file
23
src/Ombi.Core/Models/UI/GotifyNotificationViewModel.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using Ombi.Settings.Settings.Models.Notifications;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.Core.Models.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// The view model for the notification settings page
|
||||
/// </summary>
|
||||
/// <seealso cref="GotifyNotificationSettings" />
|
||||
public class GotifyNotificationViewModel : GotifySettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the notification templates.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The notification templates.
|
||||
/// </value>
|
||||
public List<NotificationTemplates> NotificationTemplates { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -11,10 +11,9 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="6.1.1" />
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="3.2.0" />
|
||||
<PackageReference Include="Hangfire" Version="1.6.21" />
|
||||
<PackageReference Include="Hangfire" Version="1.7.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
|
||||
<PackageReference Include="MiniProfiler.AspNetCore" Version="4.0.0-alpha6-79" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Helpers;
|
||||
|
@ -10,28 +12,31 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
{
|
||||
public class AutoApproveRule : BaseRequestRule, IRules<BaseRequest>
|
||||
{
|
||||
public AutoApproveRule(IPrincipal principal)
|
||||
public AutoApproveRule(IPrincipal principal, OmbiUserManager um)
|
||||
{
|
||||
User = principal;
|
||||
_manager = um;
|
||||
}
|
||||
|
||||
private IPrincipal User { get; }
|
||||
private readonly OmbiUserManager _manager;
|
||||
|
||||
public Task<RuleResult> Execute(BaseRequest obj)
|
||||
public async Task<RuleResult> Execute(BaseRequest obj)
|
||||
{
|
||||
if (User.IsInRole(OmbiRoles.Admin))
|
||||
var user = await _manager.Users.FirstOrDefaultAsync(x => x.UserName == User.Identity.Name);
|
||||
if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin))
|
||||
{
|
||||
obj.Approved = true;
|
||||
return Task.FromResult(Success());
|
||||
return Success();
|
||||
}
|
||||
|
||||
if (obj.RequestType == RequestType.Movie && User.IsInRole(OmbiRoles.AutoApproveMovie))
|
||||
if (obj.RequestType == RequestType.Movie && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie))
|
||||
obj.Approved = true;
|
||||
if (obj.RequestType == RequestType.TvShow && User.IsInRole(OmbiRoles.AutoApproveTv))
|
||||
if (obj.RequestType == RequestType.TvShow && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveTv))
|
||||
obj.Approved = true;
|
||||
if (obj.RequestType == RequestType.Album && User.IsInRole(OmbiRoles.AutoApproveMusic))
|
||||
if (obj.RequestType == RequestType.Album && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMusic))
|
||||
obj.Approved = true;
|
||||
return Task.FromResult(Success()); // We don't really care, we just don't set the obj to approve
|
||||
return Success(); // We don't really care, we just don't set the obj to approve
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +1,52 @@
|
|||
using Ombi.Store.Entities;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
|
||||
namespace Ombi.Core.Rule.Rules
|
||||
namespace Ombi.Core.Rule.Rules.Request
|
||||
{
|
||||
public class CanRequestRule : BaseRequestRule, IRules<BaseRequest>
|
||||
{
|
||||
public CanRequestRule(IPrincipal principal)
|
||||
public CanRequestRule(IPrincipal principal, OmbiUserManager manager)
|
||||
{
|
||||
User = principal;
|
||||
_manager = manager;
|
||||
}
|
||||
|
||||
private IPrincipal User { get; }
|
||||
private readonly OmbiUserManager _manager;
|
||||
|
||||
public Task<RuleResult> Execute(BaseRequest obj)
|
||||
public async Task<RuleResult> Execute(BaseRequest obj)
|
||||
{
|
||||
if (User.IsInRole(OmbiRoles.Admin))
|
||||
return Task.FromResult(Success());
|
||||
var user = await _manager.Users.FirstOrDefaultAsync(x => x.UserName == User.Identity.Name);
|
||||
if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin))
|
||||
return Success();
|
||||
|
||||
if (obj.RequestType == RequestType.Movie)
|
||||
{
|
||||
if (User.IsInRole(OmbiRoles.RequestMovie) || User.IsInRole(OmbiRoles.AutoApproveMovie))
|
||||
return Task.FromResult(Success());
|
||||
return Task.FromResult(Fail("You do not have permissions to Request a Movie"));
|
||||
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMovie) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie))
|
||||
return Success();
|
||||
return Fail("You do not have permissions to Request a Movie");
|
||||
}
|
||||
|
||||
if (obj.RequestType == RequestType.TvShow)
|
||||
{
|
||||
if (User.IsInRole(OmbiRoles.RequestTv) || User.IsInRole(OmbiRoles.AutoApproveTv))
|
||||
return Task.FromResult(Success());
|
||||
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestTv) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveTv))
|
||||
return Success();
|
||||
}
|
||||
|
||||
if (obj.RequestType == RequestType.Album)
|
||||
{
|
||||
if (User.IsInRole(OmbiRoles.RequestMusic) || User.IsInRole(OmbiRoles.AutoApproveMusic))
|
||||
return Task.FromResult(Success());
|
||||
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMusic) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMusic))
|
||||
return Success();
|
||||
}
|
||||
|
||||
return Task.FromResult(Fail("You do not have permissions to Request a TV Show"));
|
||||
return Fail("You do not have permissions to Request a TV Show");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
|
@ -28,8 +30,24 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
{
|
||||
var movie = (MovieRequests) obj;
|
||||
var movieRequests = Movie.GetAll();
|
||||
var found = false;
|
||||
var existing = await movieRequests.FirstOrDefaultAsync(x => x.TheMovieDbId == movie.TheMovieDbId);
|
||||
if (existing != null) // Do we already have a request for this?
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (!found && movie.ImdbId.HasValue())
|
||||
{
|
||||
// Let's check imdbid
|
||||
existing = await movieRequests.FirstOrDefaultAsync(x =>
|
||||
x.ImdbId.Equals(movie.ImdbId, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (existing != null)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(found)
|
||||
{
|
||||
return Fail($"\"{obj.Title}\" has already been requested");
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
|
||||
var tvContent = _plexContent.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Show);
|
||||
// We need to do a check on the TVDBId
|
||||
var anyTvDbMatches = await tvContent.Include(x => x.Episodes).FirstOrDefaultAsync(x => x.HasTvDb && x.TvDbId.Equals(tvRequest.Id.ToString())); // the Id on the child is the tvdbid at this point
|
||||
var anyTvDbMatches = await tvContent.Include(x => x.Episodes).FirstOrDefaultAsync(x => x.HasTvDb && x.TvDbId.Equals(tvRequest.Id.ToString(), StringComparison.InvariantCultureIgnoreCase)); // the Id on the child is the tvdbid at this point
|
||||
if (anyTvDbMatches == null)
|
||||
{
|
||||
// So we do not have a TVDB Id, that really sucks.
|
||||
|
@ -42,7 +42,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
&& x.ReleaseYear == tvRequest.ReleaseYear.Year.ToString());
|
||||
if (titleAndYearMatch != null)
|
||||
{
|
||||
// We have a match! Suprise Motherfucker
|
||||
// We have a match! Surprise Motherfucker
|
||||
return CheckExistingContent(tvRequest, titleAndYearMatch);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
@ -13,6 +13,18 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
{
|
||||
public static void CheckForUnairedEpisodes(SearchTvShowViewModel search)
|
||||
{
|
||||
foreach (var season in search.SeasonRequests)
|
||||
{
|
||||
// If we have all the episodes for this season, then this season is available
|
||||
if (season.Episodes.All(x => x.Available))
|
||||
{
|
||||
season.SeasonAvailable = true;
|
||||
}
|
||||
}
|
||||
if(search.SeasonRequests.Any(x => x.Episodes.Any(e => e.Available)))
|
||||
{
|
||||
search.PartlyAvailable = true;
|
||||
}
|
||||
if (search.SeasonRequests.All(x => x.Episodes.All(e => e.Available)))
|
||||
{
|
||||
search.FullyAvailable = true;
|
||||
|
@ -24,7 +36,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
if (!airedButNotAvailable)
|
||||
{
|
||||
var unairedEpisodes = search.SeasonRequests.Any(x =>
|
||||
x.Episodes.Any(c => !c.Available && c.AirDate > DateTime.Now.Date));
|
||||
x.Episodes.Any(c => !c.Available && c.AirDate > DateTime.Now.Date || c.AirDate != DateTime.MinValue));
|
||||
if (unairedEpisodes)
|
||||
{
|
||||
search.FullyAvailable = true;
|
||||
|
@ -34,28 +46,36 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
}
|
||||
|
||||
public static async Task SingleEpisodeCheck(bool useImdb, IQueryable<PlexEpisode> allEpisodes, EpisodeRequests episode,
|
||||
SeasonRequests season, PlexServerContent item, bool useTheMovieDb, bool useTvDb)
|
||||
SeasonRequests season, PlexServerContent item, bool useTheMovieDb, bool useTvDb, ILogger log)
|
||||
{
|
||||
PlexEpisode epExists = null;
|
||||
if (useImdb)
|
||||
try
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||
x.Series.ImdbId == item.ImdbId.ToString());
|
||||
}
|
||||
|
||||
if (useTheMovieDb)
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||
x.Series.TheMovieDbId == item.TheMovieDbId.ToString());
|
||||
}
|
||||
if (useImdb)
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||
x.Series.ImdbId == item.ImdbId);
|
||||
}
|
||||
|
||||
if (useTvDb)
|
||||
if (useTheMovieDb)
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||
x.Series.TheMovieDbId == item.TheMovieDbId);
|
||||
}
|
||||
|
||||
if (useTvDb)
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||
x.Series.TvDbId == item.TvDbId);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||
x.Series.TvDbId == item.TvDbId.ToString());
|
||||
log.LogError(e, "Exception thrown when attempting to check if something is available");
|
||||
}
|
||||
|
||||
if (epExists != null)
|
||||
|
@ -71,21 +91,21 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||
x.Series.ImdbId == item.ImdbId.ToString());
|
||||
x.Series.ImdbId == item.ImdbId);
|
||||
}
|
||||
|
||||
if (useTheMovieDb)
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||
x.Series.TheMovieDbId == item.TheMovieDbId.ToString());
|
||||
x.Series.TheMovieDbId == item.TheMovieDbId);
|
||||
}
|
||||
|
||||
if (useTvDb)
|
||||
{
|
||||
epExists = await allEpisodes.FirstOrDefaultAsync(x =>
|
||||
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber &&
|
||||
x.Series.TvDbId == item.TvDbId.ToString());
|
||||
x.Series.TvDbId == item.TvDbId);
|
||||
}
|
||||
|
||||
if (epExists != null)
|
||||
|
|
|
@ -3,6 +3,8 @@ using System.Threading.Tasks;
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
|
@ -11,12 +13,14 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
{
|
||||
public class EmbyAvailabilityRule : BaseSearchRule, IRules<SearchViewModel>
|
||||
{
|
||||
public EmbyAvailabilityRule(IEmbyContentRepository repo)
|
||||
public EmbyAvailabilityRule(IEmbyContentRepository repo, ISettingsService<EmbySettings> s)
|
||||
{
|
||||
EmbyContentRepository = repo;
|
||||
EmbySettings = s;
|
||||
}
|
||||
|
||||
private IEmbyContentRepository EmbyContentRepository { get; }
|
||||
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||
|
||||
public async Task<RuleResult> Execute(SearchViewModel obj)
|
||||
{
|
||||
|
@ -60,7 +64,19 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
if (item != null)
|
||||
{
|
||||
obj.Available = true;
|
||||
obj.EmbyUrl = item.Url;
|
||||
var s = await EmbySettings.GetSettingsAsync();
|
||||
if (s.Enable)
|
||||
{
|
||||
var server = s.Servers.FirstOrDefault(x => x.ServerHostname != null);
|
||||
if ((server?.ServerHostname ?? string.Empty).HasValue())
|
||||
{
|
||||
obj.EmbyUrl = $"{server.ServerHostname}#!/itemdetails.html?id={item.EmbyId}";
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.EmbyUrl = $"https://app.emby.media/#!/itemdetails.html?id={item.EmbyId}";
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.Type == RequestType.TvShow)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Models.Search;
|
||||
|
@ -29,7 +30,6 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
var movieRequests = await Movie.GetRequestAsync(obj.Id);
|
||||
if (movieRequests != null) // Do we already have a request for this?
|
||||
{
|
||||
|
||||
obj.Requested = true;
|
||||
obj.RequestId = movieRequests.Id;
|
||||
obj.Approved = movieRequests.Approved;
|
||||
|
@ -41,22 +41,11 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
}
|
||||
if (obj.Type == RequestType.TvShow)
|
||||
{
|
||||
//var tvRequests = Tv.GetRequest(obj.Id);
|
||||
//if (tvRequests != null) // Do we already have a request for this?
|
||||
//{
|
||||
|
||||
// obj.Requested = true;
|
||||
// obj.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
|
||||
// obj.Available = tvRequests.ChildRequests.Any(x => x.Available);
|
||||
|
||||
// return Task.FromResult(Success());
|
||||
//}
|
||||
|
||||
var request = (SearchTvShowViewModel)obj;
|
||||
var tvRequests = Tv.GetRequest(obj.Id);
|
||||
if (tvRequests != null) // Do we already have a request for this?
|
||||
{
|
||||
|
||||
request.RequestId = tvRequests.Id;
|
||||
request.Requested = true;
|
||||
request.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
|
||||
|
||||
|
@ -87,11 +76,11 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
}
|
||||
}
|
||||
|
||||
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.All(e => e.Available)))
|
||||
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.All(e => e.Available && e.AirDate > DateTime.MinValue)))
|
||||
{
|
||||
request.FullyAvailable = true;
|
||||
}
|
||||
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.Any(e => e.Available)))
|
||||
if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.Any(e => e.Available && e.AirDate > DateTime.MinValue)))
|
||||
{
|
||||
request.PartlyAvailable = true;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
using Ombi.Helpers;
|
||||
|
@ -10,12 +11,14 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
{
|
||||
public class PlexAvailabilityRule : BaseSearchRule, IRules<SearchViewModel>
|
||||
{
|
||||
public PlexAvailabilityRule(IPlexContentRepository repo)
|
||||
public PlexAvailabilityRule(IPlexContentRepository repo, ILogger<PlexAvailabilityRule> log)
|
||||
{
|
||||
PlexContentRepository = repo;
|
||||
Log = log;
|
||||
}
|
||||
|
||||
private IPlexContentRepository PlexContentRepository { get; }
|
||||
private ILogger Log { get; }
|
||||
|
||||
public async Task<RuleResult> Execute(SearchViewModel obj)
|
||||
{
|
||||
|
@ -72,7 +75,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
{
|
||||
foreach (var episode in season.Episodes)
|
||||
{
|
||||
await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb);
|
||||
await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb, Log);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@ namespace Ombi.Core.Senders
|
|||
{
|
||||
try
|
||||
{
|
||||
|
||||
var cpSettings = await CouchPotatoSettings.GetSettingsAsync();
|
||||
//var watcherSettings = await WatcherSettings.GetSettingsAsync();
|
||||
var radarrSettings = await RadarrSettings.GetSettingsAsync();
|
||||
|
@ -76,7 +75,7 @@ namespace Ombi.Core.Senders
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.LogError(e, "Error when seing movie to DVR app, added to the request queue");
|
||||
Log.LogError(e, "Error when sending movie to DVR app, added to the request queue");
|
||||
|
||||
// Check if already in request quee
|
||||
var existingQueue = await _requestQueuRepository.FirstOrDefaultAsync(x => x.RequestId == model.Id);
|
||||
|
|
|
@ -16,6 +16,7 @@ using Ombi.Settings.Settings.Models.External;
|
|||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Remotion.Linq.Parsing.Structure.IntermediateModel;
|
||||
|
||||
namespace Ombi.Core.Senders
|
||||
{
|
||||
|
@ -57,7 +58,7 @@ namespace Ombi.Core.Senders
|
|||
var sonarr = await SonarrSettings.GetSettingsAsync();
|
||||
if (sonarr.Enabled)
|
||||
{
|
||||
var result = await SendToSonarr(model);
|
||||
var result = await SendToSonarr(model, sonarr);
|
||||
if (result != null)
|
||||
{
|
||||
return new SenderResult
|
||||
|
@ -109,7 +110,7 @@ namespace Ombi.Core.Senders
|
|||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e, "Exception thrown when sending a movie to DVR app, added to the request queue");
|
||||
// Check if already in request quee
|
||||
// Check if already in request queue
|
||||
var existingQueue = await _requestQueueRepository.FirstOrDefaultAsync(x => x.RequestId == model.Id);
|
||||
if (existingQueue != null)
|
||||
{
|
||||
|
@ -134,7 +135,7 @@ namespace Ombi.Core.Senders
|
|||
return new SenderResult
|
||||
{
|
||||
Success = false,
|
||||
Message = "Something wen't wrong!"
|
||||
Message = "Something went wrong!"
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -150,13 +151,8 @@ namespace Ombi.Core.Senders
|
|||
/// <param name="s"></param>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<NewSeries> SendToSonarr(ChildRequests model)
|
||||
public async Task<NewSeries> SendToSonarr(ChildRequests model, SonarrSettings s)
|
||||
{
|
||||
var s = await SonarrSettings.GetSettingsAsync();
|
||||
if (!s.Enabled)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (string.IsNullOrEmpty(s.ApiKey))
|
||||
{
|
||||
return null;
|
||||
|
@ -319,10 +315,19 @@ namespace Ombi.Core.Senders
|
|||
|
||||
foreach (var season in model.SeasonRequests)
|
||||
{
|
||||
var sonarrSeason = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber);
|
||||
var sonarrEpCount = sonarrSeason.Count();
|
||||
var sonarrEpisodeList = sonarrEpList.Where(x => x.seasonNumber == season.SeasonNumber).ToList();
|
||||
var sonarrEpCount = sonarrEpisodeList.Count;
|
||||
var ourRequestCount = season.Episodes.Count;
|
||||
|
||||
var ourEpisodes = season.Episodes.Select(x => x.EpisodeNumber).ToList();
|
||||
var unairedEpisodes = sonarrEpisodeList.Where(x => x.airDateUtc > DateTime.UtcNow).Select(x => x.episodeNumber).ToList();
|
||||
|
||||
//// Check if we have requested all the latest episodes, if we have then monitor
|
||||
//// NOTE, not sure if needed since ombi ui displays future episodes anyway...
|
||||
//ourEpisodes.AddRange(unairedEpisodes);
|
||||
//var distinctEpisodes = ourEpisodes.Distinct().ToList();
|
||||
//var missingEpisodes = Enumerable.Range(distinctEpisodes.Min(), distinctEpisodes.Count).Except(distinctEpisodes);
|
||||
|
||||
var existingSeason =
|
||||
result.seasons.FirstOrDefault(x => x.seasonNumber == season.SeasonNumber);
|
||||
if (existingSeason == null)
|
||||
|
@ -332,7 +337,7 @@ namespace Ombi.Core.Senders
|
|||
}
|
||||
|
||||
|
||||
if (sonarrEpCount == ourRequestCount)
|
||||
if (sonarrEpCount == ourRequestCount /*|| !missingEpisodes.Any()*/)
|
||||
{
|
||||
// We have the same amount of requests as all of the episodes in the season.
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ using Ombi.Api.CouchPotato;
|
|||
using Ombi.Api.DogNzb;
|
||||
using Ombi.Api.FanartTv;
|
||||
using Ombi.Api.Github;
|
||||
using Ombi.Api.Gotify;
|
||||
using Ombi.Api.Lidarr;
|
||||
using Ombi.Api.Mattermost;
|
||||
using Ombi.Api.Notifications;
|
||||
|
@ -51,16 +52,15 @@ using Ombi.Schedule.Jobs.Plex;
|
|||
using Ombi.Schedule.Jobs.Sonarr;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using Ombi.Updater;
|
||||
using PlexContentCacher = Ombi.Schedule.Jobs.Plex;
|
||||
using Ombi.Api.Telegram;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Engine.Demo;
|
||||
using Ombi.Core.Engine.V2;
|
||||
using Ombi.Core.Processor;
|
||||
using Ombi.Schedule.Jobs.Lidarr;
|
||||
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
||||
using Ombi.Schedule.Jobs.SickRage;
|
||||
using Ombi.Schedule.Processor;
|
||||
using Ombi.Store.Entities;
|
||||
|
||||
namespace Ombi.DependencyInjection
|
||||
{
|
||||
|
@ -95,12 +95,16 @@ namespace Ombi.DependencyInjection
|
|||
services.AddTransient<IMassEmailSender, MassEmailSender>();
|
||||
services.AddTransient<IPlexOAuthManager, PlexOAuthManager>();
|
||||
services.AddTransient<IVoteEngine, VoteEngine>();
|
||||
services.AddTransient<IDemoMovieSearchEngine, DemoMovieSearchEngine>();
|
||||
services.AddTransient<IDemoTvSearchEngine, DemoTvSearchEngine>();
|
||||
}
|
||||
|
||||
public static void RegisterEnginesV2(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IMultiSearchEngine, MultiSearchEngine>();
|
||||
services.AddTransient<IMovieEngineV2, MovieSearchEngineV2>();
|
||||
services.AddTransient<ITVSearchEngineV2, TvSearchEngineV2>();
|
||||
services.AddTransient<ICalendarEngine, CalendarEngine>();
|
||||
}
|
||||
|
||||
public static void RegisterHttp(this IServiceCollection services)
|
||||
|
@ -127,6 +131,7 @@ namespace Ombi.DependencyInjection
|
|||
services.AddTransient<IOmbiService, OmbiService>();
|
||||
services.AddTransient<IFanartTvApi, FanartTvApi>();
|
||||
services.AddTransient<IPushoverApi, PushoverApi>();
|
||||
services.AddTransient<IGotifyApi, GotifyApi>();
|
||||
services.AddTransient<IMattermostApi, MattermostApi>();
|
||||
services.AddTransient<ICouchPotatoApi, CouchPotatoApi>();
|
||||
services.AddTransient<IDogNzbApi, DogNzbApi>();
|
||||
|
@ -139,28 +144,28 @@ namespace Ombi.DependencyInjection
|
|||
}
|
||||
|
||||
public static void RegisterStore(this IServiceCollection services) {
|
||||
services.AddEntityFrameworkSqlite().AddDbContext<OmbiContext>();
|
||||
services.AddEntityFrameworkSqlite().AddDbContext<SettingsContext>();
|
||||
services.AddEntityFrameworkSqlite().AddDbContext<ExternalContext>();
|
||||
services.AddDbContext<OmbiContext>();
|
||||
services.AddDbContext<SettingsContext>();
|
||||
services.AddDbContext<ExternalContext>();
|
||||
|
||||
services.AddScoped<IOmbiContext, OmbiContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
||||
services.AddScoped<ISettingsContext, SettingsContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
||||
services.AddScoped<IExternalContext, ExternalContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
||||
services.AddTransient<ISettingsRepository, SettingsJsonRepository>();
|
||||
services.AddTransient<ISettingsResolver, SettingsResolver>();
|
||||
services.AddTransient<IPlexContentRepository, PlexServerContentRepository>();
|
||||
services.AddTransient<IEmbyContentRepository, EmbyContentRepository>();
|
||||
services.AddTransient<INotificationTemplatesRepository, NotificationTemplatesRepository>();
|
||||
services.AddScoped<ISettingsRepository, SettingsJsonRepository>();
|
||||
services.AddScoped<ISettingsResolver, SettingsResolver>();
|
||||
services.AddScoped<IPlexContentRepository, PlexServerContentRepository>();
|
||||
services.AddScoped<IEmbyContentRepository, EmbyContentRepository>();
|
||||
services.AddScoped<INotificationTemplatesRepository, NotificationTemplatesRepository>();
|
||||
|
||||
services.AddTransient<ITvRequestRepository, TvRequestRepository>();
|
||||
services.AddTransient<IMovieRequestRepository, MovieRequestRepository>();
|
||||
services.AddTransient<IMusicRequestRepository, MusicRequestRepository>();
|
||||
services.AddTransient<IAuditRepository, AuditRepository>();
|
||||
services.AddTransient<IApplicationConfigRepository, ApplicationConfigRepository>();
|
||||
services.AddTransient<ITokenRepository, TokenRepository>();
|
||||
services.AddTransient(typeof(ISettingsService<>), typeof(SettingsService<>));
|
||||
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
|
||||
services.AddTransient(typeof(IExternalRepository<>), typeof(ExternalRepository<>));
|
||||
services.AddScoped<ITvRequestRepository, TvRequestRepository>();
|
||||
services.AddScoped<IMovieRequestRepository, MovieRequestRepository>();
|
||||
services.AddScoped<IMusicRequestRepository, MusicRequestRepository>();
|
||||
services.AddScoped<IAuditRepository, AuditRepository>();
|
||||
services.AddScoped<IApplicationConfigRepository, ApplicationConfigRepository>();
|
||||
services.AddScoped<ITokenRepository, TokenRepository>();
|
||||
services.AddScoped(typeof(ISettingsService<>), typeof(SettingsService<>));
|
||||
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
|
||||
services.AddScoped(typeof(IExternalRepository<>), typeof(ExternalRepository<>));
|
||||
}
|
||||
public static void RegisterServices(this IServiceCollection services)
|
||||
{
|
||||
|
@ -168,7 +173,7 @@ namespace Ombi.DependencyInjection
|
|||
services.AddTransient<INotificationService, NotificationService>();
|
||||
services.AddTransient<IEmailProvider, GenericEmailProvider>();
|
||||
services.AddTransient<INotificationHelper, NotificationHelper>();
|
||||
services.AddTransient<ICacheService, CacheService>();
|
||||
services.AddSingleton<ICacheService, CacheService>();
|
||||
|
||||
services.AddTransient<IDiscordNotification, DiscordNotification>();
|
||||
services.AddTransient<IEmailNotification, EmailNotification>();
|
||||
|
@ -177,6 +182,7 @@ namespace Ombi.DependencyInjection
|
|||
services.AddTransient<ISlackNotification, SlackNotification>();
|
||||
services.AddTransient<IMattermostNotification, MattermostNotification>();
|
||||
services.AddTransient<IPushoverNotification, PushoverNotification>();
|
||||
services.AddTransient<IGotifyNotification, GotifyNotification>();
|
||||
services.AddTransient<ITelegramNotification, TelegramNotification>();
|
||||
services.AddTransient<IMobileNotification, MobileNotification>();
|
||||
services.AddTransient<IChangeLogProcessor, ChangeLogProcessor>();
|
||||
|
|
28
src/Ombi.Helpers.Tests/EmbyHelperTests.cs
Normal file
28
src/Ombi.Helpers.Tests/EmbyHelperTests.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ombi.Helpers.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class EmbyHelperTests
|
||||
{
|
||||
[TestCaseSource(nameof(UrlData))]
|
||||
public string TestUrl(string mediaId, string url)
|
||||
{
|
||||
return EmbyHelper.GetEmbyMediaUrl(mediaId, url);
|
||||
}
|
||||
|
||||
public static IEnumerable<TestCaseData> UrlData
|
||||
{
|
||||
get
|
||||
{
|
||||
var mediaId = 1;
|
||||
yield return new TestCaseData(mediaId.ToString(), "http://google.com").Returns($"http://google.com/#!/itemdetails.html?id={mediaId}").SetName("EmbyHelper_GetMediaUrl_WithCustomDomain_WithoutTrailingSlash");
|
||||
yield return new TestCaseData(mediaId.ToString(), "http://google.com/").Returns($"http://google.com/#!/itemdetails.html?id={mediaId}").SetName("EmbyHelper_GetMediaUrl_WithCustomDomain");
|
||||
yield return new TestCaseData(mediaId.ToString(), "https://google.com/").Returns($"https://google.com/#!/itemdetails.html?id={mediaId}").SetName("EmbyHelper_GetMediaUrl_WithCustomDomain_Https");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
src/Ombi.Helpers.Tests/HtmlHelperTests.cs
Normal file
41
src/Ombi.Helpers.Tests/HtmlHelperTests.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Helpers.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class HtmlHelperTests
|
||||
{
|
||||
[TestCaseSource(nameof(HtmlData))]
|
||||
public string RemoveHtmlTests(string input)
|
||||
{
|
||||
return HtmlHelper.RemoveHtml(input);
|
||||
}
|
||||
|
||||
public static IEnumerable<TestCaseData> HtmlData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("<h1>hi</h1>").Returns("hi").SetName("Simple Html");
|
||||
yield return new TestCaseData("<html><body><head></head><h1>hi</h1></body></html>").Returns("hi").SetName("Nested text inside Html");
|
||||
yield return new TestCaseData("there is no html here").Returns("there is no html here").SetName("No Html");
|
||||
yield return new TestCaseData("there is <b>some</b> html here").Returns("there is some html here").SetName("Html in middle");
|
||||
yield return new TestCaseData("<a>there</a> <u>is</u> <b>lots</b> <i>html</i> <span>here</span>").Returns("there is lots html here").SetName("Html in everywhere");
|
||||
yield return new TestCaseData("there is <span class=\"abc\">some</span> html here").Returns("there is some html here").SetName("Html in with classes");
|
||||
yield return new TestCaseData("there is <span id=\"sometag\">some</span> html here").Returns("there is some html here").SetName("Html in with attribute");
|
||||
yield return new TestCaseData("there is <span data-tag=\"sometag\" class=\"abc\">some</span> html here").Returns("there is some html here").SetName("Html in with attribute and class");
|
||||
}
|
||||
}
|
||||
public static IEnumerable<TestCaseData> OtherData
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var data in HtmlData)
|
||||
{
|
||||
yield return data;
|
||||
}
|
||||
yield return new TestCaseData("xyz").Returns("xyz").SetName("More Tests");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="nunit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
120
src/Ombi.Helpers.Tests/PagnationHelperTests.cs
Normal file
120
src/Ombi.Helpers.Tests/PagnationHelperTests.cs
Normal file
|
@ -0,0 +1,120 @@
|
|||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ombi.Helpers.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class PaginationHelperTests
|
||||
{
|
||||
[TestCaseSource(nameof(TestPageData))]
|
||||
public void TestPaginationPages(int currentlyLoaded, int toLoad, int maxItemsPerPage, int[] expectedPages)
|
||||
{
|
||||
var result = PaginationHelper.GetNextPages(currentlyLoaded, toLoad, maxItemsPerPage);
|
||||
var pages = result.Select(x => x.Page).ToArray();
|
||||
|
||||
Assert.That(pages.Length, Is.EqualTo(expectedPages.Length), "Did not contain the correct amount of pages");
|
||||
for (var i = 0; i < pages.Length; i++)
|
||||
{
|
||||
Assert.That(pages[i], Is.EqualTo(expectedPages[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<TestCaseData> TestPageData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(0, 10, 20, new [] { 1 }).SetName("Pagination_Load_First_Page");
|
||||
yield return new TestCaseData(20, 10, 20, new [] { 2 }).SetName("Pagination_Load_Second_Page");
|
||||
yield return new TestCaseData(0, 20, 20, new [] { 1 }).SetName("Pagination_Load_Full_First_Page");
|
||||
yield return new TestCaseData(20, 20, 20, new [] { 2 }).SetName("Pagination_Load_Full_Second_Page");
|
||||
yield return new TestCaseData(10, 20, 20, new [] { 1, 2 }).SetName("Pagination_Load_Half_First_Page_And_Half_Second_Page");
|
||||
yield return new TestCaseData(19, 20, 20, new[] { 1, 2 }).SetName("Pagination_Load_End_First_Page_And_Most_Second_Page");
|
||||
yield return new TestCaseData(19, 40, 20, new[] { 1, 2, 3 }).SetName("Pagination_Load_End_First_Page_And_Most_Second_And_Third_Page");
|
||||
yield return new TestCaseData(10, 10, 20, new[] { 1 }).SetName("Pagination_Load_Half_First_Page");
|
||||
yield return new TestCaseData(10, 9, 20, new[] { 1 }).SetName("Pagination_Load_LessThan_Half_First_Page");
|
||||
yield return new TestCaseData(20, 10, 20, new[] { 2 }).SetName("Pagination_Load_Half_Second_Page");
|
||||
yield return new TestCaseData(20, 9, 20, new[] { 2 }).SetName("Pagination_Load_LessThan_Half_Second_Page");
|
||||
yield return new TestCaseData(30, 10, 20, new[] { 2 }).SetName("Pagination_Load_All_Second_Page_With_Half_Take");
|
||||
yield return new TestCaseData(49, 1, 50, new[] { 1 }).SetName("Pagination_Load_49_OutOf_50");
|
||||
yield return new TestCaseData(49, 1, 100,new[] { 1 }).SetName("Pagination_Load_50_OutOf_100");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(CurrentPositionTestData))]
|
||||
public void TestCurrentPositionOfPagination(int currentlyLoaded, int toLoad, int maxItemsPerPage, int expectedTake, int expectedSkip)
|
||||
{
|
||||
var result = PaginationHelper.GetNextPages(currentlyLoaded, toLoad, maxItemsPerPage);
|
||||
|
||||
var first = result.FirstOrDefault();
|
||||
Assert.That(first.Take, Is.EqualTo(expectedTake));
|
||||
Assert.That(first.Skip, Is.EqualTo(expectedSkip));
|
||||
}
|
||||
public static IEnumerable<TestCaseData> CurrentPositionTestData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(0, 10, 20, 10, 0).SetName("PaginationPosition_Load_First_Half_Of_Page");
|
||||
yield return new TestCaseData(10, 10, 20, 10, 10).SetName("PaginationPosition_Load_EndHalf_First_Page");
|
||||
yield return new TestCaseData(19, 1, 20, 1, 19).SetName("PaginationPosition_Load_LastItem_Of_First_Page");
|
||||
yield return new TestCaseData(20, 20, 300, 20, 20).SetName("PaginationPosition_Load_Full_Second_Page");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(CurrentPositionMultiplePagesTestData))]
|
||||
public void TestCurrentPositionOfPaginationWithMultiplePages(int currentlyLoaded, int toLoad, int maxItemsPerPage, List<MultiplePagesTestData> data)
|
||||
{
|
||||
var result = PaginationHelper.GetNextPages(currentlyLoaded, toLoad, maxItemsPerPage);
|
||||
|
||||
foreach (var r in result)
|
||||
{
|
||||
// get result data for this page
|
||||
var expectedPage = data.FirstOrDefault(x => x.Page == r.Page);
|
||||
Assert.That(r.Take, Is.EqualTo(expectedPage.ExpectedTake));
|
||||
Assert.That(r.Skip, Is.EqualTo(expectedPage.ExpectedSkip));
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<TestCaseData> CurrentPositionMultiplePagesTestData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(10, 20, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(1, 10, 10), new MultiplePagesTestData(2, 10, 0) })
|
||||
.SetName("PaginationPosition_Load_SecondHalf_FirstPage_FirstHalf_SecondPage");
|
||||
yield return new TestCaseData(0, 40, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(1, 20, 0), new MultiplePagesTestData(2, 20, 0) })
|
||||
.SetName("PaginationPosition_Load_Full_First_And_SecondPage");
|
||||
yield return new TestCaseData(35, 15, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(2, 5, 15), new MultiplePagesTestData(3, 10, 0) })
|
||||
.SetName("PaginationPosition_Load_EndSecondPage_Beginning_ThirdPage");
|
||||
yield return new TestCaseData(18, 22, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(1, 2, 18), new MultiplePagesTestData(2, 20, 0) })
|
||||
.SetName("PaginationPosition_Load_EndFirstPage_Full_SecondPage");
|
||||
yield return new TestCaseData(38, 4, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(2, 2, 18), new MultiplePagesTestData(3, 2, 0) })
|
||||
.SetName("PaginationPosition_Load_EndSecondPage_Some_ThirdPage");
|
||||
yield return new TestCaseData(15, 20, 10, new List<MultiplePagesTestData> { new MultiplePagesTestData(2, 5, 5), new MultiplePagesTestData(3, 10, 0), new MultiplePagesTestData(4, 5, 0) })
|
||||
.SetName("PaginationPosition_Load_EndSecondPage_All_ThirdPage_Some_ForthPage");
|
||||
yield return new TestCaseData(24, 12, 12, new List<MultiplePagesTestData> { new MultiplePagesTestData(3, 12, 0) })
|
||||
.SetName("PaginationPosition_Load_ThirdPage_Of_12");
|
||||
yield return new TestCaseData(12, 12, 12, new List<MultiplePagesTestData> { new MultiplePagesTestData(2, 12, 0) })
|
||||
.SetName("PaginationPosition_Load_SecondPage_Of_12");
|
||||
yield return new TestCaseData(40, 20, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(3, 20, 0) })
|
||||
.SetName("PaginationPosition_Load_FullThird_Page");
|
||||
yield return new TestCaseData(240, 12, 20, new List<MultiplePagesTestData> { new MultiplePagesTestData(13, 12, 0) })
|
||||
.SetName("PaginationPosition_Load_Page_13");
|
||||
}
|
||||
}
|
||||
|
||||
public class MultiplePagesTestData
|
||||
{
|
||||
public MultiplePagesTestData(int page, int take, int skip)
|
||||
{
|
||||
Page = page;
|
||||
ExpectedTake = take;
|
||||
ExpectedSkip = skip;
|
||||
}
|
||||
public int Page { get; set; }
|
||||
public int ExpectedTake { get; set; }
|
||||
public int ExpectedSkip { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
115
src/Ombi.Helpers.Tests/UriHelperTests.cs
Normal file
115
src/Ombi.Helpers.Tests/UriHelperTests.cs
Normal file
|
@ -0,0 +1,115 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Ombi.Helpers.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class UriHelperTests
|
||||
{
|
||||
[TestCaseSource(nameof(UrlData))]
|
||||
public string ReturnUri(string uri)
|
||||
{
|
||||
return UriHelper.ReturnUri(uri).ToString();
|
||||
}
|
||||
public static IEnumerable<TestCaseData> UrlData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("https://google.com/").Returns($"https://google.com/").SetName("ReturnUri_With_HttpScheme");
|
||||
yield return new TestCaseData("google.com/").Returns($"http://google.com/").SetName("ReturnUri_HttpScheme_Not_Provided");
|
||||
yield return new TestCaseData("http://google.com:9090/").Returns($"http://google.com:9090/").SetName("ReturnUri_WithPort");
|
||||
yield return new TestCaseData("https://google.com/").Returns($"https://google.com/").SetName("ReturnUri_With_HttpsScheme");
|
||||
yield return new TestCaseData("https://hi.google.com/").Returns($"https://hi.google.com/").SetName("ReturnUri_With_SubDomain");
|
||||
yield return new TestCaseData("https://google.com/hi").Returns($"https://google.com/hi").SetName("ReturnUri_With_Path");
|
||||
yield return new TestCaseData("https://hi.google.com/hi").Returns($"https://hi.google.com/hi").SetName("ReturnUri_With_Path_And_SubDomain");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(UrlWithPortData))]
|
||||
public string ReturnUriWithPort(string uri, int port)
|
||||
{
|
||||
return UriHelper.ReturnUri(uri, port).ToString();
|
||||
}
|
||||
public static IEnumerable<TestCaseData> UrlWithPortData
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
yield return new TestCaseData("https://google.com", 443).Returns($"https://google.com/").SetName("ReturnUri_With_HttpsPort");
|
||||
yield return new TestCaseData("https://google.com/", 123).Returns($"https://google.com:123/").SetName("ReturnUri_With_HttpScheme_With_Port");
|
||||
yield return new TestCaseData("google.com/", 80).Returns($"http://google.com/").SetName("ReturnUri_HttpScheme_Not_Provided_With_Port");
|
||||
yield return new TestCaseData("https://google.com/", 7000).Returns($"https://google.com:7000/").SetName("ReturnUri_With_HttpsScheme_With_Port");
|
||||
yield return new TestCaseData("https://hi.google.com/", 1).Returns($"https://hi.google.com:1/").SetName("ReturnUri_With_SubDomain_With_Port");
|
||||
yield return new TestCaseData("https://google.com/hi", 443).Returns($"https://google.com/hi").SetName("ReturnUri_With_Path_With_Port");
|
||||
yield return new TestCaseData("https://hi.google.com/hi", 443).Returns($"https://hi.google.com/hi").SetName("ReturnUri_With_Path_And_SubDomain_With_Port");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(UrlWithPortWithSSLData))]
|
||||
public string ReturnUriWithPortAndSSL(string uri, int port, bool ssl)
|
||||
{
|
||||
return UriHelper.ReturnUri(uri, port, ssl).ToString();
|
||||
}
|
||||
public static IEnumerable<TestCaseData> UrlWithPortWithSSLData
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var d in UrlWithPortData)
|
||||
{
|
||||
var expected = (string)d.ExpectedResult;
|
||||
var args = d.Arguments.ToList();
|
||||
args.Add(true);
|
||||
var newExpected = expected.Replace("http://", "https://");
|
||||
if (args.Contains(80))
|
||||
{
|
||||
newExpected = expected;
|
||||
}
|
||||
d.TestName += "_With_SSL";
|
||||
|
||||
yield return new TestCaseData(args.ToArray()).Returns(newExpected).SetName(d.TestName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(UrlWithPortWithSSLDataCasing))]
|
||||
public string ReturnUriWithPortAndSSLCasing(string uri, int port, bool ssl)
|
||||
{
|
||||
return UriHelper.ReturnUri(uri, port, ssl).ToString();
|
||||
}
|
||||
public static IEnumerable<TestCaseData> UrlWithPortWithSSLDataCasing
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var d in UrlWithPortData)
|
||||
{
|
||||
if (d.TestName.Contains("_Path_"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var expected = (string)d.ExpectedResult;
|
||||
var args = d.Arguments.ToList();
|
||||
for (int i = 0; i < args.Count; i++)
|
||||
{
|
||||
if(args[i] is string)
|
||||
{
|
||||
args[i] = ((string)args[i]).ToUpper();
|
||||
}
|
||||
}
|
||||
args.Add(true);
|
||||
var newExpected = expected.Replace("http://", "https://");
|
||||
if (args.Contains(80))
|
||||
{
|
||||
newExpected = expected;
|
||||
}
|
||||
d.TestName += "_With_SSL_ToUpper";
|
||||
|
||||
yield return new TestCaseData(args.ToArray()).Returns(newExpected).SetName(d.TestName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ namespace Ombi.Helpers
|
|||
return result;
|
||||
}
|
||||
|
||||
using (await _mutex.LockAsync())
|
||||
//using (await _mutex.LockAsync())
|
||||
{
|
||||
if (_memoryCache.TryGetValue(cacheKey, out result))
|
||||
{
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
using System;
|
||||
using System.Security.Claims;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public class ClaimConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return (objectType == typeof(System.Security.Claims.Claim));
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var claim = (System.Security.Claims.Claim)value;
|
||||
JObject jo = new JObject();
|
||||
jo.Add("Type", claim.Type);
|
||||
jo.Add("Value", IsJson(claim.Value) ? new JRaw(claim.Value) : new JValue(claim.Value));
|
||||
jo.Add("ValueType", claim.ValueType);
|
||||
jo.Add("Issuer", claim.Issuer);
|
||||
jo.Add("OriginalIssuer", claim.OriginalIssuer);
|
||||
jo.WriteTo(writer);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
JObject jo = JObject.Load(reader);
|
||||
string type = (string)jo["Type"];
|
||||
JToken token = jo["Value"];
|
||||
string value = token.Type == JTokenType.String ? (string)token : token.ToString(Formatting.None);
|
||||
string valueType = (string)jo["ValueType"];
|
||||
string issuer = (string)jo["Issuer"];
|
||||
string originalIssuer = (string)jo["OriginalIssuer"];
|
||||
return new Claim(type, value, valueType, issuer, originalIssuer);
|
||||
}
|
||||
|
||||
private bool IsJson(string val)
|
||||
{
|
||||
return (val != null &&
|
||||
(val.StartsWith("[") && val.EndsWith("]")) ||
|
||||
(val.StartsWith("{") && val.EndsWith("}")));
|
||||
}
|
||||
}
|
||||
}
|
11
src/Ombi.Helpers/DemoLists.cs
Normal file
11
src/Ombi.Helpers/DemoLists.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ombi.Config
|
||||
{
|
||||
public class DemoLists
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public int[] Movies { get; set; }
|
||||
public int[] TvShows { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
13
src/Ombi.Helpers/DemoSingleton.cs
Normal file
13
src/Ombi.Helpers/DemoSingleton.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace Ombi.Helpers
|
||||
{
|
||||
public class DemoSingleton
|
||||
{
|
||||
private static DemoSingleton instance;
|
||||
|
||||
private DemoSingleton() { }
|
||||
|
||||
public static DemoSingleton Instance => instance ?? (instance = new DemoSingleton());
|
||||
|
||||
public bool Demo { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,9 +1,4 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public class EmbyHelper
|
||||
{
|
||||
|
@ -11,6 +6,10 @@ namespace Ombi.Helpers
|
|||
{
|
||||
if (customerServerUrl.HasValue())
|
||||
{
|
||||
if(!customerServerUrl.EndsWith("/"))
|
||||
{
|
||||
return $"{customerServerUrl}/#!/itemdetails.html?id={mediaId}";
|
||||
}
|
||||
return $"{customerServerUrl}#!/itemdetails.html?id={mediaId}";
|
||||
}
|
||||
else
|
||||
|
|
|
@ -14,6 +14,5 @@ namespace Ombi.Helpers
|
|||
var step2 = Regex.Replace(step1, @"\s{2,}", " ");
|
||||
return step2;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
|
@ -21,5 +22,31 @@ namespace Ombi.Helpers
|
|||
{
|
||||
return new HashSet<T>(source, comparer);
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
|
||||
{
|
||||
return source.Shuffle(new Random());
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
if (rng == null) throw new ArgumentNullException(nameof(rng));
|
||||
|
||||
return source.ShuffleIterator(rng);
|
||||
}
|
||||
|
||||
private static IEnumerable<T> ShuffleIterator<T>(
|
||||
this IEnumerable<T> source, Random rng)
|
||||
{
|
||||
var buffer = source.ToList();
|
||||
for (int i = 0; i < buffer.Count; i++)
|
||||
{
|
||||
int j = rng.Next(i, buffer.Count);
|
||||
yield return buffer[j];
|
||||
|
||||
buffer[j] = buffer[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ namespace Ombi.Helpers
|
|||
public static EventId MattermostNotification => new EventId(4004);
|
||||
public static EventId PushoverNotification => new EventId(4005);
|
||||
public static EventId TelegramNotifcation => new EventId(4006);
|
||||
public static EventId GotifyNotification => new EventId(4007);
|
||||
|
||||
public static EventId TvSender => new EventId(5000);
|
||||
public static EventId SonarrSender => new EventId(5001);
|
||||
|
|
|
@ -10,5 +10,6 @@
|
|||
Slack = 5,
|
||||
Mattermost = 6,
|
||||
Mobile = 7,
|
||||
Gotify = 8,
|
||||
}
|
||||
}
|
|
@ -15,5 +15,6 @@
|
|||
public const string Disabled = nameof(Disabled);
|
||||
public const string ReceivesNewsletter = nameof(ReceivesNewsletter);
|
||||
public const string ManageOwnRequests = nameof(ManageOwnRequests);
|
||||
public const string EditCustomPage = nameof(EditCustomPage);
|
||||
}
|
||||
}
|
64
src/Ombi.Helpers/PaginationHelper.cs
Normal file
64
src/Ombi.Helpers/PaginationHelper.cs
Normal file
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public static class PaginationHelper
|
||||
{
|
||||
public static List<PagesToLoad> GetNextPages(int currentlyLoaded, int toTake, int maxItemsPerPage)
|
||||
{
|
||||
var result = new List<PagesToLoad>();
|
||||
|
||||
var firstPage = currentlyLoaded / maxItemsPerPage + 1;
|
||||
var startPos = currentlyLoaded % maxItemsPerPage + 1;
|
||||
|
||||
var lastItemIndex = currentlyLoaded + toTake - 1;
|
||||
var lastPage = lastItemIndex / maxItemsPerPage + 1;
|
||||
var stopPos = lastItemIndex % maxItemsPerPage + 1;
|
||||
|
||||
while (currentlyLoaded > maxItemsPerPage)
|
||||
{
|
||||
currentlyLoaded -= maxItemsPerPage;
|
||||
}
|
||||
if ((currentlyLoaded % maxItemsPerPage) == 0 && (currentlyLoaded % toTake) == 0)
|
||||
{
|
||||
currentlyLoaded = 0;
|
||||
}
|
||||
|
||||
var page1 = new PagesToLoad { Page = firstPage, Skip = currentlyLoaded, Take = toTake };
|
||||
|
||||
if (toTake + startPos - 1 > maxItemsPerPage)
|
||||
{
|
||||
page1.Take = maxItemsPerPage - startPos + 1;
|
||||
result.Add(page1);
|
||||
|
||||
for (var i = firstPage + 1; i < lastPage; i++)
|
||||
{
|
||||
var nextPage = new PagesToLoad { Page = i, Skip = 0, Take = maxItemsPerPage };
|
||||
result.Add(nextPage);
|
||||
}
|
||||
|
||||
var pageN = new PagesToLoad { Page = lastPage, Skip = 0, Take = stopPos };
|
||||
result.Add(pageN);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (page1.Skip + page1.Take > maxItemsPerPage)
|
||||
{
|
||||
page1.Skip = 0;
|
||||
}
|
||||
result.Add(page1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public class PagesToLoad
|
||||
{
|
||||
public int Page { get; set; }
|
||||
public int Take { get; set; }
|
||||
public int Skip { get; set; }
|
||||
}
|
||||
}
|
|
@ -6,46 +6,44 @@ namespace Ombi.Helpers
|
|||
{
|
||||
private const string Https = "Https";
|
||||
private const string Http = "Http";
|
||||
|
||||
|
||||
public static Uri ReturnUri(this string val)
|
||||
{
|
||||
if (val == null)
|
||||
{
|
||||
throw new ApplicationSettingsException("The URI is null, please check your settings to make sure you have configured the applications correctly.");
|
||||
}
|
||||
try
|
||||
var uri = new UriBuilder();
|
||||
|
||||
if (val.StartsWith("http://", StringComparison.Ordinal))
|
||||
{
|
||||
var uri = new UriBuilder();
|
||||
|
||||
if (val.StartsWith("http://", StringComparison.Ordinal))
|
||||
{
|
||||
uri = new UriBuilder(val);
|
||||
}
|
||||
else if (val.StartsWith("https://", StringComparison.Ordinal))
|
||||
{
|
||||
uri = new UriBuilder(val);
|
||||
}
|
||||
else if (val.Contains(":"))
|
||||
{
|
||||
var split = val.Split(':', '/');
|
||||
int port;
|
||||
int.TryParse(split[1], out port);
|
||||
|
||||
uri = split.Length == 3
|
||||
? new UriBuilder(Http, split[0], port, "/" + split[2])
|
||||
: new UriBuilder(Http, split[0], port);
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = new UriBuilder(Http, val);
|
||||
}
|
||||
|
||||
return uri.Uri;
|
||||
uri = new UriBuilder(val);
|
||||
}
|
||||
catch (Exception exception)
|
||||
else if (val.StartsWith("https://", StringComparison.Ordinal))
|
||||
{
|
||||
throw new Exception(exception.Message, exception);
|
||||
uri = new UriBuilder(val);
|
||||
}
|
||||
else if (val.Contains(":"))
|
||||
{
|
||||
var split = val.Split(':', '/');
|
||||
int port;
|
||||
int.TryParse(split[1], out port);
|
||||
|
||||
uri = split.Length == 3
|
||||
? new UriBuilder(Http, split[0], port, "/" + split[2])
|
||||
: new UriBuilder(Http, split[0], port);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(val.EndsWith("/"))
|
||||
{
|
||||
// Remove a trailing slash, since the URIBuilder adds one
|
||||
val = val.Remove(val.Length - 1, 1);
|
||||
}
|
||||
uri = new UriBuilder(Http, val);
|
||||
}
|
||||
|
||||
return uri.Uri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -64,37 +62,40 @@ namespace Ombi.Helpers
|
|||
{
|
||||
throw new ApplicationSettingsException("The URI is null, please check your settings to make sure you have configured the applications correctly.");
|
||||
}
|
||||
try
|
||||
{
|
||||
var uri = new UriBuilder();
|
||||
var uri = new UriBuilder();
|
||||
|
||||
if (val.StartsWith("http://", StringComparison.Ordinal))
|
||||
{
|
||||
var split = val.Split('/');
|
||||
uri = split.Length >= 4 ? new UriBuilder(Http, split[2], port, "/" + split[3]) : new UriBuilder(new Uri($"{val}:{port}"));
|
||||
}
|
||||
else if (val.StartsWith("https://", StringComparison.Ordinal))
|
||||
{
|
||||
var split = val.Split('/');
|
||||
uri = split.Length >= 4
|
||||
? new UriBuilder(Https, split[2], port, "/" + split[3])
|
||||
: new UriBuilder(Https, split[2], port);
|
||||
}
|
||||
else if (ssl)
|
||||
{
|
||||
uri = new UriBuilder(Https, val, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = new UriBuilder(Http, val, port);
|
||||
}
|
||||
|
||||
return uri.Uri;
|
||||
}
|
||||
catch (Exception exception)
|
||||
if (val.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
throw new Exception(exception.Message, exception);
|
||||
var split = val.Split('/');
|
||||
uri = split.Length >= 4 ? new UriBuilder(Http, split[2], port, "/" + split[3]) : new UriBuilder(new Uri($"{val}:{port}"));
|
||||
}
|
||||
else if (val.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
var split = val.Split('/');
|
||||
uri = split.Length >= 4
|
||||
? new UriBuilder(Https, split[2], port, "/" + split[3])
|
||||
: new UriBuilder(Https, split[2], port);
|
||||
}
|
||||
else if ((ssl || port == 443) && port != 80)
|
||||
{
|
||||
if (val.EndsWith("/"))
|
||||
{
|
||||
// Remove a trailing slash, since the URIBuilder adds one
|
||||
val = val.Remove(val.Length - 1, 1);
|
||||
}
|
||||
uri = new UriBuilder(Https, val, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (val.EndsWith("/"))
|
||||
{
|
||||
// Remove a trailing slash, since the URIBuilder adds one
|
||||
val = val.Remove(val.Length - 1, 1);
|
||||
}
|
||||
uri = new UriBuilder(Http, val, port);
|
||||
}
|
||||
|
||||
return uri.Uri;
|
||||
}
|
||||
|
||||
public static Uri ReturnUriWithSubDir(this string val, int port, bool ssl, string subDir)
|
||||
|
@ -112,7 +113,7 @@ namespace Ombi.Helpers
|
|||
|
||||
return uriBuilder.Uri;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class ApplicationSettingsException : Exception
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using AutoMapper;
|
||||
using AutoMapper.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
@ -12,9 +11,9 @@ namespace Ombi.Mapping
|
|||
{
|
||||
public static IServiceCollection AddOmbiMappingProfile(this IServiceCollection services)
|
||||
{
|
||||
System.Reflection.Assembly ass = typeof(AutoMapperProfile).GetTypeInfo().Assembly;
|
||||
Assembly ass = typeof(AutoMapperProfile).GetTypeInfo().Assembly;
|
||||
var assemblies = new List<Type>();
|
||||
foreach (System.Reflection.TypeInfo ti in ass.DefinedTypes)
|
||||
foreach (TypeInfo ti in ass.DefinedTypes)
|
||||
{
|
||||
if (ti.ImplementedInterfaces.Contains(typeof(IProfileConfiguration)))
|
||||
{
|
||||
|
|
|
@ -4,6 +4,8 @@ using Ombi.Api.TheMovieDb.Models;
|
|||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
using Ombi.TheMovieDbApi.Models;
|
||||
using Keywords = Ombi.Core.Models.Search.V2.Keywords;
|
||||
using KeywordsValue = Ombi.Api.TheMovieDb.Models.KeywordsValue;
|
||||
|
||||
namespace Ombi.Mapping.Profiles
|
||||
{
|
||||
|
@ -86,6 +88,22 @@ namespace Ombi.Mapping.Profiles
|
|||
CreateMap<Ombi.Api.TheMovieDb.Models.FullMovieCast, Ombi.Core.Models.Search.V2.FullMovieCastViewModel>().ReverseMap();
|
||||
CreateMap<Ombi.Api.TheMovieDb.Models.FullMovieCrew, Ombi.Core.Models.Search.V2.FullMovieCrewViewModel>().ReverseMap();
|
||||
CreateMap<Ombi.Api.TheMovieDb.Models.ExternalIds, Ombi.Core.Models.Search.V2.ExternalIds>().ReverseMap();
|
||||
CreateMap<BelongsToCollection, Ombi.Core.Models.Search.V2.CollectionsViewModel>().ReverseMap();
|
||||
CreateMap<Api.TheMovieDb.Models.Keywords, Ombi.Core.Models.Search.V2.Keywords>().ReverseMap();
|
||||
CreateMap<KeywordsValue, Ombi.Core.Models.Search.V2.KeywordsValue>().ReverseMap();
|
||||
|
||||
CreateMap<Collections, Ombi.Core.Models.Search.V2.MovieCollectionsViewModel>()
|
||||
.ForMember(x => x.Name, o => o.MapFrom(s => s.name))
|
||||
.ForMember(x => x.Overview, o => o.MapFrom(s => s.overview))
|
||||
.ForMember(x => x.Collection, o => o.MapFrom(s => s.parts));
|
||||
|
||||
CreateMap<Part, MovieCollection>()
|
||||
.ForMember(x => x.Id, o => o.MapFrom(s => s.id))
|
||||
.ForMember(x => x.Overview, o => o.MapFrom(s => s.overview))
|
||||
.ForMember(x => x.PosterPath, o => o.MapFrom(s => s.poster_path))
|
||||
.ForMember(x => x.Title, o => o.MapFrom(s => s.title));
|
||||
|
||||
CreateMap<SearchMovieViewModel, MovieCollection>().ReverseMap();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ namespace Ombi.Mapping.Profiles
|
|||
CreateMap<UpdateSettingsViewModel, UpdateSettings>().ReverseMap();
|
||||
CreateMap<MobileNotificationsViewModel, MobileNotificationSettings>().ReverseMap();
|
||||
CreateMap<NewsletterNotificationViewModel, NewsletterSettings>().ReverseMap();
|
||||
CreateMap<GotifyNotificationViewModel, GotifySettings>().ReverseMap();
|
||||
}
|
||||
}
|
||||
}
|
82
src/Ombi.Mapping/Profiles/TvProfileV2.cs
Normal file
82
src/Ombi.Mapping/Profiles/TvProfileV2.cs
Normal file
|
@ -0,0 +1,82 @@
|
|||
using System.Globalization;
|
||||
using AutoMapper;
|
||||
using Ombi.Api.TvMaze.Models.V2;
|
||||
using Ombi.Core.Models.Search;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
using Ombi.Helpers;
|
||||
|
||||
namespace Ombi.Mapping.Profiles
|
||||
{
|
||||
public class TvProfileV2 : Profile
|
||||
{
|
||||
public TvProfileV2()
|
||||
{
|
||||
CreateMap<FullSearch, SearchFullInfoTvShowViewModel>()
|
||||
.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.average.ToString(CultureInfo.CurrentUICulture)))
|
||||
.ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.runtime.ToString()))
|
||||
.ForMember(dest => dest.SeriesId, opts => opts.MapFrom(src => src.id))
|
||||
.ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.name))
|
||||
.ForMember(dest => dest.Network, opts => opts.MapFrom(src => src.network))
|
||||
.ForMember(dest => dest.Images, opts => opts.MapFrom(src => src.image))
|
||||
.ForMember(dest => dest.Cast, opts => opts.MapFrom(src => src._embedded.cast))
|
||||
.ForMember(dest => dest.Crew, opts => opts.MapFrom(src => src._embedded.crew))
|
||||
.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));
|
||||
|
||||
CreateMap<Network, NetworkViewModel>()
|
||||
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.id))
|
||||
.ForMember(dest => dest.Country, opts => opts.MapFrom(src => src.country))
|
||||
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.name));
|
||||
|
||||
CreateMap<Api.TvMaze.Models.V2.Country, Core.Models.Search.V2.Country>()
|
||||
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.name))
|
||||
.ForMember(dest => dest.Code, opts => opts.MapFrom(src => src.code))
|
||||
.ForMember(dest => dest.Timezone, opts => opts.MapFrom(src => src.timezone));
|
||||
|
||||
CreateMap<Api.TvMaze.Models.V2.Image, Images>()
|
||||
.ForMember(dest => dest.Medium, opts => opts.MapFrom(src => src.medium))
|
||||
.ForMember(dest => dest.Original, opts => opts.MapFrom(src => src.original));
|
||||
|
||||
CreateMap<Api.TvMaze.Models.V2.Cast, CastViewModel>()
|
||||
.ForMember(dest => dest.Character, opts => opts.MapFrom(src => src.character))
|
||||
.ForMember(dest => dest.Person, opts => opts.MapFrom(src => src.person))
|
||||
.ForMember(dest => dest.Voice, opts => opts.MapFrom(src => src.voice))
|
||||
.ForMember(dest => dest.Self, opts => opts.MapFrom(src => src.self));
|
||||
|
||||
CreateMap<Api.TvMaze.Models.V2.Person, PersonViewModel>()
|
||||
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.id))
|
||||
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.name))
|
||||
.ForMember(dest => dest.Image, opts => opts.MapFrom(src => src.image))
|
||||
.ForMember(dest => dest.Url, opts => opts.MapFrom(src => src.url));
|
||||
|
||||
CreateMap<Api.TvMaze.Models.V2.Crew, CrewViewModel>()
|
||||
.ForMember(dest => dest.Person, opts => opts.MapFrom(src => src.person))
|
||||
.ForMember(dest => dest.Type, opts => opts.MapFrom(src => src.type));
|
||||
|
||||
CreateMap<Api.TvMaze.Models.V2.Cast, CastViewModel>()
|
||||
.ForMember(dest => dest.Person, opts => opts.MapFrom(src => src.person))
|
||||
.ForMember(dest => dest.Self, opts => opts.MapFrom(src => src.self))
|
||||
.ForMember(dest => dest.Voice, opts => opts.MapFrom(src => src.voice))
|
||||
.ForMember(dest => dest.Character, opts => opts.MapFrom(src => src.character));
|
||||
|
||||
CreateMap<Api.TvMaze.Models.V2.Character, CharacterViewModel>()
|
||||
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.name))
|
||||
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.id))
|
||||
.ForMember(dest => dest.Url, opts => opts.MapFrom(src => src.url))
|
||||
.ForMember(dest => dest.Image, opts => opts.MapFrom(src => src.image));
|
||||
|
||||
CreateMap<SearchTvShowViewModel, SearchFullInfoTvShowViewModel>().ReverseMap();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ namespace Ombi.Notifications.Templates
|
|||
if (string.IsNullOrEmpty(_templateLocation))
|
||||
{
|
||||
#if DEBUG
|
||||
_templateLocation = Path.Combine(Directory.GetCurrentDirectory(), "bin", "Debug", "netcoreapp2.0", "Templates",
|
||||
_templateLocation = Path.Combine(Directory.GetCurrentDirectory(), "bin", "Debug", "netcoreapp2.2", "Templates",
|
||||
"BasicTemplate.html");
|
||||
#else
|
||||
_templateLocation = Path.Combine(Directory.GetCurrentDirectory(), "Templates","BasicTemplate.html");
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nunit" Version="3.10.1" />
|
||||
<PackageReference Include="Nunit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.9.0"></packagereference>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="16.0.1"></packagereference>
|
||||
<PackageReference Include="Moq" Version="4.10.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
116
src/Ombi.Notifications/Agents/GotifyNotification.cs
Normal file
116
src/Ombi.Notifications/Agents/GotifyNotification.cs
Normal file
|
@ -0,0 +1,116 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Gotify;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Settings.Settings.Models.Notifications;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Notifications.Agents
|
||||
{
|
||||
public class GotifyNotification : BaseNotification<GotifySettings>, IGotifyNotification
|
||||
{
|
||||
public GotifyNotification(IGotifyApi api, ISettingsService<GotifySettings> sn, ILogger<GotifyNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
|
||||
ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub, IMusicRequestRepository music,
|
||||
IRepository<UserNotificationPreferences> userPref) : base(sn, r, m, t, s, log, sub, music, userPref)
|
||||
{
|
||||
Api = api;
|
||||
Logger = log;
|
||||
}
|
||||
|
||||
public override string NotificationName => "GotifyNotification";
|
||||
|
||||
private IGotifyApi Api { get; }
|
||||
private ILogger<GotifyNotification> Logger { get; }
|
||||
|
||||
protected override bool ValidateConfiguration(GotifySettings settings)
|
||||
{
|
||||
return settings.Enabled && !string.IsNullOrEmpty(settings.BaseUrl) && !string.IsNullOrEmpty(settings.ApplicationToken);
|
||||
}
|
||||
|
||||
protected override async Task NewRequest(NotificationOptions model, GotifySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.NewRequest);
|
||||
}
|
||||
|
||||
|
||||
protected override async Task NewIssue(NotificationOptions model, GotifySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.Issue);
|
||||
}
|
||||
|
||||
protected override async Task IssueComment(NotificationOptions model, GotifySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.IssueComment);
|
||||
}
|
||||
|
||||
protected override async Task IssueResolved(NotificationOptions model, GotifySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.IssueResolved);
|
||||
}
|
||||
|
||||
protected override async Task AddedToRequestQueue(NotificationOptions model, GotifySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.ItemAddedToFaultQueue);
|
||||
}
|
||||
|
||||
protected override async Task RequestDeclined(NotificationOptions model, GotifySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.RequestDeclined);
|
||||
}
|
||||
|
||||
protected override async Task RequestApproved(NotificationOptions model, GotifySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.RequestApproved);
|
||||
}
|
||||
|
||||
protected override async Task AvailableRequest(NotificationOptions model, GotifySettings settings)
|
||||
{
|
||||
await Run(model, settings, NotificationType.RequestAvailable);
|
||||
}
|
||||
|
||||
protected override async Task Send(NotificationMessage model, GotifySettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Api.PushAsync(settings.BaseUrl, settings.ApplicationToken, model.Subject, model.Message, settings.Priority);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(LoggingEvents.GotifyNotification, e, "Failed to send Gotify notification");
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task Test(NotificationOptions model, GotifySettings settings)
|
||||
{
|
||||
var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!";
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
};
|
||||
await Send(notification, settings);
|
||||
}
|
||||
|
||||
private async Task Run(NotificationOptions model, GotifySettings settings, NotificationType type)
|
||||
{
|
||||
var parsed = await LoadTemplate(NotificationAgent.Gotify, type, model);
|
||||
if (parsed.Disabled)
|
||||
{
|
||||
Logger.LogInformation($"Template {type} is disabled for {NotificationAgent.Gotify}");
|
||||
return;
|
||||
}
|
||||
|
||||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = parsed.Message,
|
||||
};
|
||||
|
||||
await Send(notification, settings);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace Ombi.Notifications.Agents
|
||||
{
|
||||
public interface IGotifyNotification : INotification
|
||||
{
|
||||
}
|
||||
}
|
|
@ -52,7 +52,7 @@ namespace Ombi.Notifications.Agents
|
|||
private void AddOtherInformation(NotificationOptions model, NotificationMessage notification,
|
||||
NotificationMessageContent parsed)
|
||||
{
|
||||
notification.Other.Add("image", parsed.Image);
|
||||
notification.Other.Add("image", parsed?.Image ?? string.Empty);
|
||||
notification.Other.Add("title", model.RequestType == RequestType.Movie ? MovieRequest.Title : TvRequest.Title);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,6 @@ namespace Ombi.Notifications
|
|||
MovieRepository = movie;
|
||||
TvRepository = tv;
|
||||
CustomizationSettings = customization;
|
||||
Settings.ClearCache();
|
||||
CustomizationSettings.ClearCache();
|
||||
RequestSubscription = sub;
|
||||
_log = log;
|
||||
AlbumRepository = album;
|
||||
|
@ -55,14 +53,12 @@ namespace Ombi.Notifications
|
|||
|
||||
public async Task NotifyAsync(NotificationOptions model)
|
||||
{
|
||||
Settings.ClearCache();
|
||||
var configuration = await GetConfiguration();
|
||||
await NotifyAsync(model, configuration);
|
||||
}
|
||||
|
||||
public async Task NotifyAsync(NotificationOptions model, Settings.Settings.Models.Settings settings)
|
||||
{
|
||||
Settings.ClearCache();
|
||||
if (settings == null) await NotifyAsync(model);
|
||||
|
||||
var notificationSettings = (T)settings;
|
||||
|
|
|
@ -4,7 +4,9 @@ using EnsureThat;
|
|||
using MailKit.Net.Smtp;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MimeKit;
|
||||
using MimeKit.Utils;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Notifications.Templates;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
|
@ -36,6 +38,15 @@ namespace Ombi.Notifications
|
|||
|
||||
var customization = await CustomizationSettings.GetSettingsAsync();
|
||||
var html = email.LoadTemplate(model.Subject, model.Message, null, customization.Logo);
|
||||
|
||||
var messageId = MimeUtils.GenerateMessageId();
|
||||
if (customization.ApplicationUrl.HasValue())
|
||||
{
|
||||
if (Uri.TryCreate(customization.ApplicationUrl, UriKind.RelativeOrAbsolute, out var url))
|
||||
{
|
||||
messageId = MimeUtils.GenerateMessageId(url.IdnHost);
|
||||
}
|
||||
}
|
||||
|
||||
var textBody = string.Empty;
|
||||
|
||||
|
@ -49,7 +60,8 @@ namespace Ombi.Notifications
|
|||
var message = new MimeMessage
|
||||
{
|
||||
Body = body.ToMessageBody(),
|
||||
Subject = model.Subject
|
||||
Subject = model.Subject,
|
||||
MessageId = messageId
|
||||
};
|
||||
message.From.Add(new MailboxAddress(string.IsNullOrEmpty(settings.SenderName) ? settings.SenderAddress : settings.SenderName, settings.SenderAddress));
|
||||
message.To.Add(new MailboxAddress(model.To, model.To));
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Ombi.Notifications
|
|||
public void Setup(NotificationOptions opts, FullBaseRequest req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||
{
|
||||
LoadIssues(opts);
|
||||
|
||||
RequestId = req.Id.ToString();
|
||||
string title;
|
||||
if (req == null)
|
||||
{
|
||||
|
@ -68,6 +68,7 @@ namespace Ombi.Notifications
|
|||
{
|
||||
LoadIssues(opts);
|
||||
|
||||
RequestId = req.Id.ToString();
|
||||
string title;
|
||||
if (req == null)
|
||||
{
|
||||
|
@ -114,6 +115,7 @@ namespace Ombi.Notifications
|
|||
public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||
{
|
||||
LoadIssues(opts);
|
||||
RequestId = req.Id.ToString();
|
||||
string title;
|
||||
if (req == null)
|
||||
{
|
||||
|
@ -239,6 +241,7 @@ namespace Ombi.Notifications
|
|||
public string UserPreference { get; set; }
|
||||
public string DenyReason { get; set; }
|
||||
public string AvailableDate { get; set; }
|
||||
public string RequestId { get; set; }
|
||||
|
||||
// System Defined
|
||||
private string LongDate => DateTime.Now.ToString("D");
|
||||
|
@ -275,6 +278,7 @@ namespace Ombi.Notifications
|
|||
{nameof(UserPreference),UserPreference},
|
||||
{nameof(DenyReason),DenyReason},
|
||||
{nameof(AvailableDate),AvailableDate},
|
||||
{nameof(RequestId),RequestId},
|
||||
};
|
||||
}
|
||||
}
|
|
@ -10,11 +10,12 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ensure.That" Version="7.0.0-pre32" />
|
||||
<PackageReference Include="MailKit" Version="2.0.5" />
|
||||
<PackageReference Include="MailKit" Version="2.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Api.Discord\Ombi.Api.Discord.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Gotify\Ombi.Api.Gotify.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Notifications\Ombi.Api.Notifications.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
|
||||
|
|
|
@ -44,12 +44,12 @@ namespace Ombi.Schedule.Tests
|
|||
new Issues
|
||||
{
|
||||
Status = IssueStatus.Resolved,
|
||||
ResovledDate = DateTime.Now.AddDays(-5).AddHours(-1)
|
||||
ResovledDate = DateTime.UtcNow.AddDays(-5).AddHours(-8)
|
||||
}
|
||||
};
|
||||
|
||||
Settings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new IssueSettings { DeleteIssues = true, DaysAfterResolvedToDelete = 5 });
|
||||
Repo.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Issues>(issues));
|
||||
Repo.Setup(x => x.GetAll()).Returns(issues.AsQueryable());
|
||||
await Job.Start();
|
||||
|
||||
Assert.That(issues.First().Status, Is.EqualTo(IssueStatus.Deleted));
|
||||
|
@ -57,7 +57,7 @@ namespace Ombi.Schedule.Tests
|
|||
}
|
||||
|
||||
[Test]
|
||||
public async Task DoesNot_Delete_AnyIssues()
|
||||
public async Task DoesNot_Delete_AllIssues()
|
||||
{
|
||||
var issues = new List<Issues>()
|
||||
{
|
||||
|
@ -81,5 +81,31 @@ namespace Ombi.Schedule.Tests
|
|||
Assert.That(issues[1].Status, Is.EqualTo(IssueStatus.Deleted));
|
||||
Repo.Verify(x => x.SaveChangesAsync(), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DoesNot_Delete_AnyIssues()
|
||||
{
|
||||
var issues = new List<Issues>()
|
||||
{
|
||||
new Issues
|
||||
{
|
||||
Status = IssueStatus.Resolved,
|
||||
ResovledDate = DateTime.Now.AddDays(-2)
|
||||
},
|
||||
new Issues
|
||||
{
|
||||
Status = IssueStatus.Resolved,
|
||||
ResovledDate = DateTime.Now.AddDays(-4)
|
||||
}
|
||||
};
|
||||
|
||||
Settings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new IssueSettings { DeleteIssues = true, DaysAfterResolvedToDelete = 5 });
|
||||
Repo.Setup(x => x.GetAll()).Returns(new EnumerableQuery<Issues>(issues));
|
||||
await Job.Start();
|
||||
|
||||
Assert.That(issues[0].Status, Is.Not.EqualTo(IssueStatus.Deleted));
|
||||
Assert.That(issues[1].Status, Is.Not.EqualTo(IssueStatus.Deleted));
|
||||
Repo.Verify(x => x.SaveChangesAsync(), Times.Once);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,11 +6,12 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
|
||||
<PackageReference Include="MockQueryable.Moq" Version="1.1.0" />
|
||||
<PackageReference Include="Moq" Version="4.10.0" />
|
||||
<PackageReference Include="Nunit" Version="3.10.1" />
|
||||
<PackageReference Include="Nunit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.9.0"></packagereference>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="16.0.1"></packagereference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||
using Castle.Components.DictionaryAdapter;
|
||||
using Hangfire;
|
||||
using Moq;
|
||||
using MockQueryable.Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Notifications;
|
||||
using Ombi.Schedule.Jobs.Plex;
|
||||
|
@ -68,7 +69,6 @@ namespace Ombi.Schedule.Tests
|
|||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("EF IAsyncQueryProvider")]
|
||||
public async Task ProcessTv_ShouldMark_Episode_Available_WhenInPlex()
|
||||
{
|
||||
var request = new ChildRequests
|
||||
|
@ -90,21 +90,25 @@ namespace Ombi.Schedule.Tests
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
RequestedUser = new OmbiUser
|
||||
{
|
||||
Email = "abc"
|
||||
}
|
||||
};
|
||||
_tv.Setup(x => x.GetChild()).Returns(new List<ChildRequests> { request }.AsQueryable());
|
||||
_tv.Setup(x => x.GetChild()).Returns(new List<ChildRequests> { request }.AsQueryable().BuildMock().Object);
|
||||
_repo.Setup(x => x.GetAllEpisodes()).Returns(new List<PlexEpisode>
|
||||
{
|
||||
new PlexEpisode
|
||||
{
|
||||
Series = new PlexServerContent
|
||||
{
|
||||
ImdbId = 1.ToString(),
|
||||
TvDbId = 1.ToString(),
|
||||
},
|
||||
EpisodeNumber = 1,
|
||||
SeasonNumber = 2
|
||||
}
|
||||
}.AsQueryable);
|
||||
}.AsQueryable().BuildMock().Object);
|
||||
_repo.Setup(x => x.Include(It.IsAny<IQueryable<PlexEpisode>>(),It.IsAny<Expression<Func<PlexEpisode, PlexServerContent>>>()));
|
||||
|
||||
await Checker.Start();
|
||||
|
|
|
@ -81,7 +81,6 @@ namespace Ombi.Schedule
|
|||
RecurringJob.AddOrUpdate(() => _embyUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||
RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||
RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
||||
RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
||||
RecurringJob.AddOrUpdate(() => _resender.Start(), JobSettingsHelper.ResendFailedRequests(s));
|
||||
RecurringJob.AddOrUpdate(() => _mediaDatabaseRefresh.Start(), JobSettingsHelper.MediaDatabaseRefresh(s));
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
_repo = repo;
|
||||
_episodeSync = epSync;
|
||||
_metadata = metadata;
|
||||
_settings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly ILogger<EmbyContentSync> _logger;
|
||||
|
|
|
@ -49,7 +49,6 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
_settings = s;
|
||||
_repo = repo;
|
||||
_avaliabilityChecker = checker;
|
||||
_settings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly ISettingsService<EmbySettings> _settings;
|
||||
|
|
|
@ -50,8 +50,6 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
_log = log;
|
||||
_embySettings = embySettings;
|
||||
_userManagementSettings = ums;
|
||||
_userManagementSettings.ClearCache();
|
||||
_embySettings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly IEmbyApi _api;
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Lidarr;
|
||||
using Ombi.Api.Radarr;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Serilog;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Lidarr
|
||||
|
@ -29,7 +26,6 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
|||
_ctx = ctx;
|
||||
_job = job;
|
||||
_availability = availability;
|
||||
_lidarrSettings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Lidarr;
|
||||
using Ombi.Api.Radarr;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Serilog;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Lidarr
|
||||
|
@ -29,7 +26,6 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
|||
_ctx = ctx;
|
||||
_job = background;
|
||||
_albumSync = album;
|
||||
_lidarrSettings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||
|
|
|
@ -28,9 +28,10 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
return;
|
||||
}
|
||||
|
||||
var now = DateTime.Now.AddDays(-settings.DaysAfterResolvedToDelete).Date;
|
||||
var today = DateTime.UtcNow.Date;
|
||||
|
||||
var resolved = _issuesRepository.GetAll().Where(x => x.Status == IssueStatus.Resolved);
|
||||
var toDelete = resolved.Where(x => x.ResovledDate.HasValue && x.ResovledDate.Value.Date <= now);
|
||||
var toDelete = resolved.Where(x => x.ResovledDate.HasValue && (today - x.ResovledDate.Value.Date).TotalDays >= settings.DaysAfterResolvedToDelete);
|
||||
|
||||
foreach (var d in toDelete)
|
||||
{
|
||||
|
|
|
@ -10,28 +10,23 @@ using Ombi.Schedule.Jobs.Emby;
|
|||
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
||||
using Ombi.Store.Repository;
|
||||
|
||||
namespace Ombi.Schedule.Jobs.Plex
|
||||
namespace Ombi.Schedule.Jobs.Ombi
|
||||
{
|
||||
public class MediaDatabaseRefresh : IMediaDatabaseRefresh
|
||||
{
|
||||
public MediaDatabaseRefresh(ISettingsService<PlexSettings> s, ILogger<MediaDatabaseRefresh> log, IPlexApi plexApi,
|
||||
IPlexContentRepository plexRepo, IPlexContentSync c, IEmbyContentRepository embyRepo, IEmbyContentSync embySync)
|
||||
public MediaDatabaseRefresh(ISettingsService<PlexSettings> s, ILogger<MediaDatabaseRefresh> log,
|
||||
IPlexContentRepository plexRepo, IEmbyContentRepository embyRepo, IEmbyContentSync embySync)
|
||||
{
|
||||
_settings = s;
|
||||
_log = log;
|
||||
_api = plexApi;
|
||||
_plexRepo = plexRepo;
|
||||
_plexContentSync = c;
|
||||
_embyRepo = embyRepo;
|
||||
_embyContentSync = embySync;
|
||||
_settings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly ISettingsService<PlexSettings> _settings;
|
||||
private readonly ILogger _log;
|
||||
private readonly IPlexApi _api;
|
||||
private readonly IPlexContentRepository _plexRepo;
|
||||
private readonly IPlexContentSync _plexContentSync;
|
||||
private readonly IEmbyContentRepository _embyRepo;
|
||||
private readonly IEmbyContentSync _embyContentSync;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ using Ombi.Api.TheMovieDb;
|
|||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Api.TvMaze;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Notifications;
|
||||
using Ombi.Notifications.Models;
|
||||
|
@ -36,7 +37,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
ISettingsService<EmailNotificationSettings> emailSettings, INotificationTemplatesRepository templateRepo,
|
||||
UserManager<OmbiUser> um, ISettingsService<NewsletterSettings> newsletter, ILogger<NewsletterJob> log,
|
||||
ILidarrApi lidarrApi, IRepository<LidarrAlbumCache> albumCache, ISettingsService<LidarrSettings> lidarrSettings,
|
||||
ISettingsService<OmbiSettings> ombiSettings)
|
||||
ISettingsService<OmbiSettings> ombiSettings, ISettingsService<PlexSettings> plexSettings, ISettingsService<EmbySettings> embySettings)
|
||||
{
|
||||
_plex = plex;
|
||||
_emby = emby;
|
||||
|
@ -49,16 +50,13 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
_emailSettings = emailSettings;
|
||||
_newsletterSettings = newsletter;
|
||||
_userManager = um;
|
||||
_emailSettings.ClearCache();
|
||||
_customizationSettings.ClearCache();
|
||||
_newsletterSettings.ClearCache();
|
||||
_log = log;
|
||||
_lidarrApi = lidarrApi;
|
||||
_lidarrAlbumRepository = albumCache;
|
||||
_lidarrSettings = lidarrSettings;
|
||||
_ombiSettings = ombiSettings;
|
||||
_ombiSettings.ClearCache();
|
||||
_lidarrSettings.ClearCache();
|
||||
_plexSettings = plexSettings;
|
||||
_embySettings = embySettings;
|
||||
}
|
||||
|
||||
private readonly IPlexContentRepository _plex;
|
||||
|
@ -77,6 +75,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
private readonly ILidarrApi _lidarrApi;
|
||||
private readonly IRepository<LidarrAlbumCache> _lidarrAlbumRepository;
|
||||
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||
private readonly ISettingsService<PlexSettings> _plexSettings;
|
||||
private readonly ISettingsService<EmbySettings> _embySettings;
|
||||
|
||||
public async Task Start(NewsletterSettings settings, bool test)
|
||||
{
|
||||
|
@ -132,6 +132,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
|
||||
_log.LogInformation("Plex Episodes to send: {0}", plexEpisodesToSend.Count());
|
||||
_log.LogInformation("Emby Episodes to send: {0}", embyEpisodesToSend.Count());
|
||||
var plexSettings = await _plexSettings.GetSettingsAsync();
|
||||
var embySettings = await _embySettings.GetSettingsAsync();
|
||||
var body = string.Empty;
|
||||
if (test)
|
||||
{
|
||||
|
@ -140,11 +142,11 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
var plext = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet();
|
||||
var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
|
||||
var lidarr = lidarrContent.OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
|
||||
body = await BuildHtml(plexm, embym, plext, embyt, lidarr, settings);
|
||||
body = await BuildHtml(plexm, embym, plext, embyt, lidarr, settings, embySettings, plexSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, lidarrContentAlbumsToSend, settings);
|
||||
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, lidarrContentAlbumsToSend, settings, embySettings, plexSettings);
|
||||
if (body.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
|
@ -333,7 +335,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
}
|
||||
|
||||
private async Task<string> BuildHtml(IQueryable<PlexServerContent> plexContentToSend, IQueryable<EmbyContent> embyContentToSend,
|
||||
HashSet<PlexEpisode> plexEpisodes, HashSet<EmbyEpisode> embyEp, HashSet<LidarrAlbumCache> albums, NewsletterSettings settings)
|
||||
HashSet<PlexEpisode> plexEpisodes, HashSet<EmbyEpisode> embyEp, HashSet<LidarrAlbumCache> albums, NewsletterSettings settings, EmbySettings embySettings,
|
||||
PlexSettings plexSettings)
|
||||
{
|
||||
var ombiSettings = await _ombiSettings.GetSettingsAsync();
|
||||
var sb = new StringBuilder();
|
||||
|
@ -349,8 +352,16 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
sb.Append("<td style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 14px; vertical-align: top; \">");
|
||||
sb.Append("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; \">");
|
||||
sb.Append("<tr>");
|
||||
await ProcessPlexMovies(plexMovies, sb, ombiSettings.DefaultLanguageCode);
|
||||
await ProcessEmbyMovies(embyMovies, sb, ombiSettings.DefaultLanguageCode);
|
||||
if (plexSettings.Enable)
|
||||
{
|
||||
await ProcessPlexMovies(plexMovies, sb, ombiSettings.DefaultLanguageCode);
|
||||
}
|
||||
|
||||
if (embySettings.Enable)
|
||||
{
|
||||
await ProcessEmbyMovies(embyMovies, sb, ombiSettings.DefaultLanguageCode);
|
||||
}
|
||||
|
||||
sb.Append("</tr>");
|
||||
sb.Append("</table>");
|
||||
sb.Append("</td>");
|
||||
|
@ -367,8 +378,16 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
sb.Append("<td style=\"font-family: 'Open Sans', Helvetica, Arial, sans-serif; font-size: 14px; vertical-align: top; \">");
|
||||
sb.Append("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; \">");
|
||||
sb.Append("<tr>");
|
||||
await ProcessPlexTv(plexEpisodes, sb);
|
||||
await ProcessEmbyTv(embyEp, sb);
|
||||
if (plexSettings.Enable)
|
||||
{
|
||||
await ProcessPlexTv(plexEpisodes, sb);
|
||||
}
|
||||
|
||||
if (embySettings.Enable)
|
||||
{
|
||||
await ProcessEmbyTv(embyEp, sb);
|
||||
}
|
||||
|
||||
sb.Append("</tr>");
|
||||
sb.Append("</table>");
|
||||
sb.Append("</td>");
|
||||
|
|
|
@ -5,18 +5,13 @@ using System.IO;
|
|||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Hangfire.Console;
|
||||
using Hangfire.Server;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Ombi.Api.Service;
|
||||
using Ombi.Api.Service.Models;
|
||||
using Ombi.Core.Processor;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
|
@ -40,7 +35,6 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
Settings = s;
|
||||
_processProvider = proc;
|
||||
_appConfig = appConfig;
|
||||
Settings.ClearCache();
|
||||
}
|
||||
|
||||
private ILogger<OmbiAutomaticUpdater> Logger { get; }
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Emby;
|
||||
using Ombi.Api.TheMovieDb;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Api.TvMaze;
|
||||
|
@ -21,7 +22,8 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
public RefreshMetadata(IPlexContentRepository plexRepo, IEmbyContentRepository embyRepo,
|
||||
ILogger<RefreshMetadata> log, ITvMazeApi tvApi, ISettingsService<PlexSettings> plexSettings,
|
||||
IMovieDbApi movieApi, ISettingsService<EmbySettings> embySettings, IPlexAvailabilityChecker plexAvailability, IEmbyAvaliabilityChecker embyAvaliability)
|
||||
IMovieDbApi movieApi, ISettingsService<EmbySettings> embySettings, IPlexAvailabilityChecker plexAvailability, IEmbyAvaliabilityChecker embyAvaliability,
|
||||
IEmbyApi embyApi)
|
||||
{
|
||||
_plexRepo = plexRepo;
|
||||
_embyRepo = embyRepo;
|
||||
|
@ -32,6 +34,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
_embySettings = embySettings;
|
||||
_plexAvailabilityChecker = plexAvailability;
|
||||
_embyAvaliabilityChecker = embyAvaliability;
|
||||
_embyApi = embyApi;
|
||||
}
|
||||
|
||||
private readonly IPlexContentRepository _plexRepo;
|
||||
|
@ -43,6 +46,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
private readonly ITvMazeApi _tvApi;
|
||||
private readonly ISettingsService<PlexSettings> _plexSettings;
|
||||
private readonly ISettingsService<EmbySettings> _embySettings;
|
||||
private readonly IEmbyApi _embyApi;
|
||||
|
||||
public async Task Start()
|
||||
{
|
||||
|
@ -54,11 +58,11 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
await StartPlex();
|
||||
}
|
||||
|
||||
|
||||
var embySettings = await _embySettings.GetSettingsAsync();
|
||||
if (embySettings.Enable)
|
||||
{
|
||||
await StartEmby();
|
||||
await StartEmby(embySettings);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -123,9 +127,9 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
await StartPlexTv(allTv);
|
||||
}
|
||||
|
||||
private async Task StartEmby()
|
||||
private async Task StartEmby(EmbySettings s)
|
||||
{
|
||||
await StartEmbyMovies();
|
||||
await StartEmbyMovies(s);
|
||||
await StartEmbyTv();
|
||||
}
|
||||
|
||||
|
@ -158,7 +162,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
_plexRepo.UpdateWithoutSave(show);
|
||||
}
|
||||
tvCount++;
|
||||
if (tvCount >= 20)
|
||||
if (tvCount >= 75)
|
||||
{
|
||||
await _plexRepo.SaveChangesAsync();
|
||||
tvCount = 0;
|
||||
|
@ -198,7 +202,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
_embyRepo.UpdateWithoutSave(show);
|
||||
}
|
||||
tvCount++;
|
||||
if (tvCount >= 20)
|
||||
if (tvCount >= 75)
|
||||
{
|
||||
await _embyRepo.SaveChangesAsync();
|
||||
tvCount = 0;
|
||||
|
@ -229,7 +233,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
_plexRepo.UpdateWithoutSave(movie);
|
||||
}
|
||||
movieCount++;
|
||||
if (movieCount >= 20)
|
||||
if (movieCount >= 75)
|
||||
{
|
||||
await _plexRepo.SaveChangesAsync();
|
||||
movieCount = 0;
|
||||
|
@ -239,31 +243,56 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
await _plexRepo.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task StartEmbyMovies()
|
||||
private async Task StartEmbyMovies(EmbySettings settings)
|
||||
{
|
||||
var allMovies = _embyRepo.GetAll().Where(x =>
|
||||
x.Type == EmbyMediaType.Movie && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue()));
|
||||
int movieCount = 0;
|
||||
foreach (var movie in allMovies)
|
||||
{
|
||||
var hasImdb = movie.ImdbId.HasValue();
|
||||
var hasTheMovieDb = movie.TheMovieDbId.HasValue();
|
||||
movie.ImdbId.HasValue();
|
||||
movie.TheMovieDbId.HasValue();
|
||||
// Movies don't really use TheTvDb
|
||||
|
||||
if (!hasImdb)
|
||||
// Check if it even has 1 ID
|
||||
if (!movie.HasImdb && !movie.HasTheMovieDb)
|
||||
{
|
||||
var imdbId = await GetImdbId(hasTheMovieDb, false, movie.Title, movie.TheMovieDbId, string.Empty);
|
||||
// Ok this sucks,
|
||||
// The only think I can think that has happened is that we scanned Emby before Emby has got the metadata
|
||||
// So let's recheck emby to see if they have got the metadata now
|
||||
_log.LogInformation($"Movie {movie.Title} does not have a ImdbId or TheMovieDbId, so rechecking emby");
|
||||
foreach (var server in settings.Servers)
|
||||
{
|
||||
_log.LogInformation($"Checking server {server.Name} for upto date metadata");
|
||||
var movieInfo = await _embyApi.GetMovieInformation(movie.EmbyId, server.ApiKey, server.AdministratorId,
|
||||
server.FullUri);
|
||||
|
||||
if (movieInfo.ProviderIds?.Imdb.HasValue() ?? false)
|
||||
{
|
||||
movie.ImdbId = movieInfo.ProviderIds.Imdb;
|
||||
}
|
||||
|
||||
if (movieInfo.ProviderIds?.Tmdb.HasValue() ?? false)
|
||||
{
|
||||
movie.TheMovieDbId = movieInfo.ProviderIds.Tmdb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!movie.HasImdb)
|
||||
{
|
||||
var imdbId = await GetImdbId(movie.HasTheMovieDb, false, movie.Title, movie.TheMovieDbId, string.Empty);
|
||||
movie.ImdbId = imdbId;
|
||||
_embyRepo.UpdateWithoutSave(movie);
|
||||
}
|
||||
if (!hasTheMovieDb)
|
||||
if (!movie.HasTheMovieDb)
|
||||
{
|
||||
var id = await GetTheMovieDbId(false, hasImdb, string.Empty, movie.ImdbId, movie.Title, true);
|
||||
var id = await GetTheMovieDbId(false, movie.HasImdb, string.Empty, movie.ImdbId, movie.Title, true);
|
||||
movie.TheMovieDbId = id;
|
||||
_embyRepo.UpdateWithoutSave(movie);
|
||||
}
|
||||
movieCount++;
|
||||
if (movieCount >= 20)
|
||||
if (movieCount >= 75)
|
||||
{
|
||||
await _embyRepo.SaveChangesAsync();
|
||||
movieCount = 0;
|
||||
|
|
|
@ -20,8 +20,6 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
_email = provider;
|
||||
_templates = template;
|
||||
_customizationSettings = c;
|
||||
email.ClearCache();
|
||||
_customizationSettings.ClearCache();
|
||||
}
|
||||
|
||||
private readonly ISettingsService<EmailNotificationSettings> _emailSettings;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue