mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-30 11:38:32 -07:00
Merge branch 'develop' into feature/jellyfin-libs
This commit is contained in:
commit
132c935c28
261 changed files with 8133 additions and 1639 deletions
|
@ -27,4 +27,4 @@ variables:
|
|||
value: "4.0.$(Build.BuildId)"
|
||||
|
||||
- name: isMain
|
||||
value: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/develop'), eq(variables['Build.SourceBranch'], 'refs/heads/main'))]
|
||||
value: $[or(eq(variables['Build.SourceBranch'], 'refs/heads/develop'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))]
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -247,5 +247,6 @@ _Pvt_Extensions
|
|||
# Ignore local vscode config
|
||||
*.vscode
|
||||
/src/Ombi/database.json
|
||||
/src/Ombi/databases.json
|
||||
/src/Ombi/healthchecksdb
|
||||
/src/Ombi/ClientApp/package-lock.json
|
||||
|
|
|
@ -40,8 +40,8 @@ Search the existing requests to see if your suggestion has already been submitte
|
|||
___
|
||||
<a href='https://play.google.com/store/apps/details?id=com.tidusjar.Ombi&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img width="150" alt='Get it on Google Play' src='https://play.google.com/intl/en_gb/badges/images/generic/en_badge_web_generic.png'/></a>
|
||||
<br>
|
||||
_**Note:** There is no longer an iOS app due to complications outside of our control._
|
||||
|
||||
<a href='https://apps.apple.com/us/app/ombi/id1335260043'><img width="130" alt='Get it on the App Store' src='https://developer.apple.com/app-store/marketing/guidelines/images/badge-example-preferred.png'/></a>
|
||||
<br>
|
||||
|
||||
# Features
|
||||
Here are some of the features Ombi has:
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace Ombi.Api.Plex
|
|||
Task<PlexFriends> GetUsers(string authToken);
|
||||
Task<PlexAccount> GetAccount(string authToken);
|
||||
Task<PlexMetadata> GetRecentlyAdded(string authToken, string uri, string sectionId);
|
||||
Task<OAuthPin> GetPin(int pinId);
|
||||
Task<OAuthContainer> GetPin(int pinId);
|
||||
Task<Uri> GetOAuthUrl(string code, string applicationUrl);
|
||||
Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Api.Plex.Models.OAuth
|
||||
{
|
||||
public class OAuthContainer
|
||||
{
|
||||
public OAuthPin Result { get; set; }
|
||||
public OAuthErrorsContainer Errors { get; set; }
|
||||
}
|
||||
|
||||
public class OAuthPin
|
||||
{
|
||||
public int id { get; set; }
|
||||
|
@ -24,4 +31,15 @@ namespace Ombi.Api.Plex.Models.OAuth
|
|||
public string coordinates { get; set; }
|
||||
}
|
||||
|
||||
public class OAuthErrorsContainer
|
||||
{
|
||||
public List<OAuthErrors> errors { get; set; }
|
||||
}
|
||||
|
||||
public class OAuthErrors
|
||||
{
|
||||
public int code { get; set; }
|
||||
public string message { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Ombi.Api.Plex.Models;
|
||||
using Ombi.Api.Plex.Models.Friends;
|
||||
using Ombi.Api.Plex.Models.OAuth;
|
||||
|
@ -208,12 +208,28 @@ namespace Ombi.Api.Plex
|
|||
return await Api.Request<PlexMetadata>(request);
|
||||
}
|
||||
|
||||
public async Task<OAuthPin> GetPin(int pinId)
|
||||
public async Task<OAuthContainer> GetPin(int pinId)
|
||||
{
|
||||
var request = new Request($"api/v2/pins/{pinId}", "https://plex.tv/", HttpMethod.Get);
|
||||
await AddHeaders(request);
|
||||
|
||||
return await Api.Request<OAuthPin>(request);
|
||||
var response = await Api.RequestContent(request);
|
||||
|
||||
if (response.Contains("errors"))
|
||||
{
|
||||
var errors = JsonConvert.DeserializeObject<OAuthErrorsContainer>(response, Ombi.Api.Api.Settings);
|
||||
return new OAuthContainer
|
||||
{
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
var pinResult = JsonConvert.DeserializeObject<OAuthPin>(response, Ombi.Api.Api.Settings);
|
||||
|
||||
return new OAuthContainer
|
||||
{
|
||||
Result = pinResult
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<Uri> GetOAuthUrl(string code, string applicationUrl)
|
||||
|
|
|
@ -1,39 +1,122 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Mime;
|
||||
|
||||
namespace Ombi.Api.Radarr.Models
|
||||
{
|
||||
{
|
||||
public class MovieResponse
|
||||
{
|
||||
public string title { get; set; }
|
||||
public string originalTitle { get; set; }
|
||||
public Alternatetitle[] alternateTitles { get; set; }
|
||||
public int secondaryYearSourceId { get; set; }
|
||||
public string sortTitle { get; set; }
|
||||
public double sizeOnDisk { get; set; }
|
||||
public long sizeOnDisk { get; set; }
|
||||
public string status { get; set; }
|
||||
public string overview { get; set; }
|
||||
public string inCinemas { get; set; }
|
||||
public string physicalRelease { get; set; }
|
||||
public List<Image> images { get; set; }
|
||||
public DateTime inCinemas { get; set; }
|
||||
public DateTime physicalRelease { get; set; }
|
||||
public DateTime digitalRelease { get; set; }
|
||||
public Image[] images { get; set; }
|
||||
public string website { get; set; }
|
||||
public bool downloaded { get; set; }
|
||||
public int year { get; set; }
|
||||
public bool hasFile { get; set; }
|
||||
public string youTubeTrailerId { get; set; }
|
||||
public string studio { get; set; }
|
||||
public string path { get; set; }
|
||||
public int profileId { get; set; }
|
||||
public string minimumAvailability { get; set; }
|
||||
public int qualityProfileId { get; set; }
|
||||
public bool monitored { get; set; }
|
||||
public string minimumAvailability { get; set; }
|
||||
public bool isAvailable { get; set; }
|
||||
public string folderName { get; set; }
|
||||
public int runtime { get; set; }
|
||||
public string lastInfoSync { get; set; }
|
||||
public string cleanTitle { get; set; }
|
||||
public string imdbId { get; set; }
|
||||
public int tmdbId { get; set; }
|
||||
public string titleSlug { get; set; }
|
||||
public List<string> genres { get; set; }
|
||||
public List<object> tags { get; set; }
|
||||
public string added { get; set; }
|
||||
public string certification { get; set; }
|
||||
public string[] genres { get; set; }
|
||||
public object[] tags { get; set; }
|
||||
public DateTime added { get; set; }
|
||||
public Ratings ratings { get; set; }
|
||||
//public List<string> alternativeTitles { get; set; }
|
||||
public int qualityProfileId { get; set; }
|
||||
public Moviefile movieFile { get; set; }
|
||||
public Collection collection { get; set; }
|
||||
public int id { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class Moviefile
|
||||
{
|
||||
public int movieId { get; set; }
|
||||
public string relativePath { get; set; }
|
||||
public string path { get; set; }
|
||||
public long size { get; set; }
|
||||
public DateTime dateAdded { get; set; }
|
||||
public string sceneName { get; set; }
|
||||
public int indexerFlags { get; set; }
|
||||
public V3.Quality quality { get; set; }
|
||||
public Mediainfo mediaInfo { get; set; }
|
||||
public string originalFilePath { get; set; }
|
||||
public bool qualityCutoffNotMet { get; set; }
|
||||
public Language[] languages { get; set; }
|
||||
public string releaseGroup { get; set; }
|
||||
public string edition { get; set; }
|
||||
public int id { get; set; }
|
||||
}
|
||||
|
||||
public class Revision
|
||||
{
|
||||
public int version { get; set; }
|
||||
public int real { get; set; }
|
||||
public bool isRepack { get; set; }
|
||||
}
|
||||
|
||||
public class Mediainfo
|
||||
{
|
||||
public string audioAdditionalFeatures { get; set; }
|
||||
public int audioBitrate { get; set; }
|
||||
public float audioChannels { get; set; }
|
||||
public string audioCodec { get; set; }
|
||||
public string audioLanguages { get; set; }
|
||||
public int audioStreamCount { get; set; }
|
||||
public int videoBitDepth { get; set; }
|
||||
public int videoBitrate { get; set; }
|
||||
public string videoCodec { get; set; }
|
||||
public float videoFps { get; set; }
|
||||
public string resolution { get; set; }
|
||||
public string runTime { get; set; }
|
||||
public string scanType { get; set; }
|
||||
public string subtitles { get; set; }
|
||||
}
|
||||
|
||||
public class Language
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string name { get; set; }
|
||||
}
|
||||
|
||||
public class Collection
|
||||
{
|
||||
public string name { get; set; }
|
||||
public int tmdbId { get; set; }
|
||||
public object[] images { get; set; }
|
||||
}
|
||||
|
||||
public class Alternatetitle
|
||||
{
|
||||
public string sourceType { get; set; }
|
||||
public int movieId { get; set; }
|
||||
public string title { get; set; }
|
||||
public int sourceId { get; set; }
|
||||
public int votes { get; set; }
|
||||
public int voteCount { get; set; }
|
||||
public Language1 language { get; set; }
|
||||
public int id { get; set; }
|
||||
}
|
||||
|
||||
public class Language1
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string name { get; set; }
|
||||
}
|
||||
}
|
|
@ -28,5 +28,6 @@ namespace Ombi.Api.Radarr.Models
|
|||
public string titleSlug { get; set; }
|
||||
public int year { get; set; }
|
||||
public string minimumAvailability { get; set; }
|
||||
public long sizeOnDisk { get; set; }
|
||||
}
|
||||
}
|
|
@ -82,7 +82,8 @@ namespace Ombi.Api.Radarr
|
|||
titleSlug = title + year,
|
||||
monitored = true,
|
||||
year = year,
|
||||
minimumAvailability = minimumAvailability
|
||||
minimumAvailability = minimumAvailability,
|
||||
sizeOnDisk = 0
|
||||
};
|
||||
|
||||
if (searchNow)
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace Ombi.Api.Radarr
|
|||
|
||||
public async Task<SystemStatus> SystemStatus(string apiKey, string baseUrl)
|
||||
{
|
||||
var request = new Request("/api/v3/status", baseUrl, HttpMethod.Get);
|
||||
var request = new Request("/api/v3/system/status", baseUrl, HttpMethod.Get);
|
||||
AddHeaders(request, apiKey);
|
||||
|
||||
return await Api.Request<SystemStatus>(request);
|
||||
|
@ -65,7 +65,7 @@ namespace Ombi.Api.Radarr
|
|||
|
||||
public async Task<MovieResponse> UpdateMovie(MovieResponse movie, string apiKey, string baseUrl)
|
||||
{
|
||||
var request = new Request($"/api/v3/movie/", baseUrl, HttpMethod.Put);
|
||||
var request = new Request($"/api/v3/movie/{movie.id}", baseUrl, HttpMethod.Put);
|
||||
AddHeaders(request, apiKey);
|
||||
request.AddJsonBody(movie);
|
||||
|
||||
|
@ -85,7 +85,8 @@ namespace Ombi.Api.Radarr
|
|||
titleSlug = title + year,
|
||||
monitored = true,
|
||||
year = year,
|
||||
minimumAvailability = minimumAvailability
|
||||
minimumAvailability = minimumAvailability,
|
||||
sizeOnDisk = 0
|
||||
};
|
||||
|
||||
if (searchNow)
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Ombi.Api.Webhook
|
|||
|
||||
public async Task PushAsync(string baseUrl, string accessToken, IDictionary<string, string> parameters)
|
||||
{
|
||||
var request = new Request("/", baseUrl, HttpMethod.Post);
|
||||
var request = new Request("", baseUrl, HttpMethod.Post);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(accessToken))
|
||||
{
|
||||
|
|
|
@ -16,14 +16,14 @@ namespace Ombi.Api
|
|||
{
|
||||
public class Api : IApi
|
||||
{
|
||||
public Api(ILogger<Api> log, IOmbiHttpClient client)
|
||||
public Api(ILogger<Api> log, HttpClient client)
|
||||
{
|
||||
Logger = log;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
private ILogger<Api> Logger { get; }
|
||||
private readonly IOmbiHttpClient _client;
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
|
||||
{
|
||||
|
@ -73,7 +73,7 @@ namespace Ombi.Api
|
|||
}
|
||||
|
||||
// do something with the response
|
||||
var receivedString = await httpResponseMessage.Content.ReadAsStringAsync();
|
||||
var receivedString = await httpResponseMessage.Content.ReadAsStringAsync(cancellationToken);
|
||||
LogDebugContent(receivedString);
|
||||
if (request.ContentType == ContentType.Json)
|
||||
{
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Api
|
||||
{
|
||||
public interface IOmbiHttpClient
|
||||
{
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request);
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
|
||||
Task<string> GetStringAsync(Uri requestUri);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Polly" Version="7.1.0" />
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: OmbiHttpClient.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
|
||||
namespace Ombi.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// The purpose of this class is simple, keep one instance of the HttpClient in play.
|
||||
/// There are many articles related to when using multiple HttpClient's keeping the socket in a WAIT state
|
||||
/// https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/
|
||||
/// https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
|
||||
/// </summary>
|
||||
public class OmbiHttpClient : IOmbiHttpClient
|
||||
{
|
||||
public OmbiHttpClient(ICacheService cache, ISettingsService<OmbiSettings> s)
|
||||
{
|
||||
_cache = cache;
|
||||
_settings = s;
|
||||
_runtimeVersion = AssemblyHelper.GetRuntimeVersion();
|
||||
}
|
||||
|
||||
private static HttpClient _client;
|
||||
private static HttpMessageHandler _handler;
|
||||
|
||||
private readonly ICacheService _cache;
|
||||
private readonly ISettingsService<OmbiSettings> _settings;
|
||||
private readonly string _runtimeVersion;
|
||||
|
||||
|
||||
public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
|
||||
{
|
||||
await Setup();
|
||||
return await _client.SendAsync(request);
|
||||
}
|
||||
|
||||
public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
await Setup();
|
||||
return await _client.SendAsync(request, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<string> GetStringAsync(Uri requestUri)
|
||||
{
|
||||
await Setup();
|
||||
return await _client.GetStringAsync(requestUri);
|
||||
}
|
||||
|
||||
private async Task Setup()
|
||||
{
|
||||
if (_client == null)
|
||||
{
|
||||
if (_handler == null)
|
||||
{
|
||||
// Get the handler
|
||||
_handler = await GetHandler();
|
||||
}
|
||||
_client = new HttpClient(_handler);
|
||||
_client.DefaultRequestHeaders.Add("User-Agent", $"Ombi/{_runtimeVersion} (https://ombi.io/)");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<HttpMessageHandler> GetHandler()
|
||||
{
|
||||
if (_cache == null)
|
||||
{
|
||||
return new HttpClientHandler();
|
||||
}
|
||||
var settings = await _cache.GetOrAdd(CacheKeys.OmbiSettings, async () => await _settings.GetSettingsAsync(), DateTime.Now.AddHours(1));
|
||||
if (settings.IgnoreCertificateErrors)
|
||||
{
|
||||
return new HttpClientHandler
|
||||
{
|
||||
ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true,
|
||||
};
|
||||
}
|
||||
return new HttpClientHandler();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -42,8 +42,9 @@ namespace Ombi.Core.Tests.Engine.V2
|
|||
var cache = new Mock<ICacheService>();
|
||||
var ombiSettings = new Mock<ISettingsService<OmbiSettings>>();
|
||||
var requestSubs = new Mock<IRepository<RequestSubscription>>();
|
||||
var mediaCache = new Mock<IMediaCacheService>();
|
||||
_engine = new MovieRequestEngine(movieApi.Object, requestService.Object, user.Object, notificationHelper.Object, rules.Object, movieSender.Object,
|
||||
logger.Object, userManager.Object, requestLogRepo.Object, cache.Object, ombiSettings.Object, requestSubs.Object);
|
||||
logger.Object, userManager.Object, requestLogRepo.Object, cache.Object, ombiSettings.Object, requestSubs.Object, mediaCache.Object);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
209
src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs
Normal file
209
src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs
Normal file
|
@ -0,0 +1,209 @@
|
|||
using MockQueryable.Moq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Rule.Rules.Request;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Core.Tests.Rule.Request
|
||||
{
|
||||
[TestFixture]
|
||||
public class ExistingPlexRequestRuleTests
|
||||
{
|
||||
private ExistingPlexRequestRule Rule;
|
||||
private Mock<IPlexContentRepository> PlexContentRepo;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
PlexContentRepo = new Mock<IPlexContentRepository>();
|
||||
Rule = new ExistingPlexRequestRule(PlexContentRepo.Object);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RequestShow_DoesNotExistAtAll_IsSuccessful()
|
||||
{
|
||||
PlexContentRepo.Setup(x => x.GetAll()).Returns(new List<PlexServerContent>().AsQueryable().BuildMock().Object);
|
||||
var req = new ChildRequests
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 1,
|
||||
}
|
||||
},
|
||||
SeasonNumber = 1
|
||||
}
|
||||
}
|
||||
};
|
||||
var result = await Rule.Execute(req);
|
||||
|
||||
|
||||
Assert.That(result.Success, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RequestShow_AllEpisodesAreaRequested_IsNotSuccessful()
|
||||
{
|
||||
SetupMockData();
|
||||
|
||||
var req = new ChildRequests
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 1,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 2,
|
||||
},
|
||||
},
|
||||
SeasonNumber = 1
|
||||
}
|
||||
},
|
||||
Id = 1,
|
||||
};
|
||||
var result = await Rule.Execute(req);
|
||||
|
||||
|
||||
Assert.That(result.Success, Is.False);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async Task RequestShow_SomeEpisodesAreaRequested_IsSuccessful()
|
||||
{
|
||||
SetupMockData();
|
||||
|
||||
var req = new ChildRequests
|
||||
{
|
||||
RequestType = RequestType.TvShow,
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 1,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 2,
|
||||
EpisodeNumber = 2,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 3,
|
||||
EpisodeNumber = 3,
|
||||
},
|
||||
},
|
||||
SeasonNumber = 1
|
||||
}
|
||||
},
|
||||
Id = 1,
|
||||
};
|
||||
var result = await Rule.Execute(req);
|
||||
|
||||
|
||||
Assert.That(result.Success, Is.True);
|
||||
|
||||
var episodes = req.SeasonRequests.SelectMany(x => x.Episodes);
|
||||
Assert.That(episodes.Count() == 1, "We didn't remove the episodes that have already been requested!");
|
||||
Assert.That(episodes.First().EpisodeNumber == 3, "We removed the wrong episode");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RequestShow_NewSeasonRequest_IsSuccessful()
|
||||
{
|
||||
SetupMockData();
|
||||
|
||||
var req = new ChildRequests
|
||||
{
|
||||
RequestType = RequestType.TvShow,
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 1,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 2,
|
||||
EpisodeNumber = 2,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 3,
|
||||
EpisodeNumber = 3,
|
||||
},
|
||||
},
|
||||
SeasonNumber = 2
|
||||
}
|
||||
},
|
||||
Id = 1,
|
||||
};
|
||||
var result = await Rule.Execute(req);
|
||||
|
||||
Assert.That(result.Success, Is.True);
|
||||
}
|
||||
|
||||
private void SetupMockData()
|
||||
{
|
||||
var childRequests = new List<PlexServerContent>
|
||||
{
|
||||
new PlexServerContent
|
||||
{
|
||||
Type = PlexMediaTypeEntity.Show,
|
||||
TheMovieDbId = "1",
|
||||
Title = "Test",
|
||||
ReleaseYear = "2001",
|
||||
Episodes = new List<PlexEpisode>
|
||||
{
|
||||
new PlexEpisode
|
||||
{
|
||||
EpisodeNumber = 1,
|
||||
Id = 1,
|
||||
SeasonNumber = 1,
|
||||
},
|
||||
new PlexEpisode
|
||||
{
|
||||
EpisodeNumber = 2,
|
||||
Id = 2,
|
||||
SeasonNumber = 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
PlexContentRepo.Setup(x => x.GetAll()).Returns(childRequests.AsQueryable().BuildMock().Object);
|
||||
}
|
||||
}
|
||||
}
|
215
src/Ombi.Core.Tests/Rule/Request/ExistingTvRequestRuleTests.cs
Normal file
215
src/Ombi.Core.Tests/Rule/Request/ExistingTvRequestRuleTests.cs
Normal file
|
@ -0,0 +1,215 @@
|
|||
using MockQueryable.Moq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Core.Rule.Rules.Request;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ombi.Core.Tests.Rule.Request
|
||||
{
|
||||
[TestFixture]
|
||||
public class ExistingTvRequestRuleTests
|
||||
{
|
||||
private ExistingTvRequestRule Rule;
|
||||
private Mock<ITvRequestRepository> TvRequestRepo;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
TvRequestRepo = new Mock<ITvRequestRepository>();
|
||||
Rule = new ExistingTvRequestRule(TvRequestRepo.Object);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RequestShow_DoesNotExistAtAll_IsSuccessful()
|
||||
{
|
||||
TvRequestRepo.Setup(x => x.GetChild()).Returns(new List<ChildRequests>().AsQueryable().BuildMock().Object);
|
||||
var req = new ChildRequests
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 1,
|
||||
}
|
||||
},
|
||||
SeasonNumber = 1
|
||||
}
|
||||
}
|
||||
};
|
||||
var result = await Rule.Execute(req);
|
||||
|
||||
|
||||
Assert.That(result.Success, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RequestShow_AllEpisodesAreaRequested_IsNotSuccessful()
|
||||
{
|
||||
SetupMockData();
|
||||
|
||||
var req = new ChildRequests
|
||||
{
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 1,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 2,
|
||||
},
|
||||
},
|
||||
SeasonNumber = 1
|
||||
}
|
||||
},
|
||||
Id = 1,
|
||||
};
|
||||
var result = await Rule.Execute(req);
|
||||
|
||||
|
||||
Assert.That(result.Success, Is.False);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async Task RequestShow_SomeEpisodesAreaRequested_IsSuccessful()
|
||||
{
|
||||
SetupMockData();
|
||||
|
||||
var req = new ChildRequests
|
||||
{
|
||||
RequestType = RequestType.TvShow,
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 1,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 2,
|
||||
EpisodeNumber = 2,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 3,
|
||||
EpisodeNumber = 3,
|
||||
},
|
||||
},
|
||||
SeasonNumber = 1
|
||||
}
|
||||
},
|
||||
Id = 1,
|
||||
};
|
||||
var result = await Rule.Execute(req);
|
||||
|
||||
|
||||
Assert.That(result.Success, Is.True);
|
||||
|
||||
var episodes = req.SeasonRequests.SelectMany(x => x.Episodes);
|
||||
Assert.That(episodes.Count() == 1, "We didn't remove the episodes that have already been requested!");
|
||||
Assert.That(episodes.First().EpisodeNumber == 3, "We removed the wrong episode");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RequestShow_NewSeasonRequest_IsSuccessful()
|
||||
{
|
||||
SetupMockData();
|
||||
|
||||
var req = new ChildRequests
|
||||
{
|
||||
RequestType = RequestType.TvShow,
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 1,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 2,
|
||||
EpisodeNumber = 2,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 3,
|
||||
EpisodeNumber = 3,
|
||||
},
|
||||
},
|
||||
SeasonNumber = 2
|
||||
}
|
||||
},
|
||||
Id = 1,
|
||||
};
|
||||
var result = await Rule.Execute(req);
|
||||
|
||||
Assert.That(result.Success, Is.True);
|
||||
}
|
||||
|
||||
private void SetupMockData()
|
||||
{
|
||||
var childRequests = new List<ChildRequests>
|
||||
{
|
||||
new ChildRequests
|
||||
{
|
||||
ParentRequest = new TvRequests
|
||||
{
|
||||
Id = 1,
|
||||
ExternalProviderId = 1,
|
||||
},
|
||||
SeasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Id = 1,
|
||||
SeasonNumber = 1,
|
||||
Episodes = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 1,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
Id = 1,
|
||||
EpisodeNumber = 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
TvRequestRepo.Setup(x => x.GetChild()).Returns(childRequests.AsQueryable().BuildMock().Object);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
public async Task Should_Not_Be_Monitored_Or_Available()
|
||||
{
|
||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
var result = await Rule.Execute(request, string.Empty);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
|
@ -49,7 +49,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
var result = await Rule.Execute(request, string.Empty);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
|
@ -71,7 +71,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
var result = await Rule.Execute(request, string.Empty);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
|
@ -93,7 +93,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
var result = await Rule.Execute(request, string.Empty);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
|
@ -114,7 +114,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
var result = await Rule.Execute(request, string.Empty);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Approved);
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
public async Task Should_Not_Be_Monitored()
|
||||
{
|
||||
var request = new SearchArtistViewModel { ForignArtistId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
var result = await Rule.Execute(request, string.Empty);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.False(request.Monitored);
|
||||
|
@ -46,7 +46,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchArtistViewModel { ForignArtistId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
var result = await Rule.Execute(request, string.Empty);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.True(request.Monitored);
|
||||
|
@ -64,7 +64,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
|||
}
|
||||
}.AsQueryable());
|
||||
var request = new SearchArtistViewModel { ForignArtistId = "abc" };
|
||||
var result = await Rule.Execute(request);
|
||||
var result = await Rule.Execute(request, string.Empty);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.True(request.Monitored);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Plex;
|
||||
using Ombi.Api.Plex.Models;
|
||||
using Ombi.Api.Plex.Models.OAuth;
|
||||
|
@ -11,24 +13,37 @@ namespace Ombi.Core.Authentication
|
|||
{
|
||||
public class PlexOAuthManager : IPlexOAuthManager
|
||||
{
|
||||
public PlexOAuthManager(IPlexApi api, ISettingsService<CustomizationSettings> settings)
|
||||
public PlexOAuthManager(IPlexApi api, ISettingsService<CustomizationSettings> settings, ILogger<PlexOAuthManager> logger)
|
||||
{
|
||||
_api = api;
|
||||
_customizationSettingsService = settings;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private readonly IPlexApi _api;
|
||||
private readonly ISettingsService<CustomizationSettings> _customizationSettingsService;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public async Task<string> GetAccessTokenFromPin(int pinId)
|
||||
{
|
||||
var pin = await _api.GetPin(pinId);
|
||||
if (pin.expiresAt < DateTime.UtcNow)
|
||||
if (pin.Errors != null)
|
||||
{
|
||||
foreach (var err in pin.Errors?.errors ?? new List<OAuthErrors>())
|
||||
{
|
||||
_logger.LogError($"Code: '{err.code}' : '{err.message}'");
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return pin.authToken;
|
||||
if (pin.Result.expiresIn <= 0)
|
||||
{
|
||||
_logger.LogError("Pin has expired");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return pin.Result.authToken;
|
||||
}
|
||||
|
||||
public async Task<PlexAccount> GetAccount(string accessToken)
|
||||
|
|
|
@ -48,6 +48,8 @@ namespace Ombi.Core.Engine
|
|||
protected readonly ISettingsService<OmbiSettings> OmbiSettings;
|
||||
protected readonly IRepository<RequestSubscription> _subscriptionRepository;
|
||||
|
||||
private bool _demo = DemoSingleton.Instance.Demo;
|
||||
|
||||
protected async Task<Dictionary<int, MovieRequests>> GetMovieRequests()
|
||||
{
|
||||
var now = DateTime.Now.Ticks;
|
||||
|
@ -125,7 +127,7 @@ namespace Ombi.Core.Engine
|
|||
UserId = user.Id
|
||||
};
|
||||
}
|
||||
var settings = await Cache.GetOrAdd(CacheKeys.OmbiSettings, async () => await OmbiSettings.GetSettingsAsync());
|
||||
var settings = await Cache.GetOrAddAsync(CacheKeys.OmbiSettings, () => OmbiSettings.GetSettingsAsync());
|
||||
var result = new HideResult
|
||||
{
|
||||
Hide = settings.HideRequestsUsers,
|
||||
|
@ -193,6 +195,23 @@ namespace Ombi.Core.Engine
|
|||
return ombiSettings ?? (ombiSettings = await OmbiSettings.GetSettingsAsync());
|
||||
}
|
||||
|
||||
protected bool DemoCheck(string title)
|
||||
{
|
||||
if (!title.HasValue())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_demo)
|
||||
{
|
||||
if (ExcludedDemo.ExcludedContent.Any(x => title.Contains(x, System.Globalization.CompareOptions.OrdinalIgnoreCase)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public class HideResult
|
||||
{
|
||||
public bool Hide { get; set; }
|
||||
|
|
|
@ -9,6 +9,7 @@ using Ombi.Store.Entities.Requests;
|
|||
using Ombi.Store.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Helpers;
|
||||
|
||||
namespace Ombi.Core.Engine.Interfaces
|
||||
{
|
||||
|
@ -29,6 +30,10 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
private OmbiUser _user;
|
||||
protected async Task<OmbiUser> GetUser()
|
||||
{
|
||||
if(!Username.HasValue())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var username = Username.ToUpper();
|
||||
return _user ?? (_user = await UserManager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username));
|
||||
}
|
||||
|
@ -54,9 +59,9 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
var ruleResults = await Rules.StartSearchRules(model);
|
||||
return ruleResults;
|
||||
}
|
||||
public async Task<RuleResult> RunSpecificRule(object model, SpecificRules rule)
|
||||
public async Task<RuleResult> RunSpecificRule(object model, SpecificRules rule, string requestOnBehalf)
|
||||
{
|
||||
var ruleResults = await Rules.StartSpecificRules(model, rule);
|
||||
var ruleResults = await Rules.StartSpecificRules(model, rule, requestOnBehalf);
|
||||
return ruleResults;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies(int currentPosition, int amountToLoad);
|
||||
Task<MovieCollectionsViewModel> GetCollection(int collectionId, CancellationToken cancellationToken, string langCode = null);
|
||||
Task<int> GetTvDbId(int theMovieDbId);
|
||||
Task<IEnumerable<SearchMovieViewModel>> PopularMovies(int currentlyLoaded, int toLoad, CancellationToken cancellationToken);
|
||||
Task<IEnumerable<SearchMovieViewModel>> PopularMovies(int currentlyLoaded, int toLoad, CancellationToken cancellationToken, string langCustomCode = null);
|
||||
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies(int currentlyLoaded, int toLoad);
|
||||
Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies(int currentlyLoaded, int toLoad);
|
||||
Task<ActorCredits> GetMoviesByActor(int actorId, string langCode);
|
||||
|
@ -28,5 +28,6 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
Task<MovieFullInfoViewModel> GetMovieInfoByImdbId(string imdbId, CancellationToken requestAborted);
|
||||
Task<IEnumerable<StreamingData>> GetStreamInformation(int movieDbId, CancellationToken cancellationToken);
|
||||
Task<IEnumerable<SearchMovieViewModel>> RecentlyRequestedMovies(int currentlyLoaded, int toLoad, CancellationToken cancellationToken);
|
||||
Task<IEnumerable<SearchMovieViewModel>> SeasonalList(int currentPosition, int amountToLoad, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.UI;
|
||||
|
@ -11,6 +12,7 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
Task<RequestEngineResult> RequestMovie(MovieRequestViewModel model);
|
||||
|
||||
Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search);
|
||||
Task<RequestEngineResult> RequestCollection(int collectionId, CancellationToken cancellationToken);
|
||||
|
||||
Task RemoveMovieRequest(int requestId);
|
||||
Task RemoveAllMovieRequests();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Core.Models.Requests;
|
||||
|
@ -24,5 +25,6 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
Task UnSubscribeRequest(int requestId, RequestType type);
|
||||
Task SubscribeToRequest(int requestId, RequestType type);
|
||||
Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user = null);
|
||||
Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
|
@ -11,8 +11,9 @@ namespace Ombi.Core
|
|||
Task<SearchFullInfoTvShowViewModel> GetShowInformation(string tvdbid, CancellationToken token);
|
||||
Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId, CancellationToken token);
|
||||
Task<IEnumerable<StreamingData>> GetStreamInformation(int movieDbId, CancellationToken cancellationToken);
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Popular(int currentlyLoaded, int amountToLoad);
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Popular(int currentlyLoaded, int amountToLoad, string langCustomCode = null);
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Anticipated(int currentlyLoaded, int amountToLoad);
|
||||
Task<IEnumerable<SearchTvShowViewModel>> Trending(int currentlyLoaded, int amountToLoad);
|
||||
Task<IEnumerable<SearchFullInfoTvShowViewModel>> RecentlyRequestedShows(int currentlyLoaded, int toLoad, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ using Ombi.Settings.Settings.Models;
|
|||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Core.Models;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
|
@ -29,7 +30,7 @@ namespace Ombi.Core.Engine
|
|||
public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user,
|
||||
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log,
|
||||
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
|
||||
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub)
|
||||
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService)
|
||||
: base(user, requestService, r, manager, cache, ombiSettings, sub)
|
||||
{
|
||||
MovieApi = movieApi;
|
||||
|
@ -37,6 +38,7 @@ namespace Ombi.Core.Engine
|
|||
Sender = sender;
|
||||
Logger = log;
|
||||
_requestLog = rl;
|
||||
_mediaCacheService = mediaCacheService;
|
||||
}
|
||||
|
||||
private IMovieDbApi MovieApi { get; }
|
||||
|
@ -44,6 +46,7 @@ namespace Ombi.Core.Engine
|
|||
private IMovieSender Sender { get; }
|
||||
private ILogger<MovieRequestEngine> Logger { get; }
|
||||
private readonly IRepository<RequestLog> _requestLog;
|
||||
private readonly IMediaCacheService _mediaCacheService;
|
||||
|
||||
/// <summary>
|
||||
/// Requests the movie.
|
||||
|
@ -70,7 +73,7 @@ namespace Ombi.Core.Engine
|
|||
var canRequestOnBehalf = model.RequestOnBehalf.HasValue();
|
||||
|
||||
var isAdmin = await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser) || await UserManager.IsInRoleAsync(userDetails, OmbiRoles.Admin);
|
||||
if (model.RequestOnBehalf.HasValue() && !isAdmin)
|
||||
if (canRequestOnBehalf && !isAdmin)
|
||||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
|
@ -370,7 +373,6 @@ namespace Ombi.Core.Engine
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
public async Task<RequestEngineResult> UpdateAdvancedOptions(MediaAdvancedOptions options)
|
||||
{
|
||||
var request = await MovieRepository.Find(options.RequestId);
|
||||
|
@ -526,6 +528,7 @@ namespace Ombi.Core.Engine
|
|||
// We are denying a request
|
||||
await NotificationHelper.Notify(request, NotificationType.RequestDeclined);
|
||||
await MovieRepository.Update(request);
|
||||
await _mediaCacheService.Purge();
|
||||
|
||||
return new RequestEngineResult
|
||||
{
|
||||
|
@ -549,12 +552,42 @@ namespace Ombi.Core.Engine
|
|||
request.Denied = false;
|
||||
await MovieRepository.Update(request);
|
||||
|
||||
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification);
|
||||
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification, string.Empty);
|
||||
if (canNotify.Success)
|
||||
{
|
||||
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
||||
}
|
||||
await _mediaCacheService.Purge();
|
||||
|
||||
return await ProcessSendingMovie(request);
|
||||
}
|
||||
|
||||
public async Task<RequestEngineResult> RequestCollection(int collectionId, CancellationToken cancellationToken)
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
var collections = await Cache.GetOrAddAsync($"GetCollection{collectionId}{langCode}",
|
||||
() => MovieApi.GetCollection(langCode, collectionId, cancellationToken), DateTimeOffset.Now.AddDays(1));
|
||||
|
||||
var results = new List<RequestEngineResult>();
|
||||
foreach (var collection in collections.parts)
|
||||
{
|
||||
results.Add(await RequestMovie(new MovieRequestViewModel
|
||||
{
|
||||
TheMovieDbId = collection.id
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
if (results.All(x => x.IsError))
|
||||
{
|
||||
new RequestEngineResult { Result = false, ErrorMessage = $"The whole collection {collections.name} Is already monitored or requested!" };
|
||||
}
|
||||
|
||||
return new RequestEngineResult { Result = true, Message = $"The collection {collections.name} has been successfully added!", RequestId = results.FirstOrDefault().RequestId};
|
||||
}
|
||||
|
||||
private async Task<RequestEngineResult> ProcessSendingMovie(MovieRequests request)
|
||||
{
|
||||
if (request.Approved)
|
||||
{
|
||||
var result = await Sender.Send(request);
|
||||
|
@ -609,6 +642,7 @@ namespace Ombi.Core.Engine
|
|||
results.RootPathOverride = request.RootPathOverride;
|
||||
|
||||
await MovieRepository.Update(results);
|
||||
await _mediaCacheService.Purge();
|
||||
return results;
|
||||
}
|
||||
|
||||
|
@ -621,12 +655,14 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
var request = await MovieRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||
await MovieRepository.Delete(request);
|
||||
await _mediaCacheService.Purge();
|
||||
}
|
||||
|
||||
public async Task RemoveAllMovieRequests()
|
||||
{
|
||||
var request = MovieRepository.GetAll();
|
||||
await MovieRepository.DeleteRange(request);
|
||||
await _mediaCacheService.Purge();
|
||||
}
|
||||
|
||||
public async Task<bool> UserHasRequest(string userId)
|
||||
|
@ -634,6 +670,21 @@ namespace Ombi.Core.Engine
|
|||
return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId);
|
||||
}
|
||||
|
||||
public async Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken)
|
||||
{
|
||||
var request = await MovieRepository.Find(requestId);
|
||||
if (request == null)
|
||||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
Result = false,
|
||||
ErrorMessage = "Request does not exist"
|
||||
};
|
||||
}
|
||||
|
||||
return await ProcessSendingMovie(request);
|
||||
}
|
||||
|
||||
public async Task<RequestEngineResult> MarkUnavailable(int modelId)
|
||||
{
|
||||
var request = await MovieRepository.Find(modelId);
|
||||
|
@ -647,6 +698,7 @@ namespace Ombi.Core.Engine
|
|||
|
||||
request.Available = false;
|
||||
await MovieRepository.Update(request);
|
||||
await _mediaCacheService.Purge();
|
||||
|
||||
return new RequestEngineResult
|
||||
{
|
||||
|
@ -670,6 +722,7 @@ namespace Ombi.Core.Engine
|
|||
request.MarkedAsAvailable = DateTime.Now;
|
||||
await NotificationHelper.Notify(request, NotificationType.RequestAvailable);
|
||||
await MovieRepository.Update(request);
|
||||
await _mediaCacheService.Purge();
|
||||
|
||||
return new RequestEngineResult
|
||||
{
|
||||
|
@ -682,12 +735,14 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
await MovieRepository.Add(model);
|
||||
|
||||
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification);
|
||||
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification, requestOnBehalf);
|
||||
if (result.Success)
|
||||
{
|
||||
await NotificationHelper.NewRequest(model);
|
||||
}
|
||||
|
||||
await _mediaCacheService.Purge();
|
||||
|
||||
await _requestLog.Add(new RequestLog
|
||||
{
|
||||
UserId = requestOnBehalf.HasValue() ? requestOnBehalf : (await GetUser()).Id,
|
||||
|
|
|
@ -45,9 +45,9 @@ namespace Ombi.Core.Engine
|
|||
public async Task<SearchMovieViewModel> LookupImdbInformation(int theMovieDbId, string langCode = null)
|
||||
{
|
||||
langCode = await DefaultLanguageCode(langCode);
|
||||
var movieInfo = await Cache.GetOrAdd(nameof(LookupImdbInformation) + langCode + theMovieDbId,
|
||||
async () => await MovieApi.GetMovieInformationWithExtraInfo(theMovieDbId, langCode),
|
||||
DateTime.Now.AddHours(12));
|
||||
var movieInfo = await Cache.GetOrAddAsync(nameof(LookupImdbInformation) + langCode + theMovieDbId,
|
||||
() => MovieApi.GetMovieInformationWithExtraInfo(theMovieDbId, langCode),
|
||||
DateTimeOffset.Now.AddHours(12));
|
||||
var viewMovie = Mapper.Map<SearchMovieViewModel>(movieInfo);
|
||||
|
||||
return await ProcessSingleMovie(viewMovie, true);
|
||||
|
@ -121,11 +121,11 @@ namespace Ombi.Core.Engine
|
|||
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
|
||||
{
|
||||
|
||||
var result = await Cache.GetOrAdd(CacheKeys.PopularMovies, async () =>
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.PopularMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.PopularMovies(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
|
@ -139,11 +139,11 @@ namespace Ombi.Core.Engine
|
|||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.TopRatedMovies, async () =>
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.TopRatedMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.TopRated(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
|
@ -157,11 +157,11 @@ namespace Ombi.Core.Engine
|
|||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.UpcomingMovies, async () =>
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.UpcomingMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.Upcoming(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
Logger.LogDebug("Search Result: {result}", result);
|
||||
|
@ -176,11 +176,11 @@ namespace Ombi.Core.Engine
|
|||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.NowPlayingMovies, async () =>
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.NowPlayingMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.NowPlaying(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
|
|
|
@ -362,7 +362,7 @@ namespace Ombi.Core.Engine
|
|||
await MusicRepository.Update(request);
|
||||
|
||||
|
||||
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification);
|
||||
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification, string.Empty);
|
||||
if (canNotify.Success)
|
||||
{
|
||||
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
||||
|
@ -506,7 +506,7 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
await MusicRepository.Add(model);
|
||||
|
||||
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification);
|
||||
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification, string.Empty);
|
||||
if (result.Success)
|
||||
{
|
||||
await NotificationHelper.NewRequest(model);
|
||||
|
|
|
@ -151,7 +151,7 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
|
||||
|
||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrArtist);
|
||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrArtist, string.Empty);
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ namespace Ombi.Core.Engine
|
|||
|
||||
vm.Cover = a.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url?.ToHttpsUrl();
|
||||
|
||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum);
|
||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum, string.Empty);
|
||||
|
||||
await RunSearchRules(vm);
|
||||
|
||||
|
@ -230,7 +230,7 @@ namespace Ombi.Core.Engine
|
|||
vm.Cover = a.remoteCover;
|
||||
}
|
||||
|
||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum);
|
||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum, string.Empty);
|
||||
|
||||
await RunSearchRules(vm);
|
||||
|
||||
|
@ -258,7 +258,7 @@ namespace Ombi.Core.Engine
|
|||
vm.Cover = fullAlbum.remoteCover;
|
||||
}
|
||||
|
||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum);
|
||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum, string.Empty);
|
||||
|
||||
await RunSearchRules(vm);
|
||||
|
||||
|
|
|
@ -25,28 +25,35 @@ using Ombi.Settings.Settings.Models;
|
|||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Core.Models;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
{
|
||||
public class TvRequestEngine : BaseMediaEngine, ITvRequestEngine
|
||||
{
|
||||
public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user,
|
||||
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager,
|
||||
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager, ILogger<TvRequestEngine> logger,
|
||||
ITvSender sender, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache,
|
||||
IRepository<RequestSubscription> sub) : base(user, requestService, rule, manager, cache, settings, sub)
|
||||
IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService) : base(user, requestService, rule, manager, cache, settings, sub)
|
||||
{
|
||||
TvApi = tvApi;
|
||||
MovieDbApi = movApi;
|
||||
NotificationHelper = helper;
|
||||
_logger = logger;
|
||||
TvSender = sender;
|
||||
_requestLog = rl;
|
||||
_mediaCacheService = mediaCacheService;
|
||||
}
|
||||
|
||||
private INotificationHelper NotificationHelper { get; }
|
||||
private ITvMazeApi TvApi { get; }
|
||||
private IMovieDbApi MovieDbApi { get; }
|
||||
private ITvSender TvSender { get; }
|
||||
|
||||
private readonly ILogger<TvRequestEngine> _logger;
|
||||
private readonly IRepository<RequestLog> _requestLog;
|
||||
private readonly IMediaCacheService _mediaCacheService;
|
||||
|
||||
public async Task<RequestEngineResult> RequestTvShow(TvRequestViewModel tv)
|
||||
{
|
||||
|
@ -68,7 +75,7 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
}
|
||||
|
||||
var tvBuilder = new TvShowRequestBuilder(TvApi, MovieDbApi);
|
||||
var tvBuilder = new TvShowRequestBuilder(TvApi, MovieDbApi, _logger);
|
||||
(await tvBuilder
|
||||
.GetShowInfo(tv.TvDbId))
|
||||
.CreateTvList(tv)
|
||||
|
@ -164,7 +171,7 @@ namespace Ombi.Core.Engine
|
|||
};
|
||||
}
|
||||
|
||||
if ((tv.RootFolderOverride.HasValue || tv.QualityPathOverride.HasValue) && !isAdmin)
|
||||
if ((tv.RootFolderOverride.HasValue || tv.QualityPathOverride.HasValue || tv.LanguageProfile.HasValue) && !isAdmin)
|
||||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
|
@ -250,7 +257,7 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
|
||||
// This is a new request
|
||||
var newRequest = tvBuilder.CreateNewRequest(tv, tv.RootFolderOverride.GetValueOrDefault(), tv.QualityPathOverride.GetValueOrDefault());
|
||||
var newRequest = tvBuilder.CreateNewRequest(tv, tv.RootFolderOverride.GetValueOrDefault(), tv.QualityPathOverride.GetValueOrDefault(), tv.LanguageProfile.GetValueOrDefault());
|
||||
return await AddRequest(newRequest.NewRequest, tv.RequestOnBehalf);
|
||||
}
|
||||
|
||||
|
@ -324,6 +331,7 @@ namespace Ombi.Core.Engine
|
|||
Collection = allRequests
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TvRequests>> GetRequests()
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
|
@ -343,7 +351,6 @@ namespace Ombi.Core.Engine
|
|||
return allRequests;
|
||||
}
|
||||
|
||||
|
||||
public async Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
|
@ -399,7 +406,7 @@ namespace Ombi.Core.Engine
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder, RequestStatus status)
|
||||
public async Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder, RequestStatus status)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
List<ChildRequests> allRequests;
|
||||
|
@ -471,6 +478,7 @@ namespace Ombi.Core.Engine
|
|||
Total = total,
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<RequestsViewModel<ChildRequests>> GetUnavailableRequests(int count, int position, string sortProperty, string sortOrder)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
|
@ -524,7 +532,6 @@ namespace Ombi.Core.Engine
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<TvRequests>> GetRequestsLite()
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
|
@ -694,6 +701,7 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
|
||||
await TvRepository.UpdateChild(request);
|
||||
await _mediaCacheService.Purge();
|
||||
|
||||
if (request.Approved)
|
||||
{
|
||||
|
@ -720,6 +728,7 @@ namespace Ombi.Core.Engine
|
|||
request.Denied = true;
|
||||
request.DeniedReason = reason;
|
||||
await TvRepository.UpdateChild(request);
|
||||
await _mediaCacheService.Purge();
|
||||
await NotificationHelper.Notify(request, NotificationType.RequestDeclined);
|
||||
return new RequestEngineResult
|
||||
{
|
||||
|
@ -730,6 +739,7 @@ namespace Ombi.Core.Engine
|
|||
public async Task<ChildRequests> UpdateChildRequest(ChildRequests request)
|
||||
{
|
||||
await TvRepository.UpdateChild(request);
|
||||
await _mediaCacheService.Purge();
|
||||
return request;
|
||||
}
|
||||
|
||||
|
@ -749,12 +759,14 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
|
||||
await TvRepository.Db.SaveChangesAsync();
|
||||
await _mediaCacheService.Purge();
|
||||
}
|
||||
|
||||
public async Task RemoveTvRequest(int requestId)
|
||||
{
|
||||
var request = await TvRepository.Get().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||
await TvRepository.Delete(request);
|
||||
await _mediaCacheService.Purge();
|
||||
}
|
||||
|
||||
public async Task<bool> UserHasRequest(string userId)
|
||||
|
@ -781,6 +793,7 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
}
|
||||
await TvRepository.UpdateChild(request);
|
||||
await _mediaCacheService.Purge();
|
||||
return new RequestEngineResult
|
||||
{
|
||||
Result = true,
|
||||
|
@ -809,6 +822,7 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
await TvRepository.UpdateChild(request);
|
||||
await NotificationHelper.Notify(request, NotificationType.RequestAvailable);
|
||||
await _mediaCacheService.Purge();
|
||||
return new RequestEngineResult
|
||||
{
|
||||
Result = true,
|
||||
|
@ -883,22 +897,25 @@ namespace Ombi.Core.Engine
|
|||
return await AfterRequest(model.ChildRequests.FirstOrDefault(), requestOnBehalf);
|
||||
}
|
||||
|
||||
private static List<ChildRequests> SortEpisodes(List<ChildRequests> items)
|
||||
public async Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (var value in items)
|
||||
var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId, cancellationToken);
|
||||
if (request == null)
|
||||
{
|
||||
foreach (var requests in value.SeasonRequests)
|
||||
return new RequestEngineResult
|
||||
{
|
||||
requests.Episodes = requests.Episodes.OrderBy(x => x.EpisodeNumber).ToList();
|
||||
}
|
||||
Result = false,
|
||||
ErrorMessage = "Request does not exist"
|
||||
};
|
||||
}
|
||||
return items;
|
||||
|
||||
return await ProcessSendingShow(request);
|
||||
}
|
||||
|
||||
|
||||
private async Task<RequestEngineResult> AfterRequest(ChildRequests model, string requestOnBehalf)
|
||||
{
|
||||
var sendRuleResult = await RunSpecificRule(model, SpecificRules.CanSendNotification);
|
||||
var sendRuleResult = await RunSpecificRule(model, SpecificRules.CanSendNotification, requestOnBehalf);
|
||||
if (sendRuleResult.Success)
|
||||
{
|
||||
await NotificationHelper.NewRequest(model);
|
||||
|
@ -912,7 +929,13 @@ namespace Ombi.Core.Engine
|
|||
RequestType = RequestType.TvShow,
|
||||
EpisodeCount = model.SeasonRequests.Select(m => m.Episodes.Count).Sum(),
|
||||
});
|
||||
await _mediaCacheService.Purge();
|
||||
|
||||
return await ProcessSendingShow(model);
|
||||
}
|
||||
|
||||
private async Task<RequestEngineResult> ProcessSendingShow(ChildRequests model)
|
||||
{
|
||||
if (model.Approved)
|
||||
{
|
||||
// Autosend
|
||||
|
@ -997,6 +1020,10 @@ namespace Ombi.Core.Engine
|
|||
|
||||
request.QualityOverride = options.QualityOverride;
|
||||
request.RootFolder = options.RootPathOverride;
|
||||
if (options.LanguageProfile > 0)
|
||||
{
|
||||
request.LanguageProfile = options.LanguageProfile;
|
||||
}
|
||||
|
||||
await TvRepository.Update(request);
|
||||
|
||||
|
|
|
@ -77,16 +77,16 @@ namespace Ombi.Core.Engine
|
|||
|
||||
public async Task<SearchTvShowViewModel> GetShowInformation(string tvdbid, CancellationToken token)
|
||||
{
|
||||
var show = await Cache.GetOrAdd(nameof(GetShowInformation) + tvdbid,
|
||||
async () => await TvMazeApi.ShowLookupByTheTvDbId(int.Parse(tvdbid)), DateTime.Now.AddHours(12));
|
||||
var show = await Cache.GetOrAddAsync(nameof(GetShowInformation) + tvdbid,
|
||||
() => TvMazeApi.ShowLookupByTheTvDbId(int.Parse(tvdbid)), DateTimeOffset.Now.AddHours(12));
|
||||
if (show == null)
|
||||
{
|
||||
// We don't have enough information
|
||||
return null;
|
||||
}
|
||||
|
||||
var episodes = await Cache.GetOrAdd("TvMazeEpisodeLookup" + show.id,
|
||||
async () => await TvMazeApi.EpisodeLookup(show.id), DateTime.Now.AddHours(12));
|
||||
var episodes = await Cache.GetOrAddAsync("TvMazeEpisodeLookup" + show.id,
|
||||
() => TvMazeApi.EpisodeLookup(show.id), DateTimeOffset.Now.AddHours(12));
|
||||
if (episodes == null || !episodes.Any())
|
||||
{
|
||||
// We don't have enough information
|
||||
|
@ -133,7 +133,7 @@ namespace Ombi.Core.Engine
|
|||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Popular()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.PopularTv, async () => await TraktApi.GetPopularShows(null, ResultLimit), DateTime.Now.AddHours(12));
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.PopularTv, () => TraktApi.GetPopularShows(null, ResultLimit), DateTimeOffset.Now.AddHours(12));
|
||||
var processed = ProcessResults(result);
|
||||
return await processed;
|
||||
}
|
||||
|
@ -146,8 +146,8 @@ namespace Ombi.Core.Engine
|
|||
var results = new List<TraktShow>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAdd(nameof(Popular) + langCode + pagesToLoad.Page,
|
||||
async () => await TraktApi.GetPopularShows(pagesToLoad.Page, ResultLimit), DateTime.Now.AddHours(12));
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(Popular) + langCode + pagesToLoad.Page,
|
||||
() => TraktApi.GetPopularShows(pagesToLoad.Page, ResultLimit), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
|
||||
|
@ -158,7 +158,7 @@ namespace Ombi.Core.Engine
|
|||
public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated()
|
||||
{
|
||||
|
||||
var result = await Cache.GetOrAdd(CacheKeys.AnticipatedTv, async () => await TraktApi.GetAnticipatedShows(null, ResultLimit), DateTime.Now.AddHours(12));
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.AnticipatedTv, () => TraktApi.GetAnticipatedShows(null, ResultLimit), DateTimeOffset.Now.AddHours(12));
|
||||
var processed = ProcessResults(result);
|
||||
return await processed;
|
||||
}
|
||||
|
@ -171,8 +171,8 @@ namespace Ombi.Core.Engine
|
|||
var results = new List<TraktShow>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAdd(nameof(Anticipated) + langCode + pagesToLoad.Page,
|
||||
async () => await TraktApi.GetAnticipatedShows(pagesToLoad.Page, ResultLimit), DateTime.Now.AddHours(12));
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(Anticipated) + langCode + pagesToLoad.Page,
|
||||
() => TraktApi.GetAnticipatedShows(pagesToLoad.Page, ResultLimit), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
var processed = ProcessResults(results);
|
||||
|
@ -181,7 +181,7 @@ namespace Ombi.Core.Engine
|
|||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Trending()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.TrendingTv, async () => await TraktApi.GetTrendingShows(null, ResultLimit), DateTime.Now.AddHours(12));
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.TrendingTv, () => TraktApi.GetTrendingShows(null, ResultLimit), DateTimeOffset.Now.AddHours(12));
|
||||
var processed = ProcessResults(result);
|
||||
return await processed;
|
||||
}
|
||||
|
@ -195,8 +195,8 @@ namespace Ombi.Core.Engine
|
|||
var results = new List<TraktShow>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAdd(nameof(Trending) + langCode + pagesToLoad.Page,
|
||||
async () => await TraktApi.GetTrendingShows(pagesToLoad.Page, ResultLimit), DateTime.Now.AddHours(12));
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(Trending) + langCode + pagesToLoad.Page,
|
||||
() => TraktApi.GetTrendingShows(pagesToLoad.Page, ResultLimit), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
var processed = ProcessResults(results);
|
||||
|
|
|
@ -19,6 +19,7 @@ using Ombi.Store.Repository;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -29,7 +30,7 @@ namespace Ombi.Core.Engine.V2
|
|||
{
|
||||
public MovieSearchEngineV2(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
|
||||
ILogger<MovieSearchEngineV2> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub,
|
||||
ISettingsService<CustomizationSettings> customizationSettings, IMovieRequestEngine movieRequestEngine)
|
||||
ISettingsService<CustomizationSettings> customizationSettings, IMovieRequestEngine movieRequestEngine, IHttpClientFactory httpClientFactory)
|
||||
: base(identity, service, r, um, mem, s, sub)
|
||||
{
|
||||
MovieApi = movApi;
|
||||
|
@ -37,6 +38,7 @@ namespace Ombi.Core.Engine.V2
|
|||
Logger = logger;
|
||||
_customizationSettings = customizationSettings;
|
||||
_movieRequestEngine = movieRequestEngine;
|
||||
_client = httpClientFactory.CreateClient();
|
||||
}
|
||||
|
||||
private IMovieDbApi MovieApi { get; }
|
||||
|
@ -44,12 +46,13 @@ namespace Ombi.Core.Engine.V2
|
|||
private ILogger Logger { get; }
|
||||
private readonly ISettingsService<CustomizationSettings> _customizationSettings;
|
||||
private readonly IMovieRequestEngine _movieRequestEngine;
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public async Task<MovieFullInfoViewModel> GetFullMovieInformation(int theMovieDbId, CancellationToken cancellationToken, string langCode = null)
|
||||
{
|
||||
langCode = await DefaultLanguageCode(langCode);
|
||||
var movieInfo = await Cache.GetOrAdd(nameof(GetFullMovieInformation) + theMovieDbId + langCode,
|
||||
async () => await MovieApi.GetFullMovieInfo(theMovieDbId, cancellationToken, langCode), DateTime.Now.AddHours(12), cancellationToken);
|
||||
var movieInfo = await Cache.GetOrAddAsync(nameof(GetFullMovieInformation) + theMovieDbId + langCode,
|
||||
() => MovieApi.GetFullMovieInfo(theMovieDbId, cancellationToken, langCode), DateTimeOffset.Now.AddHours(12));
|
||||
|
||||
return await ProcessSingleMovie(movieInfo);
|
||||
}
|
||||
|
@ -58,8 +61,8 @@ namespace Ombi.Core.Engine.V2
|
|||
{
|
||||
langCode = await DefaultLanguageCode(langCode);
|
||||
var request = await RequestService.MovieRequestService.Find(requestId);
|
||||
var movieInfo = await Cache.GetOrAdd(nameof(GetFullMovieInformation) + request.TheMovieDbId + langCode,
|
||||
async () => await MovieApi.GetFullMovieInfo(request.TheMovieDbId, cancellationToken, langCode), DateTime.Now.AddHours(12), cancellationToken);
|
||||
var movieInfo = await Cache.GetOrAddAsync(nameof(GetFullMovieInformation) + request.TheMovieDbId + langCode,
|
||||
() => MovieApi.GetFullMovieInfo(request.TheMovieDbId, cancellationToken, langCode), DateTimeOffset.Now.AddHours(12));
|
||||
|
||||
return await ProcessSingleMovie(movieInfo);
|
||||
}
|
||||
|
@ -67,8 +70,8 @@ namespace Ombi.Core.Engine.V2
|
|||
public async Task<MovieCollectionsViewModel> GetCollection(int collectionId, CancellationToken cancellationToken, string langCode = null)
|
||||
{
|
||||
langCode = await DefaultLanguageCode(langCode);
|
||||
var collections = await Cache.GetOrAdd(nameof(GetCollection) + collectionId + langCode,
|
||||
async () => await MovieApi.GetCollection(langCode, collectionId, cancellationToken), DateTime.Now.AddDays(1), cancellationToken);
|
||||
var collections = await Cache.GetOrAddAsync(nameof(GetCollection) + collectionId + langCode,
|
||||
() => MovieApi.GetCollection(langCode, collectionId, cancellationToken), DateTimeOffset.Now.AddDays(1));
|
||||
|
||||
var c = await ProcessCollection(collections);
|
||||
c.Collection = c.Collection.OrderBy(x => x.ReleaseDate).ToList();
|
||||
|
@ -105,11 +108,11 @@ namespace Ombi.Core.Engine.V2
|
|||
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
|
||||
{
|
||||
|
||||
var result = await Cache.GetOrAdd(CacheKeys.PopularMovies, async () =>
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.PopularMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.PopularMovies(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
|
@ -124,17 +127,17 @@ namespace Ombi.Core.Engine.V2
|
|||
/// Gets popular movies by paging
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies(int currentlyLoaded, int toLoad, CancellationToken cancellationToken)
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies(int currentlyLoaded, int toLoad, CancellationToken cancellationToken, string langCustomCode = null)
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
var langCode = await DefaultLanguageCode(langCustomCode);
|
||||
|
||||
var pages = PaginationHelper.GetNextPages(currentlyLoaded, toLoad, _theMovieDbMaxPageItems);
|
||||
|
||||
var results = new List<MovieDbSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAdd(nameof(PopularMovies) + pagesToLoad.Page + langCode,
|
||||
async () => await MovieApi.PopularMovies(langCode, pagesToLoad.Page, cancellationToken), DateTime.Now.AddHours(12), cancellationToken);
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(PopularMovies) + pagesToLoad.Page + langCode,
|
||||
() => MovieApi.PopularMovies(langCode, pagesToLoad.Page, cancellationToken), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
return await TransformMovieResultsToResponse(results);
|
||||
|
@ -146,11 +149,11 @@ namespace Ombi.Core.Engine.V2
|
|||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.TopRatedMovies, async () =>
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.TopRatedMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.TopRated(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
|
@ -167,8 +170,8 @@ namespace Ombi.Core.Engine.V2
|
|||
var results = new List<MovieDbSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAdd(nameof(TopRatedMovies) + pagesToLoad.Page + langCode,
|
||||
async () => await MovieApi.TopRated(langCode, pagesToLoad.Page), DateTime.Now.AddHours(12));
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(TopRatedMovies) + pagesToLoad.Page + langCode,
|
||||
() => MovieApi.TopRated(langCode, pagesToLoad.Page), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
return await TransformMovieResultsToResponse(results);
|
||||
|
@ -183,8 +186,32 @@ namespace Ombi.Core.Engine.V2
|
|||
var results = new List<MovieDbSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAdd(nameof(NowPlayingMovies) + pagesToLoad.Page + langCode,
|
||||
async () => await MovieApi.NowPlaying(langCode, pagesToLoad.Page), DateTime.Now.AddHours(12));
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(NowPlayingMovies) + pagesToLoad.Page + langCode,
|
||||
() => MovieApi.NowPlaying(langCode, pagesToLoad.Page), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
return await TransformMovieResultsToResponse(results);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> SeasonalList(int currentPosition, int amountToLoad, CancellationToken cancellationToken)
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
|
||||
var result = await _client.GetAsync("https://raw.githubusercontent.com/Ombi-app/Ombi.News/main/Seasonal.md");
|
||||
var keyWordIds = await result.Content.ReadAsStringAsync();
|
||||
|
||||
if (string.IsNullOrEmpty(keyWordIds) || keyWordIds.Equals("\n"))
|
||||
{
|
||||
return new List<SearchMovieViewModel>();
|
||||
}
|
||||
|
||||
var pages = PaginationHelper.GetNextPages(currentPosition, amountToLoad, _theMovieDbMaxPageItems);
|
||||
|
||||
var results = new List<MovieDbSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(SeasonalList) + pagesToLoad.Page + langCode + keyWordIds,
|
||||
() => MovieApi.GetMoviesViaKeywords(keyWordIds, langCode, cancellationToken, pagesToLoad.Page), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
return await TransformMovieResultsToResponse(results);
|
||||
|
@ -200,16 +227,16 @@ namespace Ombi.Core.Engine.V2
|
|||
|
||||
var results = new List<MovieResponseDto>();
|
||||
|
||||
var requestResult = await Cache.GetOrAdd(nameof(RecentlyRequestedMovies) + "Requests" + toLoad + langCode,
|
||||
var requestResult = await Cache.GetOrAddAsync(nameof(RecentlyRequestedMovies) + "Requests" + toLoad + langCode,
|
||||
async () =>
|
||||
{
|
||||
return await _movieRequestEngine.GetRequests(toLoad, currentlyLoaded, new Models.UI.OrderFilterModel
|
||||
{
|
||||
OrderType = OrderType.RequestedDateDesc
|
||||
});
|
||||
}, DateTime.Now.AddMinutes(15), cancellationToken);
|
||||
}, DateTimeOffset.Now.AddMinutes(15));
|
||||
|
||||
var movieDBResults = await Cache.GetOrAdd(nameof(RecentlyRequestedMovies) + toLoad + langCode,
|
||||
var movieDBResults = await Cache.GetOrAddAsync(nameof(RecentlyRequestedMovies) + toLoad + langCode,
|
||||
async () =>
|
||||
{
|
||||
var responses = new List<MovieResponseDto>();
|
||||
|
@ -218,7 +245,7 @@ namespace Ombi.Core.Engine.V2
|
|||
responses.Add(await MovieApi.GetMovieInformation(movie.TheMovieDbId));
|
||||
}
|
||||
return responses;
|
||||
}, DateTime.Now.AddHours(12), cancellationToken);
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
|
||||
results.AddRange(movieDBResults);
|
||||
|
||||
|
@ -232,11 +259,11 @@ namespace Ombi.Core.Engine.V2
|
|||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.UpcomingMovies, async () =>
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.UpcomingMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.Upcoming(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
Logger.LogDebug("Search Result: {result}", result);
|
||||
|
@ -254,8 +281,8 @@ namespace Ombi.Core.Engine.V2
|
|||
var results = new List<MovieDbSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAdd(nameof(UpcomingMovies) + pagesToLoad.Page + langCode,
|
||||
async () => await MovieApi.Upcoming(langCode, pagesToLoad.Page), DateTime.Now.AddHours(12));
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(UpcomingMovies) + pagesToLoad.Page + langCode,
|
||||
() => MovieApi.Upcoming(langCode, pagesToLoad.Page), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
return await TransformMovieResultsToResponse(results);
|
||||
|
@ -267,11 +294,11 @@ namespace Ombi.Core.Engine.V2
|
|||
/// <returns></returns>
|
||||
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
|
||||
{
|
||||
var result = await Cache.GetOrAdd(CacheKeys.NowPlayingMovies, async () =>
|
||||
var result = await Cache.GetOrAddAsync(CacheKeys.NowPlayingMovies, async () =>
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
return await MovieApi.NowPlaying(langCode);
|
||||
}, DateTime.Now.AddHours(12));
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
if (result != null)
|
||||
{
|
||||
return await TransformMovieResultsToResponse(result.Shuffle().Take(ResultLimit)); // Take x to stop us overloading the API
|
||||
|
@ -281,8 +308,8 @@ namespace Ombi.Core.Engine.V2
|
|||
|
||||
public async Task<ActorCredits> GetMoviesByActor(int actorId, string langCode)
|
||||
{
|
||||
var result = await Cache.GetOrAdd(nameof(GetMoviesByActor) + actorId + langCode,
|
||||
async () => await MovieApi.GetActorMovieCredits(actorId, langCode));
|
||||
var result = await Cache.GetOrAddAsync(nameof(GetMoviesByActor) + actorId + langCode,
|
||||
() => MovieApi.GetActorMovieCredits(actorId, langCode), DateTimeOffset.Now.AddHours(12));
|
||||
// Later we run this through the rules engine
|
||||
return result;
|
||||
}
|
||||
|
@ -315,6 +342,12 @@ namespace Ombi.Core.Engine.V2
|
|||
foreach (var movie in movies)
|
||||
{
|
||||
var result = await ProcessSingleMovie(movie);
|
||||
|
||||
if (DemoCheck(result.Title))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (settings.HideAvailableFromDiscover && result.Available)
|
||||
{
|
||||
continue;
|
||||
|
@ -333,6 +366,14 @@ namespace Ombi.Core.Engine.V2
|
|||
private async Task<MovieFullInfoViewModel> ProcessSingleMovie(FullMovieInfo movie)
|
||||
{
|
||||
var viewMovie = Mapper.Map<SearchMovieViewModel>(movie);
|
||||
var user = await GetUser();
|
||||
var digitalReleaseDate = viewMovie.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == user.StreamingCountry);
|
||||
if (digitalReleaseDate == null)
|
||||
{
|
||||
digitalReleaseDate = viewMovie.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US");
|
||||
}
|
||||
viewMovie.DigitalReleaseDate = digitalReleaseDate?.ReleaseDate?.FirstOrDefault(x => x.Type == ReleaseDateType.Digital)?.ReleaseDate;
|
||||
|
||||
await RunSearchRules(viewMovie);
|
||||
|
||||
// This requires the rules to be run first to populate the RequestId property
|
||||
|
@ -348,6 +389,7 @@ namespace Ombi.Core.Engine.V2
|
|||
mapped.JellyfinUrl = viewMovie.JellyfinUrl;
|
||||
mapped.Subscribed = viewMovie.Subscribed;
|
||||
mapped.ShowSubscribe = viewMovie.ShowSubscribe;
|
||||
mapped.DigitalReleaseDate = viewMovie.DigitalReleaseDate;
|
||||
|
||||
return mapped;
|
||||
}
|
||||
|
@ -371,6 +413,7 @@ namespace Ombi.Core.Engine.V2
|
|||
mapped.Requested = movie.Requested;
|
||||
mapped.PlexUrl = movie.PlexUrl;
|
||||
mapped.EmbyUrl = movie.EmbyUrl;
|
||||
mapped.JellyfinUrl = movie.JellyfinUrl;
|
||||
mapped.Subscribed = movie.Subscribed;
|
||||
mapped.ShowSubscribe = movie.ShowSubscribe;
|
||||
mapped.ReleaseDate = movie.ReleaseDate;
|
||||
|
@ -382,12 +425,21 @@ namespace Ombi.Core.Engine.V2
|
|||
{
|
||||
if (viewMovie.ImdbId.IsNullOrEmpty())
|
||||
{
|
||||
var showInfo = await Cache.GetOrAdd("GetMovieInformationWIthImdbId" + viewMovie.Id,
|
||||
async () => await MovieApi.GetMovieInformation(viewMovie.Id), DateTime.Now.AddHours(12));
|
||||
var showInfo = await Cache.GetOrAddAsync("GetMovieInformationWIthImdbId" + viewMovie.Id,
|
||||
() => MovieApi.GetMovieInformation(viewMovie.Id), DateTimeOffset.Now.AddHours(12));
|
||||
viewMovie.Id = showInfo.Id; // TheMovieDbId
|
||||
viewMovie.ImdbId = showInfo.ImdbId;
|
||||
}
|
||||
|
||||
var user = await GetUser();
|
||||
var digitalReleaseDate = viewMovie.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == user.StreamingCountry);
|
||||
if (digitalReleaseDate == null)
|
||||
{
|
||||
digitalReleaseDate = viewMovie.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US");
|
||||
}
|
||||
viewMovie.DigitalReleaseDate = digitalReleaseDate?.ReleaseDate?.FirstOrDefault(x => x.Type == ReleaseDateType.Digital)?.ReleaseDate;
|
||||
|
||||
|
||||
viewMovie.TheMovieDbId = viewMovie.Id.ToString();
|
||||
|
||||
await RunSearchRules(viewMovie);
|
||||
|
@ -424,12 +476,12 @@ namespace Ombi.Core.Engine.V2
|
|||
public async Task<MovieFullInfoViewModel> GetMovieInfoByImdbId(string imdbId, CancellationToken cancellationToken)
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
var findResult = await Cache.GetOrAdd(nameof(GetMovieInfoByImdbId) + imdbId + langCode,
|
||||
async () => await MovieApi.Find(imdbId, ExternalSource.imdb_id), DateTime.Now.AddHours(12), cancellationToken);
|
||||
var findResult = await Cache.GetOrAddAsync(nameof(GetMovieInfoByImdbId) + imdbId + langCode,
|
||||
() => MovieApi.Find(imdbId, ExternalSource.imdb_id), DateTimeOffset.Now.AddHours(12));
|
||||
|
||||
var movie = findResult.movie_results.FirstOrDefault();
|
||||
var movieInfo = await Cache.GetOrAdd(nameof(GetMovieInfoByImdbId) + movie.id + langCode,
|
||||
async () => await MovieApi.GetFullMovieInfo(movie.id, cancellationToken, langCode), DateTime.Now.AddHours(12), cancellationToken);
|
||||
var movieInfo = await Cache.GetOrAddAsync(nameof(GetMovieInfoByImdbId) + movie.id + langCode,
|
||||
() => MovieApi.GetFullMovieInfo(movie.id, cancellationToken, langCode), DateTimeOffset.Now.AddHours(12));
|
||||
|
||||
return await ProcessSingleMovie(movieInfo);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ namespace Ombi.Core.Engine.V2
|
|||
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||
private readonly IMusicBrainzApi _musicApi;
|
||||
|
||||
private bool _demo = DemoSingleton.Instance.Demo;
|
||||
|
||||
|
||||
public async Task<List<MultiSearchResult>> MultiSearch(string searchTerm, MultiSearchFilter filter, CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -60,6 +62,12 @@ namespace Ombi.Core.Engine.V2
|
|||
|
||||
foreach (var multiSearch in movieDbData)
|
||||
{
|
||||
|
||||
if (DemoCheck(multiSearch.title) || DemoCheck(multiSearch.name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var result = new MultiSearchResult
|
||||
{
|
||||
MediaType = multiSearch.media_type,
|
||||
|
|
|
@ -22,6 +22,9 @@ using Microsoft.EntityFrameworkCore;
|
|||
using System.Threading;
|
||||
using Ombi.Api.TheMovieDb;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using System.Diagnostics;
|
||||
using Ombi.Core.Engine.Interfaces;
|
||||
using Ombi.Core.Models.UI;
|
||||
|
||||
namespace Ombi.Core.Engine.V2
|
||||
{
|
||||
|
@ -32,10 +35,11 @@ namespace Ombi.Core.Engine.V2
|
|||
private readonly ITraktApi _traktApi;
|
||||
private readonly IMovieDbApi _movieApi;
|
||||
private readonly ISettingsService<CustomizationSettings> _customization;
|
||||
private readonly ITvRequestEngine _requestEngine;
|
||||
|
||||
public TvSearchEngineV2(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
|
||||
ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache, ISettingsService<OmbiSettings> s,
|
||||
IRepository<RequestSubscription> sub, IMovieDbApi movieApi, ISettingsService<CustomizationSettings> customization)
|
||||
IRepository<RequestSubscription> sub, IMovieDbApi movieApi, ISettingsService<CustomizationSettings> customization, ITvRequestEngine requestEngine)
|
||||
: base(identity, service, r, um, memCache, s, sub)
|
||||
{
|
||||
_tvMaze = tvMaze;
|
||||
|
@ -43,25 +47,43 @@ namespace Ombi.Core.Engine.V2
|
|||
_traktApi = trakt;
|
||||
_movieApi = movieApi;
|
||||
_customization = customization;
|
||||
_requestEngine = requestEngine;
|
||||
}
|
||||
|
||||
|
||||
public async Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId, CancellationToken token)
|
||||
{
|
||||
var request = await RequestService.TvRequestService.Get().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||
return await GetShowInformation(request.ExternalProviderId.ToString(), token); // TODO
|
||||
return await GetShowInformation(request.ExternalProviderId.ToString(), token);
|
||||
}
|
||||
|
||||
public async Task<SearchFullInfoTvShowViewModel> GetShowInformation(string tvdbid, CancellationToken token)
|
||||
{
|
||||
var show = await Cache.GetOrAdd(nameof(GetShowInformation) + tvdbid,
|
||||
async () => await _movieApi.GetTVInfo(tvdbid), DateTime.Now.AddHours(12));
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
var show = await Cache.GetOrAddAsync(nameof(GetShowInformation) + langCode + tvdbid,
|
||||
async () => await _movieApi.GetTVInfo(tvdbid, langCode), DateTimeOffset.Now.AddHours(12));
|
||||
if (show == null || show.name == null)
|
||||
{
|
||||
// We don't have enough information
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!show.Images?.Posters?.Any() ?? false && !string.Equals(langCode, "en", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// There's no regional assets for this, so
|
||||
// lookup the en-us version to get them
|
||||
var enShow = await Cache.GetOrAddAsync(nameof(GetShowInformation) + "en" + tvdbid,
|
||||
async () => await _movieApi.GetTVInfo(tvdbid, "en"), DateTimeOffset.Now.AddHours(12));
|
||||
|
||||
// For some of the more obsecure cases
|
||||
if (!show.overview.HasValue())
|
||||
{
|
||||
show.overview = enShow.overview;
|
||||
}
|
||||
|
||||
show.Images = enShow.Images;
|
||||
}
|
||||
|
||||
var mapped = _mapper.Map<SearchFullInfoTvShowViewModel>(show);
|
||||
|
||||
|
||||
|
@ -69,54 +91,22 @@ namespace Ombi.Core.Engine.V2
|
|||
{
|
||||
var seasonEpisodes = (await _movieApi.GetSeasonEpisodes(show.id, tvSeason.season_number, token));
|
||||
|
||||
foreach (var episode in seasonEpisodes.episodes)
|
||||
{
|
||||
var season = mapped.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == episode.season_number);
|
||||
if (season == null)
|
||||
{
|
||||
var newSeason = new SeasonRequests
|
||||
{
|
||||
SeasonNumber = episode.season_number,
|
||||
Overview = tvSeason.overview,
|
||||
Episodes = new List<EpisodeRequests>()
|
||||
};
|
||||
newSeason.Episodes.Add(new EpisodeRequests
|
||||
{
|
||||
//Url = episode...ToHttpsUrl(),
|
||||
Title = episode.name,
|
||||
AirDate = episode.air_date.HasValue() ? DateTime.Parse(episode.air_date) : DateTime.MinValue,
|
||||
EpisodeNumber = episode.episode_number,
|
||||
|
||||
});
|
||||
mapped.SeasonRequests.Add(newSeason);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We already have the season, so just add the episode
|
||||
season.Episodes.Add(new EpisodeRequests
|
||||
{
|
||||
//Url = e.url.ToHttpsUrl(),
|
||||
Title = episode.name,
|
||||
AirDate = episode.air_date.HasValue() ? DateTime.Parse(episode.air_date) : DateTime.MinValue,
|
||||
EpisodeNumber = episode.episode_number,
|
||||
});
|
||||
}
|
||||
}
|
||||
MapSeasons(mapped.SeasonRequests, tvSeason, seasonEpisodes);
|
||||
}
|
||||
|
||||
return await ProcessResult(mapped);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Popular(int currentlyLoaded, int amountToLoad)
|
||||
public async Task<IEnumerable<SearchTvShowViewModel>> Popular(int currentlyLoaded, int amountToLoad, string langCustomCode = null)
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
var langCode = await DefaultLanguageCode(langCustomCode);
|
||||
|
||||
var pages = PaginationHelper.GetNextPages(currentlyLoaded, amountToLoad, ResultLimit);
|
||||
var results = new List<MovieDbSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAdd(nameof(Popular) + langCode + pagesToLoad.Page,
|
||||
async () => await _movieApi.PopularTv(langCode, pagesToLoad.Page), DateTime.Now.AddHours(12));
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(Popular) + langCode + pagesToLoad.Page,
|
||||
async () => await _movieApi.PopularTv(langCode, pagesToLoad.Page), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
|
||||
|
@ -132,8 +122,8 @@ namespace Ombi.Core.Engine.V2
|
|||
var results = new List<MovieDbSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAdd(nameof(Anticipated) + langCode + pagesToLoad.Page,
|
||||
async () => await _movieApi.UpcomingTv(langCode, pagesToLoad.Page), DateTime.Now.AddHours(12));
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(Anticipated) + langCode + pagesToLoad.Page,
|
||||
async () => await _movieApi.UpcomingTv(langCode, pagesToLoad.Page), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
var processed = ProcessResults(results);
|
||||
|
@ -148,10 +138,11 @@ namespace Ombi.Core.Engine.V2
|
|||
var results = new List<MovieDbSearchResult>();
|
||||
foreach (var pagesToLoad in pages)
|
||||
{
|
||||
var apiResult = await Cache.GetOrAdd(nameof(Trending) + langCode + pagesToLoad.Page,
|
||||
async () => await _movieApi.TopRatedTv(langCode, pagesToLoad.Page), DateTime.Now.AddHours(12));
|
||||
var apiResult = await Cache.GetOrAddAsync(nameof(Trending) + langCode + pagesToLoad.Page,
|
||||
async () => await _movieApi.TopRatedTv(langCode, pagesToLoad.Page), DateTimeOffset.Now.AddHours(12));
|
||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||
}
|
||||
|
||||
var processed = ProcessResults(results);
|
||||
return await processed;
|
||||
}
|
||||
|
@ -177,22 +168,118 @@ namespace Ombi.Core.Engine.V2
|
|||
return data;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<SearchTvShowViewModel>> ProcessResults<T>(IEnumerable<T> items)
|
||||
|
||||
public async Task<IEnumerable<SearchFullInfoTvShowViewModel>> RecentlyRequestedShows(int currentlyLoaded, int toLoad, CancellationToken cancellationToken)
|
||||
{
|
||||
var langCode = await DefaultLanguageCode(null);
|
||||
|
||||
var results = new List<SearchFullInfoTvShowViewModel>();
|
||||
|
||||
var requestResult = await Cache.GetOrAddAsync(nameof(RecentlyRequestedShows) + "Requests" + toLoad + langCode,
|
||||
async () =>
|
||||
{
|
||||
return await _requestEngine.GetRequests(toLoad, currentlyLoaded, new Models.UI.OrderFilterModel
|
||||
{
|
||||
OrderType = OrderType.RequestedDateDesc
|
||||
});
|
||||
}, DateTimeOffset.Now.AddMinutes(15));
|
||||
|
||||
var movieDBResults = await Cache.GetOrAddAsync(nameof(RecentlyRequestedShows) + toLoad + langCode,
|
||||
async () =>
|
||||
{
|
||||
var responses = new List<TvInfo>();
|
||||
foreach (var movie in requestResult.Collection)
|
||||
{
|
||||
responses.Add(await _movieApi.GetTVInfo(movie.ExternalProviderId.ToString()));
|
||||
}
|
||||
return responses;
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
|
||||
var mapped = _mapper.Map<List<SearchFullInfoTvShowViewModel>>(movieDBResults);
|
||||
|
||||
foreach(var map in mapped)
|
||||
{
|
||||
var processed = await ProcessResult(map);
|
||||
results.Add(processed);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<SearchTvShowViewModel>> ProcessResults(List<MovieDbSearchResult> items)
|
||||
{
|
||||
var retVal = new List<SearchTvShowViewModel>();
|
||||
var settings = await _customization.GetSettingsAsync();
|
||||
|
||||
foreach (var tvMazeSearch in items)
|
||||
{
|
||||
if (DemoCheck(tvMazeSearch.Title))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (settings.HideAvailableFromDiscover)
|
||||
{
|
||||
// To hide, we need to know if it's fully available, the only way to do this is to lookup it's episodes to check if we have every episode
|
||||
var show = await Cache.GetOrAddAsync(nameof(GetShowInformation) + tvMazeSearch.Id.ToString(),
|
||||
async () => await _movieApi.GetTVInfo(tvMazeSearch.Id.ToString()), DateTime.Now.AddHours(12));
|
||||
foreach (var tvSeason in show.seasons.Where(x => x.season_number != 0)) // skip the first season
|
||||
{
|
||||
var seasonEpisodes = await Cache.GetOrAddAsync("SeasonEpisodes" + show.id + tvSeason.season_number, async () =>
|
||||
{
|
||||
return await _movieApi.GetSeasonEpisodes(show.id, tvSeason.season_number, CancellationToken.None);
|
||||
}, DateTimeOffset.Now.AddHours(12));
|
||||
|
||||
MapSeasons(tvMazeSearch.SeasonRequests, tvSeason, seasonEpisodes);
|
||||
}
|
||||
}
|
||||
|
||||
var result = await ProcessResult(tvMazeSearch);
|
||||
if (result == null || settings.HideAvailableFromDiscover && result.Available)
|
||||
if (result == null || settings.HideAvailableFromDiscover && result.FullyAvailable)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
retVal.Add(result);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private static void MapSeasons(List<SeasonRequests> seasonRequests, Season tvSeason, SeasonDetails seasonEpisodes)
|
||||
{
|
||||
foreach (var episode in seasonEpisodes.episodes)
|
||||
{
|
||||
var season = seasonRequests.FirstOrDefault(x => x.SeasonNumber == episode.season_number);
|
||||
if (season == null)
|
||||
{
|
||||
var newSeason = new SeasonRequests
|
||||
{
|
||||
SeasonNumber = episode.season_number,
|
||||
Overview = tvSeason.overview,
|
||||
Episodes = new List<EpisodeRequests>()
|
||||
};
|
||||
newSeason.Episodes.Add(new EpisodeRequests
|
||||
{
|
||||
//Url = episode...ToHttpsUrl(),
|
||||
Title = episode.name,
|
||||
AirDate = episode.air_date.HasValue() ? DateTime.Parse(episode.air_date) : DateTime.MinValue,
|
||||
EpisodeNumber = episode.episode_number,
|
||||
|
||||
});
|
||||
seasonRequests.Add(newSeason);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We already have the season, so just add the episode
|
||||
season.Episodes.Add(new EpisodeRequests
|
||||
{
|
||||
//Url = e.url.ToHttpsUrl(),
|
||||
Title = episode.name,
|
||||
AirDate = episode.air_date.HasValue() ? DateTime.Parse(episode.air_date) : DateTime.MinValue,
|
||||
EpisodeNumber = episode.episode_number,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<SearchTvShowViewModel> ProcessResult<T>(T tvMazeSearch)
|
||||
{
|
||||
var item = _mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
||||
|
@ -216,6 +303,9 @@ namespace Ombi.Core.Engine.V2
|
|||
item.Approved = oldModel.Approved;
|
||||
item.SeasonRequests = oldModel.SeasonRequests;
|
||||
item.RequestId = oldModel.RequestId;
|
||||
item.PlexUrl = oldModel.PlexUrl;
|
||||
item.EmbyUrl = oldModel.EmbyUrl;
|
||||
item.JellyfinUrl = oldModel.JellyfinUrl;
|
||||
|
||||
if (!string.IsNullOrEmpty(item.Images?.Medium))
|
||||
{
|
||||
|
|
|
@ -12,16 +12,19 @@ using Ombi.Helpers;
|
|||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Ombi.Core.Helpers
|
||||
{
|
||||
public class TvShowRequestBuilder
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public TvShowRequestBuilder(ITvMazeApi tvApi, IMovieDbApi movApi)
|
||||
public TvShowRequestBuilder(ITvMazeApi tvApi, IMovieDbApi movApi, ILogger logger)
|
||||
{
|
||||
TvApi = tvApi;
|
||||
MovieDbApi = movApi;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private ITvMazeApi TvApi { get; }
|
||||
|
@ -45,6 +48,7 @@ namespace Ombi.Core.Helpers
|
|||
{
|
||||
if (result.Name.Equals(ShowInfo.name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.LogInformation($"Found matching MovieDb entry for show name {ShowInfo.name}");
|
||||
TheMovieDbRecord = result;
|
||||
var showIds = await MovieDbApi.GetTvExternals(result.Id);
|
||||
ShowInfo.externals.imdb = showIds.imdb_id;
|
||||
|
@ -237,18 +241,19 @@ namespace Ombi.Core.Helpers
|
|||
|
||||
public TvShowRequestBuilder CreateNewRequest(TvRequestViewModel tv)
|
||||
{
|
||||
_logger.LogInformation($"Building Request for {ShowInfo.name} with Provider ID {TheMovieDbRecord?.Id ?? 0}");
|
||||
NewRequest = new TvRequests
|
||||
{
|
||||
Overview = ShowInfo.summary.RemoveHtml(),
|
||||
PosterPath = PosterPath,
|
||||
Title = ShowInfo.name,
|
||||
ReleaseDate = FirstAir,
|
||||
ExternalProviderId = TheMovieDbRecord.Id,
|
||||
ExternalProviderId = TheMovieDbRecord?.Id ?? 0,
|
||||
Status = ShowInfo.status,
|
||||
ImdbId = ShowInfo.externals?.imdb ?? string.Empty,
|
||||
TvDbId = tv.TvDbId,
|
||||
ChildRequests = new List<ChildRequests>(),
|
||||
TotalSeasons = tv.Seasons.Count(),
|
||||
TotalSeasons = tv.Seasons?.Count ?? 0,
|
||||
Background = BackdropPath
|
||||
};
|
||||
NewRequest.ChildRequests.Add(ChildRequest);
|
||||
|
|
|
@ -33,6 +33,14 @@ namespace Ombi.Core.Helpers
|
|||
public async Task<TvShowRequestBuilderV2> GetShowInfo(int id)
|
||||
{
|
||||
TheMovieDbRecord = await MovieDbApi.GetTVInfo(id.ToString());
|
||||
|
||||
// Remove 'Specials Season'
|
||||
var firstSeason = TheMovieDbRecord.seasons.OrderBy(x => x.season_number).FirstOrDefault();
|
||||
if (firstSeason?.season_number == 0)
|
||||
{
|
||||
TheMovieDbRecord.seasons.Remove(firstSeason);
|
||||
}
|
||||
|
||||
BackdropPath = TheMovieDbRecord.Images?.Backdrops?.OrderBy(x => x.VoteCount).ThenBy(x => x.VoteAverage).FirstOrDefault()?.FilePath; ;
|
||||
|
||||
DateTime.TryParse(TheMovieDbRecord.first_air_date, out var dt);
|
||||
|
@ -149,6 +157,10 @@ namespace Ombi.Core.Helpers
|
|||
else if (tv.FirstSeason)
|
||||
{
|
||||
var first = allEpisodes.OrderBy(x => x.season_number).FirstOrDefault();
|
||||
if (first.season_number == 0)
|
||||
{
|
||||
first = allEpisodes.OrderBy(x => x.season_number).Skip(1).FirstOrDefault();
|
||||
}
|
||||
var episodesRequests = new List<EpisodeRequests>();
|
||||
foreach (var ep in allEpisodes)
|
||||
{
|
||||
|
@ -217,7 +229,7 @@ namespace Ombi.Core.Helpers
|
|||
}
|
||||
|
||||
|
||||
public TvShowRequestBuilderV2 CreateNewRequest(TvRequestViewModelV2 tv, int rootPathOverride, int qualityOverride)
|
||||
public TvShowRequestBuilderV2 CreateNewRequest(TvRequestViewModelV2 tv, int rootPathOverride, int qualityOverride, int langProfile)
|
||||
{
|
||||
int.TryParse(TheMovieDbRecord.ExternalIds?.TvDbId, out var tvdbId);
|
||||
NewRequest = new TvRequests
|
||||
|
@ -234,7 +246,8 @@ namespace Ombi.Core.Helpers
|
|||
TotalSeasons = tv.Seasons.Count(),
|
||||
Background = BackdropPath,
|
||||
RootFolder = rootPathOverride,
|
||||
QualityOverride = qualityOverride
|
||||
QualityOverride = qualityOverride,
|
||||
LanguageProfile = langProfile
|
||||
};
|
||||
NewRequest.ChildRequests.Add(ChildRequest);
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ namespace Ombi.Core
|
|||
|
||||
public async Task<string> GetTvBackground(string tvdbId)
|
||||
{
|
||||
var key = await _cache.GetOrAdd(CacheKeys.FanartTv, async () => await _configRepository.GetAsync(Store.Entities.ConfigurationTypes.FanartTv), DateTime.Now.AddDays(1));
|
||||
var images = await _cache.GetOrAdd($"{CacheKeys.FanartTv}tv{tvdbId}", async () => await _fanartTvApi.GetTvImages(int.Parse(tvdbId), key.Value), DateTime.Now.AddDays(1));
|
||||
var key = await _cache.GetOrAddAsync(CacheKeys.FanartTv, () => _configRepository.GetAsync(Store.Entities.ConfigurationTypes.FanartTv), DateTimeOffset.Now.AddDays(1));
|
||||
var images = await _cache.GetOrAddAsync($"{CacheKeys.FanartTv}tv{tvdbId}", () => _fanartTvApi.GetTvImages(int.Parse(tvdbId), key.Value), DateTimeOffset.Now.AddDays(1));
|
||||
|
||||
if (images == null)
|
||||
{
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
public int RequestId { get; set; }
|
||||
public int RootPathOverride { get; set; }
|
||||
public int QualityOverride { get; set; }
|
||||
public int LanguageProfile { get; set; }
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ namespace Ombi.Core.Models.Requests
|
|||
{
|
||||
public bool RequestAll { get; set; }
|
||||
public bool LatestSeason { get; set; }
|
||||
public int? LanguageProfile { get; set; }
|
||||
public bool FirstSeason { get; set; }
|
||||
public List<SeasonsViewModel> Seasons { get; set; } = new List<SeasonsViewModel>();
|
||||
[JsonIgnore]
|
||||
|
|
|
@ -58,9 +58,6 @@ namespace Ombi.Core.Models.Search
|
|||
public bool PartlyAvailable { get; set; }
|
||||
public override RequestType Type => RequestType.TvShow;
|
||||
|
||||
/// <summary>
|
||||
/// Only set on the images call
|
||||
/// </summary>
|
||||
public string BackdropPath { get; set; }
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ namespace Ombi.Core.Models.Search.V2
|
|||
public string Overview { get; set; }
|
||||
public string PosterPath { get; set; }
|
||||
public string Title { get; set; }
|
||||
public DateTime ReleaseDate { get; set; }
|
||||
public DateTime? ReleaseDate { get; set; }
|
||||
|
||||
|
||||
public override RequestType Type => RequestType.Movie;
|
||||
|
|
|
@ -9,6 +9,6 @@ namespace Ombi.Core.Rule.Interfaces
|
|||
{
|
||||
Task<IEnumerable<RuleResult>> StartRequestRules(BaseRequest obj);
|
||||
Task<IEnumerable<RuleResult>> StartSearchRules(SearchViewModel obj);
|
||||
Task<RuleResult> StartSpecificRules(object obj, SpecificRules selectedRule);
|
||||
Task<RuleResult> StartSpecificRules(object obj, SpecificRules selectedRule, string requestOnBehalf);
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ namespace Ombi.Core.Rule.Interfaces
|
|||
{
|
||||
public interface ISpecificRule<T> where T : new()
|
||||
{
|
||||
Task<RuleResult> Execute(T obj);
|
||||
Task<RuleResult> Execute(T obj, string requestOnBehalf);
|
||||
SpecificRules Rule { get; }
|
||||
}
|
||||
}
|
|
@ -58,13 +58,13 @@ namespace Ombi.Core.Rule
|
|||
return results;
|
||||
}
|
||||
|
||||
public async Task<RuleResult> StartSpecificRules(object obj, SpecificRules selectedRule)
|
||||
public async Task<RuleResult> StartSpecificRules(object obj, SpecificRules selectedRule, string requestOnBehalf)
|
||||
{
|
||||
foreach (var rule in SpecificRules)
|
||||
{
|
||||
if (selectedRule == rule.Rule)
|
||||
{
|
||||
var result = await rule.Execute(obj);
|
||||
var result = await rule.Execute(obj, requestOnBehalf);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using Ombi.Core.Rule.Interfaces;
|
|||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Core.Rule.Rules.Request
|
||||
{
|
||||
|
@ -60,6 +61,7 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
{
|
||||
foreach (var season in child.SeasonRequests)
|
||||
{
|
||||
var episodesToRemove = new List<EpisodeRequests>();
|
||||
var currentSeasonRequest =
|
||||
content.Episodes.Where(x => x.SeasonNumber == season.SeasonNumber).ToList();
|
||||
if (!currentSeasonRequest.Any())
|
||||
|
@ -68,12 +70,24 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
}
|
||||
foreach (var e in season.Episodes)
|
||||
{
|
||||
var hasEpisode = currentSeasonRequest.Any(x => x.EpisodeNumber == e.EpisodeNumber);
|
||||
if (hasEpisode)
|
||||
var existingEpRequest = currentSeasonRequest.FirstOrDefault(x => x.EpisodeNumber == e.EpisodeNumber);
|
||||
if (existingEpRequest != null)
|
||||
{
|
||||
return Fail($"We already have episodes requested from series {child.Title}");
|
||||
episodesToRemove.Add(e);
|
||||
}
|
||||
}
|
||||
|
||||
episodesToRemove.ForEach(x =>
|
||||
{
|
||||
season.Episodes.Remove(x);
|
||||
});
|
||||
}
|
||||
|
||||
var anyEpisodes = child.SeasonRequests.SelectMany(x => x.Episodes).Any();
|
||||
|
||||
if (!anyEpisodes)
|
||||
{
|
||||
return Fail($"We already have episodes requested from series {child.Title}");
|
||||
}
|
||||
|
||||
return Success();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Rule.Interfaces;
|
||||
|
@ -41,15 +42,30 @@ namespace Ombi.Core.Rule.Rules.Request
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var episodesToRemove = new List<EpisodeRequests>();
|
||||
foreach (var e in season.Episodes)
|
||||
{
|
||||
var hasEpisode = currentSeasonRequest.Episodes.Any(x => x.EpisodeNumber == e.EpisodeNumber);
|
||||
if (hasEpisode)
|
||||
var existingEpRequest = currentSeasonRequest.Episodes.FirstOrDefault(x => x.EpisodeNumber == e.EpisodeNumber);
|
||||
if (existingEpRequest != null)
|
||||
{
|
||||
return Fail($"We already have episodes requested from series {tv.Title}");
|
||||
episodesToRemove.Add(e);
|
||||
}
|
||||
}
|
||||
|
||||
episodesToRemove.ForEach(x =>
|
||||
{
|
||||
season.Episodes.Remove(x);
|
||||
});
|
||||
}
|
||||
|
||||
var anyEpisodes = tv.SeasonRequests.SelectMany(x => x.Episodes).Any();
|
||||
|
||||
if (!anyEpisodes)
|
||||
{
|
||||
return Fail($"We already have episodes requested from series {tv.Title}");
|
||||
}
|
||||
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
|
|
|
@ -13,12 +13,12 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
{
|
||||
public static void CheckForUnairedEpisodes(SearchTvShowViewModel search)
|
||||
{
|
||||
foreach (var season in search.SeasonRequests)
|
||||
foreach (var season in search.SeasonRequests.ToList())
|
||||
{
|
||||
// If we have all the episodes for this season, then this season is available
|
||||
if (season.Episodes.All(x => x.Available))
|
||||
{
|
||||
season.SeasonAvailable = true;
|
||||
season.SeasonAvailable = true;
|
||||
}
|
||||
}
|
||||
if (search.SeasonRequests.All(x => x.Episodes.All(e => e.Available)))
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
var s = await EmbySettings.GetSettingsAsync();
|
||||
if (s.Enable)
|
||||
{
|
||||
var server = s.Servers.FirstOrDefault(x => x.ServerHostname != null);
|
||||
var server = s.Servers.FirstOrDefault();
|
||||
if ((server?.ServerHostname ?? string.Empty).HasValue())
|
||||
{
|
||||
obj.EmbyUrl = EmbyHelper.GetEmbyMediaUrl(item.EmbyId, server?.ServerId, server?.ServerHostname);
|
||||
|
|
|
@ -9,7 +9,7 @@ using Ombi.Store.Repository;
|
|||
|
||||
namespace Ombi.Core.Rule.Rules.Search
|
||||
{
|
||||
public class LidarrAlbumCacheRule : BaseSearchRule, IRules<SearchViewModel>
|
||||
public class LidarrAlbumCacheRule : SpecificRule, ISpecificRule<object>
|
||||
{
|
||||
public LidarrAlbumCacheRule(IExternalRepository<LidarrAlbumCache> db)
|
||||
{
|
||||
|
@ -18,7 +18,9 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
|
||||
private readonly IExternalRepository<LidarrAlbumCache> _db;
|
||||
|
||||
public Task<RuleResult> Execute(SearchViewModel objec)
|
||||
public override SpecificRules Rule => SpecificRules.LidarrAlbum;
|
||||
|
||||
public Task<RuleResult> Execute(object objec, string requestOnBehalf)
|
||||
{
|
||||
if (objec is SearchAlbumViewModel obj)
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
|
||||
private readonly IExternalRepository<LidarrArtistCache> _db;
|
||||
|
||||
public Task<RuleResult> Execute(object objec)
|
||||
public Task<RuleResult> Execute(object objec, string requestOnBehalf)
|
||||
{
|
||||
var obj = (SearchArtistViewModel) objec;
|
||||
// Check if it's in Lidarr
|
||||
|
@ -30,6 +30,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
return Task.FromResult(Success());
|
||||
}
|
||||
|
||||
|
||||
public override SpecificRules Rule => SpecificRules.LidarrArtist;
|
||||
}
|
||||
}
|
|
@ -25,10 +25,14 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
PlexServerContent item = null;
|
||||
var useImdb = false;
|
||||
var useTheMovieDb = false;
|
||||
var useId = false;
|
||||
var useTvDb = false;
|
||||
|
||||
PlexMediaTypeEntity type = ConvertType(obj.Type);
|
||||
|
||||
if (obj.ImdbId.HasValue())
|
||||
{
|
||||
item = await PlexContentRepository.Get(obj.ImdbId);
|
||||
item = await PlexContentRepository.GetByType(obj.ImdbId, ProviderType.ImdbId, type);
|
||||
if (item != null)
|
||||
{
|
||||
useImdb = true;
|
||||
|
@ -36,9 +40,17 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
}
|
||||
if (item == null)
|
||||
{
|
||||
if (obj.Id > 0)
|
||||
{
|
||||
item = await PlexContentRepository.GetByType(obj.Id.ToString(), ProviderType.TheMovieDbId, type);
|
||||
if (item != null)
|
||||
{
|
||||
useId = true;
|
||||
}
|
||||
}
|
||||
if (obj.TheMovieDbId.HasValue())
|
||||
{
|
||||
item = await PlexContentRepository.Get(obj.TheMovieDbId);
|
||||
item = await PlexContentRepository.GetByType(obj.TheMovieDbId, ProviderType.TheMovieDbId, type);
|
||||
if (item != null)
|
||||
{
|
||||
useTheMovieDb = true;
|
||||
|
@ -49,7 +61,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
{
|
||||
if (obj.TheTvDbId.HasValue())
|
||||
{
|
||||
item = await PlexContentRepository.Get(obj.TheTvDbId);
|
||||
item = await PlexContentRepository.GetByType(obj.TheTvDbId, ProviderType.TvDbId, type);
|
||||
if (item != null)
|
||||
{
|
||||
useTvDb = true;
|
||||
|
@ -60,6 +72,11 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
|
||||
if (item != null)
|
||||
{
|
||||
if (useId)
|
||||
{
|
||||
obj.TheMovieDbId = obj.Id.ToString();
|
||||
useTheMovieDb = true;
|
||||
}
|
||||
obj.Available = true;
|
||||
obj.PlexUrl = item.Url;
|
||||
obj.Quality = item.Quality;
|
||||
|
@ -71,9 +88,9 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
if (search.SeasonRequests.Any())
|
||||
{
|
||||
var allEpisodes = PlexContentRepository.GetAllEpisodes();
|
||||
foreach (var season in search.SeasonRequests)
|
||||
foreach (var season in search.SeasonRequests.ToList())
|
||||
{
|
||||
foreach (var episode in season.Episodes)
|
||||
foreach (var episode in season.Episodes.ToList())
|
||||
{
|
||||
await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb, Log);
|
||||
}
|
||||
|
@ -86,6 +103,12 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
return Success();
|
||||
}
|
||||
|
||||
|
||||
private PlexMediaTypeEntity ConvertType(RequestType type) =>
|
||||
type switch
|
||||
{
|
||||
RequestType.Movie => PlexMediaTypeEntity.Movie,
|
||||
RequestType.TvShow => PlexMediaTypeEntity.Show,
|
||||
_ => PlexMediaTypeEntity.Movie,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Ombi.Core.Models.Search;
|
||||
|
@ -6,6 +7,7 @@ using Ombi.Helpers;
|
|||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
|
||||
namespace Ombi.Core.Rule.Rules
|
||||
{
|
||||
|
@ -23,7 +25,7 @@ namespace Ombi.Core.Rule.Rules
|
|||
if (obj.RequestType == RequestType.TvShow)
|
||||
{
|
||||
var vm = (ChildRequests) obj;
|
||||
var result = await _ctx.SonarrCache.FirstOrDefaultAsync(x => x.TvDbId == vm.Id); // TODO lookup the external provider in the sonarr sync to use themoviedb
|
||||
var result = await _ctx.SonarrCache.FirstOrDefaultAsync(x => x.TheMovieDbId == vm.Id);
|
||||
if (result != null)
|
||||
{
|
||||
if (vm.SeasonRequests.Any())
|
||||
|
@ -31,17 +33,30 @@ namespace Ombi.Core.Rule.Rules
|
|||
var sonarrEpisodes = _ctx.SonarrEpisodeCache;
|
||||
foreach (var season in vm.SeasonRequests)
|
||||
{
|
||||
var toRemove = new List<EpisodeRequests>();
|
||||
foreach (var ep in season.Episodes)
|
||||
{
|
||||
// Check if we have it
|
||||
var monitoredInSonarr = sonarrEpisodes.Any(x =>
|
||||
var monitoredInSonarr = sonarrEpisodes.FirstOrDefault(x =>
|
||||
x.EpisodeNumber == ep.EpisodeNumber && x.SeasonNumber == season.SeasonNumber
|
||||
&& x.TvDbId == vm.Id);
|
||||
if (monitoredInSonarr)
|
||||
&& x.MovieDbId == vm.Id);
|
||||
if (monitoredInSonarr != null)
|
||||
{
|
||||
return new RuleResult{Message = "We already have this request, please choose the \"Select...\" option to refine your request"};
|
||||
}
|
||||
toRemove.Add(ep);
|
||||
}
|
||||
}
|
||||
|
||||
toRemove.ForEach(x =>
|
||||
{
|
||||
season.Episodes.Remove(x);
|
||||
});
|
||||
|
||||
}
|
||||
var anyEpisodes = vm.SeasonRequests.SelectMany(x => x.Episodes).Any();
|
||||
|
||||
if (!anyEpisodes)
|
||||
{
|
||||
return new RuleResult { Message = $"We already have episodes requested from series {vm.Title}" };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,11 +22,20 @@ namespace Ombi.Core.Rule.Rules.Specific
|
|||
private OmbiUserManager UserManager { get; }
|
||||
private ISettingsService<OmbiSettings> Settings { get; }
|
||||
|
||||
public async Task<RuleResult> Execute(object obj)
|
||||
public async Task<RuleResult> Execute(object obj, string requestOnBehalf)
|
||||
{
|
||||
var req = (BaseRequest)obj;
|
||||
var canRequestonBehalf = requestOnBehalf.HasValue();
|
||||
var settings = await Settings.GetSettingsAsync();
|
||||
var sendNotification = true;
|
||||
|
||||
if (settings.DoNotSendNotificationsForAutoApprove && canRequestonBehalf)
|
||||
{
|
||||
return new RuleResult
|
||||
{
|
||||
Success = false
|
||||
};
|
||||
}
|
||||
var requestedUser = await UserManager.Users.FirstOrDefaultAsync(x => x.Id == req.RequestedUserId);
|
||||
if (req.RequestType == RequestType.Movie)
|
||||
{
|
||||
|
|
|
@ -125,7 +125,6 @@ namespace Ombi.Core.Senders
|
|||
|
||||
private async Task<SenderResult> SendToRadarr(MovieRequests model, RadarrSettings settings)
|
||||
{
|
||||
var v3 = settings.V3;
|
||||
var qualityToUse = int.Parse(settings.DefaultQualityProfile);
|
||||
|
||||
var rootFolderPath = settings.DefaultRootPath;
|
||||
|
@ -159,30 +158,16 @@ namespace Ombi.Core.Senders
|
|||
|
||||
List<MovieResponse> movies;
|
||||
// Check if the movie already exists? Since it could be unmonitored
|
||||
if (settings.V3)
|
||||
{
|
||||
movies = await _radarrV3Api.GetMovies(settings.ApiKey, settings.FullUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
movies = await _radarrV2Api.GetMovies(settings.ApiKey, settings.FullUri);
|
||||
}
|
||||
|
||||
movies = await _radarrV3Api.GetMovies(settings.ApiKey, settings.FullUri);
|
||||
|
||||
var existingMovie = movies.FirstOrDefault(x => x.tmdbId == model.TheMovieDbId);
|
||||
if (existingMovie == null)
|
||||
{
|
||||
RadarrAddMovie result;
|
||||
if (v3)
|
||||
{
|
||||
result = await _radarrV3Api.AddMovie(model.TheMovieDbId, model.Title, model.ReleaseDate.Year,
|
||||
qualityToUse, rootFolderPath, settings.ApiKey, settings.FullUri, !settings.AddOnly,
|
||||
settings.MinimumAvailability);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await _radarrV2Api.AddMovie(model.TheMovieDbId, model.Title, model.ReleaseDate.Year,
|
||||
qualityToUse, rootFolderPath, settings.ApiKey, settings.FullUri, !settings.AddOnly,
|
||||
settings.MinimumAvailability);
|
||||
}
|
||||
var result = await _radarrV3Api.AddMovie(model.TheMovieDbId, model.Title, model.ReleaseDate.Year,
|
||||
qualityToUse, rootFolderPath, settings.ApiKey, settings.FullUri, !settings.AddOnly,
|
||||
settings.MinimumAvailability);
|
||||
|
||||
if (!string.IsNullOrEmpty(result.Error?.message))
|
||||
{
|
||||
_log.LogError(LoggingEvents.RadarrCacher, result.Error.message);
|
||||
|
@ -199,23 +184,12 @@ namespace Ombi.Core.Senders
|
|||
{
|
||||
// let's set it to monitored and search for it
|
||||
existingMovie.monitored = true;
|
||||
if (v3)
|
||||
|
||||
await _radarrV3Api.UpdateMovie(existingMovie, settings.ApiKey, settings.FullUri);
|
||||
// Search for it
|
||||
if (!settings.AddOnly)
|
||||
{
|
||||
await _radarrV3Api.UpdateMovie(existingMovie, settings.ApiKey, settings.FullUri);
|
||||
// Search for it
|
||||
if (!settings.AddOnly)
|
||||
{
|
||||
await _radarrV3Api.MovieSearch(new[] { existingMovie.id }, settings.ApiKey, settings.FullUri);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await _radarrV2Api.UpdateMovie(existingMovie, settings.ApiKey, settings.FullUri);
|
||||
// Search for it
|
||||
if (!settings.AddOnly)
|
||||
{
|
||||
await _radarrV2Api.MovieSearch(new[] { existingMovie.id }, settings.ApiKey, settings.FullUri);
|
||||
}
|
||||
await _radarrV3Api.MovieSearch(new[] { existingMovie.id }, settings.ApiKey, settings.FullUri);
|
||||
}
|
||||
|
||||
return new SenderResult { Success = true, Sent = true };
|
||||
|
@ -226,18 +200,9 @@ namespace Ombi.Core.Senders
|
|||
|
||||
private async Task<string> RadarrRootPath(int overrideId, RadarrSettings settings)
|
||||
{
|
||||
if (settings.V3)
|
||||
{
|
||||
var paths = await _radarrV3Api.GetRootFolders(settings.ApiKey, settings.FullUri);
|
||||
var selectedPath = paths.FirstOrDefault(x => x.id == overrideId);
|
||||
return selectedPath?.path ?? string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
var paths = await _radarrV2Api.GetRootFolders(settings.ApiKey, settings.FullUri);
|
||||
var selectedPath = paths.FirstOrDefault(x => x.id == overrideId);
|
||||
return selectedPath?.path ?? string.Empty;
|
||||
}
|
||||
var paths = await _radarrV3Api.GetRootFolders(settings.ApiKey, settings.FullUri);
|
||||
var selectedPath = paths.FirstOrDefault(x => x.id == overrideId);
|
||||
return selectedPath?.path ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -158,6 +158,8 @@ namespace Ombi.Core.Senders
|
|||
}
|
||||
|
||||
int qualityToUse;
|
||||
var sonarrV3 = s.V3;
|
||||
var languageProfileId = s.LanguageProfile;
|
||||
string rootFolderPath;
|
||||
string seriesType;
|
||||
|
||||
|
@ -167,8 +169,17 @@ namespace Ombi.Core.Senders
|
|||
{
|
||||
// Get the root path from the rootfolder selected.
|
||||
// For some reason, if we haven't got one use the first root folder in Sonarr
|
||||
rootFolderPath = await GetSonarrRootPath(int.Parse(s.RootPathAnime), s);
|
||||
int.TryParse(s.QualityProfileAnime, out qualityToUse);
|
||||
if (!int.TryParse(s.RootPathAnime, out int animePath))
|
||||
{
|
||||
animePath = int.Parse(s.RootPath); // Set it to the main root folder if we have no anime folder.
|
||||
}
|
||||
rootFolderPath = await GetSonarrRootPath(animePath, s);
|
||||
languageProfileId = s.LanguageProfileAnime > 0 ? s.LanguageProfileAnime : s.LanguageProfile;
|
||||
|
||||
if (!int.TryParse(s.QualityProfileAnime, out qualityToUse))
|
||||
{
|
||||
qualityToUse = int.Parse(s.QualityProfile);
|
||||
}
|
||||
if (profiles != null)
|
||||
{
|
||||
if (profiles.SonarrRootPathAnime > 0)
|
||||
|
@ -181,7 +192,6 @@ namespace Ombi.Core.Senders
|
|||
}
|
||||
}
|
||||
seriesType = "anime";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -220,11 +230,16 @@ namespace Ombi.Core.Senders
|
|||
rootFolderPath = await GetSonarrRootPath(rootfolderOverride, s);
|
||||
}
|
||||
}
|
||||
|
||||
// Are we using v3 sonarr?
|
||||
var sonarrV3 = s.V3;
|
||||
var languageProfileId = s.LanguageProfile;
|
||||
|
||||
if (model.ParentRequest.LanguageProfile.HasValue)
|
||||
{
|
||||
var languageProfile = model.ParentRequest.LanguageProfile.Value;
|
||||
if (languageProfile > 0)
|
||||
{
|
||||
languageProfileId = languageProfile;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Does the series actually exist?
|
||||
|
@ -264,6 +279,10 @@ namespace Ombi.Core.Senders
|
|||
var seasonsToAdd = GetSeasonsToCreate(model);
|
||||
newSeries.seasons = seasonsToAdd;
|
||||
var result = await SonarrApi.AddSeries(newSeries, s.ApiKey, s.FullUri);
|
||||
if (result?.ErrorMessages?.Any() ?? false)
|
||||
{
|
||||
throw new Exception(string.Join(',', result.ErrorMessages));
|
||||
}
|
||||
existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri);
|
||||
await SendToSonarr(model, existingSeries, s);
|
||||
}
|
||||
|
@ -407,7 +426,6 @@ namespace Ombi.Core.Senders
|
|||
await SonarrApi.SeasonPass(s.ApiKey, s.FullUri, result);
|
||||
}
|
||||
|
||||
|
||||
if (!s.AddOnly)
|
||||
{
|
||||
await SearchForRequest(model, sonarrEpList, result, s, episodesToUpdate);
|
||||
|
|
|
@ -23,7 +23,6 @@ using Ombi.Notifications;
|
|||
using Ombi.Schedule;
|
||||
using Ombi.Schedule.Jobs;
|
||||
using Ombi.Settings.Settings;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Notifications.Agents;
|
||||
using Ombi.Schedule.Jobs.Radarr;
|
||||
|
@ -68,6 +67,8 @@ using Ombi.Api.MusicBrainz;
|
|||
using Ombi.Api.Twilio;
|
||||
using Ombi.Api.CloudService;
|
||||
using Ombi.Api.RottenTomatoes;
|
||||
using System.Net.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Ombi.DependencyInjection
|
||||
{
|
||||
|
@ -119,14 +120,24 @@ namespace Ombi.DependencyInjection
|
|||
|
||||
public static void RegisterHttp(this IServiceCollection services)
|
||||
{
|
||||
var runtimeVersion = AssemblyHelper.GetRuntimeVersion();
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
services.AddScoped<IPrincipal>(sp => sp.GetService<IHttpContextAccessor>().HttpContext.User);
|
||||
services.AddHttpClient("OmbiClient", client =>
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("User-Agent", $"Ombi/{runtimeVersion} (https://ombi.io/)");
|
||||
}).ConfigurePrimaryHttpMessageHandler(() =>
|
||||
{
|
||||
var httpClientHandler = new HttpClientHandler();
|
||||
httpClientHandler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true;
|
||||
|
||||
return httpClientHandler;
|
||||
});
|
||||
}
|
||||
|
||||
public static void RegisterApi(this IServiceCollection services)
|
||||
{
|
||||
services.AddScoped<IApi, Api.Api>();
|
||||
services.AddScoped<IOmbiHttpClient, OmbiHttpClient>(); // https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/
|
||||
services.AddScoped<IApi, Api.Api>(s => new Api.Api(s.GetRequiredService<ILogger<Api.Api>>(), s.GetRequiredService<IHttpClientFactory>().CreateClient("OmbiClient")));
|
||||
services.AddTransient<IMovieDbApi, Api.TheMovieDb.TheMovieDbApi>();
|
||||
services.AddTransient<IPlexApi, PlexApi>();
|
||||
services.AddTransient<IEmbyApi, EmbyApi>();
|
||||
|
@ -195,6 +206,7 @@ namespace Ombi.DependencyInjection
|
|||
services.AddTransient<IEmailProvider, GenericEmailProvider>();
|
||||
services.AddTransient<INotificationHelper, NotificationHelper>();
|
||||
services.AddSingleton<ICacheService, CacheService>();
|
||||
services.AddSingleton<IMediaCacheService, MediaCacheService>();
|
||||
services.AddScoped<IImageService, ImageService>();
|
||||
|
||||
services.AddTransient<IDiscordNotification, DiscordNotification>();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Ombi.HealthChecks.Checks
|
|||
using (var scope = CreateScope())
|
||||
{
|
||||
var settingsProvider = scope.ServiceProvider.GetRequiredService<ISettingsService<RadarrSettings>>();
|
||||
var api = scope.ServiceProvider.GetRequiredService<IRadarrApi>();
|
||||
var api = scope.ServiceProvider.GetRequiredService<IRadarrV3Api>();
|
||||
var settings = await settingsProvider.GetSettingsAsync();
|
||||
if (!settings.Enabled)
|
||||
{
|
||||
|
|
|
@ -61,6 +61,7 @@ namespace Ombi.Helpers.Tests
|
|||
get
|
||||
{
|
||||
yield return new TestCaseData("plex://movie/5e1632df2d4d84003e48e54e|imdb://tt9178402|tmdb://610201", new ProviderId { ImdbId = "tt9178402", TheMovieDb = "610201" }).SetName("V2 Regular Plex Id");
|
||||
yield return new TestCaseData("plex://movie/5e1632df2d4d84003e48e54e|imdb://tt9178402|tmdb://610201|thetvdb://12345", new ProviderId { ImdbId = "tt9178402", TheMovieDb = "610201", TheTvDb = "12345" }).SetName("V2 Regular Plex Id w/ tvdb");
|
||||
yield return new TestCaseData("plex://movie/5d7768253c3c2a001fbcab72|imdb://tt0119567|tmdb://330", new ProviderId { ImdbId = "tt0119567", TheMovieDb = "330" }).SetName("V2 Regular Plex Id Another");
|
||||
yield return new TestCaseData("plex://movie/5d7768253c3c2a001fbcab72|imdb://tt0119567", new ProviderId { ImdbId = "tt0119567" }).SetName("V2 Regular Plex Id Single Imdb");
|
||||
yield return new TestCaseData("plex://movie/5d7768253c3c2a001fbcab72|tmdb://330", new ProviderId { TheMovieDb = "330" }).SetName("V2 Regular Plex Id Single Tmdb");
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
|
@ -8,7 +9,8 @@ namespace Ombi.Helpers
|
|||
public static string GetRuntimeVersion()
|
||||
{
|
||||
ApplicationEnvironment app = PlatformServices.Default.Application;
|
||||
return app.ApplicationVersion;
|
||||
var split = app.ApplicationVersion.Split('.');
|
||||
return string.Join('.', split.Take(3));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,48 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Nito.AsyncEx;
|
||||
using LazyCache;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public class CacheService : ICacheService
|
||||
{
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
private readonly AsyncLock _mutex = new AsyncLock();
|
||||
public CacheService(IMemoryCache memoryCache)
|
||||
protected readonly IAppCache _memoryCache;
|
||||
public CacheService(IAppCache memoryCache)
|
||||
{
|
||||
_memoryCache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache));
|
||||
_memoryCache = memoryCache;
|
||||
}
|
||||
|
||||
public async Task<T> GetOrAdd<T>(string cacheKey, Func<Task<T>> factory, DateTime absoluteExpiration = default(DateTime), CancellationToken cancellationToken = default(CancellationToken))
|
||||
public virtual async Task<T> GetOrAddAsync<T>(string cacheKey, Func<Task<T>> factory, DateTimeOffset absoluteExpiration = default)
|
||||
{
|
||||
if (absoluteExpiration == default(DateTime))
|
||||
if (absoluteExpiration == default)
|
||||
{
|
||||
absoluteExpiration = DateTime.Now.AddHours(1);
|
||||
}
|
||||
// locks get and set internally
|
||||
if (_memoryCache.TryGetValue<T>(cacheKey, out var result))
|
||||
{
|
||||
return result;
|
||||
absoluteExpiration = DateTimeOffset.Now.AddHours(1);
|
||||
}
|
||||
|
||||
if (_memoryCache.TryGetValue(cacheKey, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
result = await factory();
|
||||
_memoryCache.Set(cacheKey, result, absoluteExpiration);
|
||||
|
||||
return result;
|
||||
return await _memoryCache.GetOrAddAsync<T>(cacheKey, () => factory(), absoluteExpiration);
|
||||
}
|
||||
|
||||
public void Remove(string key)
|
||||
|
@ -50,28 +28,10 @@ namespace Ombi.Helpers
|
|||
_memoryCache.Remove(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public T GetOrAdd<T>(string cacheKey, Func<T> factory, DateTime absoluteExpiration)
|
||||
public T GetOrAdd<T>(string cacheKey, Func<T> factory, DateTimeOffset absoluteExpiration)
|
||||
{
|
||||
// locks get and set internally
|
||||
if (_memoryCache.TryGetValue<T>(cacheKey, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
lock (TypeLock<T>.Lock)
|
||||
{
|
||||
if (_memoryCache.TryGetValue(cacheKey, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = factory();
|
||||
_memoryCache.Set(cacheKey, result, absoluteExpiration);
|
||||
|
||||
return result;
|
||||
}
|
||||
return _memoryCache.GetOrAdd<T>(cacheKey, () => factory(), absoluteExpiration);
|
||||
}
|
||||
|
||||
private static class TypeLock<T>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace Ombi.Helpers
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public class DemoSingleton
|
||||
{
|
||||
|
@ -10,4 +12,460 @@
|
|||
|
||||
public bool Demo { get; set; }
|
||||
}
|
||||
|
||||
public static class ExcludedDemo
|
||||
{
|
||||
public static HashSet<string> ExcludedContent => new HashSet<string>
|
||||
{
|
||||
"101 Dalmatians",
|
||||
"102 Dalmatians",
|
||||
"20,000 Leagues Under the Sea",
|
||||
"A Bug's Life",
|
||||
"A Far Off Place",
|
||||
"A Goofy Movie",
|
||||
"A Kid in King Arthur's Court",
|
||||
"A Tale of Two Critters",
|
||||
"A Tiger Walks",
|
||||
"A Wrinkle in Time",
|
||||
"ABCD 2",
|
||||
"African Cats",
|
||||
"Air Bud",
|
||||
"Air Bud: Golden Receiver",
|
||||
"Aladdin",
|
||||
"Aladdin",
|
||||
"Alexander and the Terrible, Horrible, No Good, Very Bad Day",
|
||||
"Alice Through the Looking Glass",
|
||||
"Alice in Wonderland",
|
||||
"Alice in Wonderland",
|
||||
"Aliens of the Deep",
|
||||
"Almost Angels",
|
||||
"America's Heart and Soul",
|
||||
"Amy",
|
||||
"Anaganaga O Dheerudu",
|
||||
"Angels in the Outfield",
|
||||
"Arjun: The Warrior Prince",
|
||||
"Around the World in 80 Days",
|
||||
"Artemis Fowl",
|
||||
"Atlantis: The Lost Empire",
|
||||
"Babes in Toyland",
|
||||
"Bambi",
|
||||
"Bears",
|
||||
"Beauty and the Beast",
|
||||
"Beauty and the Beast",
|
||||
"Bedknobs and Broomsticks",
|
||||
"Bedtime Stories",
|
||||
"Benji the Hunted",
|
||||
"Beverly Hills Chihuahua",
|
||||
"Big Hero 6",
|
||||
"Big Red",
|
||||
"Blackbeard's Ghost",
|
||||
"Blank Check",
|
||||
"Blue",
|
||||
"Bolt",
|
||||
"Bon Voyage!",
|
||||
"Born in China",
|
||||
"Brave",
|
||||
"Bridge to Terabithia",
|
||||
"Brother Bear",
|
||||
"Candleshoe",
|
||||
"Cars",
|
||||
"Cars 2",
|
||||
"Cars 3",
|
||||
"Charley and the Angel",
|
||||
"Charlie, the Lonesome Cougar",
|
||||
"Cheetah",
|
||||
"Chicken Little",
|
||||
"Chimpanzee",
|
||||
"Christopher Robin",
|
||||
"Cinderella",
|
||||
"Cinderella",
|
||||
"Coco",
|
||||
"College Road Trip",
|
||||
"Condorman",
|
||||
"Confessions of a Teenage Drama Queen",
|
||||
"Cool Runnings",
|
||||
"D2: The Mighty Ducks",
|
||||
"D3: The Mighty Ducks",
|
||||
"Dangal",
|
||||
"Darby O'Gill and the Little People",
|
||||
"Dasavathaaram",
|
||||
"Davy Crockett and the River Pirates",
|
||||
"Davy Crockett, King of the Wild Frontier",
|
||||
"Dinosaur",
|
||||
"Disney's A Christmas Carol",
|
||||
"Disney's The Kid",
|
||||
"Do Dooni Chaar",
|
||||
"Dolphin Reef",
|
||||
"Doug's 1st Movie",
|
||||
"Dragonslayer",
|
||||
"DuckTales the Movie: Treasure of the Lost Lamp",
|
||||
"Dumbo",
|
||||
"Dumbo",
|
||||
"Earth",
|
||||
"Eight Below",
|
||||
"Emil and the Detectives",
|
||||
"Enchanted",
|
||||
"Endurance",
|
||||
"Escape to Witch Mountain",
|
||||
"Expedition China",
|
||||
"Fantasia",
|
||||
"Fantasia 2000",
|
||||
"Finding Dory",
|
||||
"Finding Nemo",
|
||||
"First Kid",
|
||||
"Flight of the Navigator",
|
||||
"Flubber",
|
||||
"Follow Me, Boys!",
|
||||
"Frank and Ollie",
|
||||
"Frankenweenie",
|
||||
"Freaky Friday",
|
||||
"Freaky Friday",
|
||||
"Frozen",
|
||||
"Frozen II",
|
||||
"Onward",
|
||||
"Star Wars",
|
||||
"Raya",
|
||||
"Mandalorian",
|
||||
"Fun and Fancy Free",
|
||||
"G-Force",
|
||||
"George of the Jungle",
|
||||
"Ghost in the Shell 2: Innocence GITS2",
|
||||
"Ghost of the Mountains",
|
||||
"Ghosts of the Abyss",
|
||||
"Glory Road",
|
||||
"Greyfriars Bobby",
|
||||
"Growing Up Wild",
|
||||
"Gus",
|
||||
"Hannah Montana and Miley Cyrus: Best of Both Worlds Concert",
|
||||
"Hannah Montana: The Movie",
|
||||
"Heavyweights",
|
||||
"Herbie Goes Bananas",
|
||||
"Herbie Goes to Monte Carlo",
|
||||
"Herbie Rides Again",
|
||||
"Herbie: Fully Loaded",
|
||||
"Hercules",
|
||||
"High School Musical 3: Senior Year",
|
||||
"Hocus Pocus",
|
||||
"Holes",
|
||||
"Home on the Range",
|
||||
"Homeward Bound II: Lost in San Francisco",
|
||||
"Homeward Bound: The Incredible Journey",
|
||||
"Honey, I Blew Up the Kid",
|
||||
"Honey, I Shrunk the Kids",
|
||||
"Hot Lead and Cold Feet",
|
||||
"I'll Be Home for Christmas",
|
||||
"Ice Princess",
|
||||
"In Search of the Castaways",
|
||||
"Incredibles 2",
|
||||
"Inside Out",
|
||||
"Inspector Gadget",
|
||||
"Into the Woods",
|
||||
"Invincible",
|
||||
"Iron Will",
|
||||
"Jagga Jasoos",
|
||||
"James and the Giant Peach",
|
||||
"John Carter",
|
||||
"Johnny Tremain",
|
||||
"Jonas Brothers: The 3D Concert Experience",
|
||||
"Jungle 2 Jungle",
|
||||
"Jungle Cat",
|
||||
"Khoobsurat",
|
||||
"Kidnapped",
|
||||
"King of the Grizzlies",
|
||||
"L'Empereur - March of the Penguins 2: The Next Step[a]",
|
||||
"Lady and the Tramp",
|
||||
"Lady and the Tramp",
|
||||
"Lilly the Witch: The Dragon and the Magic Book",
|
||||
"Lilly the Witch: The Journey to Mandolan",
|
||||
"Lilo & Stitch",
|
||||
"Lt. Robin Crusoe, U.S.N.",
|
||||
"Make Mine Music",
|
||||
"Maleficent",
|
||||
"Maleficent: Mistress of Evil",
|
||||
"Man of the House",
|
||||
"Mars Needs Moms",
|
||||
"Mary Poppins",
|
||||
"Mary Poppins Returns",
|
||||
"Max Keeble's Big Move",
|
||||
"McFarland, USA",
|
||||
"Meet the Deedles",
|
||||
"Meet the Robinsons",
|
||||
"Melody Time",
|
||||
"Midnight Madness",
|
||||
"Mighty Joe Young",
|
||||
"Million Dollar Arm",
|
||||
"Miracle",
|
||||
"Miracle of the White Stallions",
|
||||
"Moana",
|
||||
"Monkey Kingdom",
|
||||
"Monkeys, Go Home!",
|
||||
"Monsters University",
|
||||
"Monsters, Inc.",
|
||||
"Moon Pilot",
|
||||
"Morning Light",
|
||||
"Mr. Magoo",
|
||||
"Mulan",
|
||||
"Muppet Treasure Island",
|
||||
"Muppets Most Wanted",
|
||||
"My Favorite Martian",
|
||||
"Napoleon and Samantha",
|
||||
"National Treasure",
|
||||
"National Treasure: Book of Secrets",
|
||||
"Never Cry Wolf",
|
||||
"Never a Dull Moment",
|
||||
"Newsies",
|
||||
"Night Crossing",
|
||||
"Nikki, Wild Dog of the North",
|
||||
"No Deposit, No Return",
|
||||
"Now You See Him, Now You Don't",
|
||||
"Oceans",
|
||||
"Old Dogs",
|
||||
"Old Yeller",
|
||||
"Oliver & Company",
|
||||
"One Hundred and One Dalmatians",
|
||||
"One Little Indian",
|
||||
"One Magic Christmas",
|
||||
"One of Our Dinosaurs Is Missing",
|
||||
"Operation Dumbo Drop",
|
||||
"Oz the Great and Powerful",
|
||||
"Penguins",
|
||||
"Perri",
|
||||
"Pete's Dragon",
|
||||
"Pete's Dragon",
|
||||
"Peter Pan",
|
||||
"Piglet's Big Movie",
|
||||
"Pinocchio",
|
||||
"Pirates of the Caribbean: At World's End",
|
||||
"Pirates of the Caribbean: Dead Man's Chest",
|
||||
"Pirates of the Caribbean: Dead Men Tell No Tales",
|
||||
"Pirates of the Caribbean: On Stranger Tides",
|
||||
"Pirates of the Caribbean: The Curse of the Black Pearl",
|
||||
"Planes",
|
||||
"Planes: Fire & Rescue",
|
||||
"Pocahontas",
|
||||
"Pollyanna",
|
||||
"Pooh's Heffalump Movie",
|
||||
"Popeye",
|
||||
"Prince of Persia: The Sands of Time",
|
||||
"Prom",
|
||||
"Queen of Katwe",
|
||||
"Race to Witch Mountain",
|
||||
"Ralph Breaks the Internet",
|
||||
"Rascal",
|
||||
"Ratatouille",
|
||||
"Recess: School's Out",
|
||||
"Remember the Titans",
|
||||
"Return from Witch Mountain",
|
||||
"Return to Never Land",
|
||||
"Return to Oz",
|
||||
"Return to Snowy River",
|
||||
"Ride a Wild Pony",
|
||||
"Roadside Romeo",
|
||||
"Rob Roy, the Highland Rogue",
|
||||
"Robin Hood",
|
||||
"RocketMan",
|
||||
"Roving Mars",
|
||||
"Run, Cougar, Run",
|
||||
"Sacred Planet",
|
||||
"Saludos Amigos",
|
||||
"Savage Sam",
|
||||
"Saving Mr. Banks",
|
||||
"Scandalous John",
|
||||
"Secretariat",
|
||||
"Secrets of Life",
|
||||
"Shipwrecked",
|
||||
"Sky High",
|
||||
"Sleeping Beauty",
|
||||
"Smith!",
|
||||
"Snow Dogs",
|
||||
"Snow White and the Seven Dwarfs",
|
||||
"Snowball Express",
|
||||
"So Dear to My Heart",
|
||||
"Something Wicked This Way Comes",
|
||||
"Son of Flubber",
|
||||
"Song of the South",
|
||||
"Squanto: A Warrior's Tale",
|
||||
"Summer Magic",
|
||||
"Superdad",
|
||||
"Swiss Family Robinson",
|
||||
"Tall Tale",
|
||||
"Tangled",
|
||||
"Tarzan",
|
||||
"Teacher's Pet",
|
||||
"Ten Who Dared",
|
||||
"Tex",
|
||||
"That Darn Cat",
|
||||
"That Darn Cat!",
|
||||
"The Absent-Minded Professor",
|
||||
"The Adventures of Bullwhip Griffin",
|
||||
"The Adventures of Huck Finn",
|
||||
"The Adventures of Ichabod and Mr. Toad",
|
||||
"The African Lion",
|
||||
"The Apple Dumpling Gang",
|
||||
"The Apple Dumpling Gang Rides Again",
|
||||
"The Aristocats",
|
||||
"The BFG",
|
||||
"The Barefoot Executive",
|
||||
"The Bears and I",
|
||||
"The Best of Walt Disney's True-Life Adventures",
|
||||
"The Big Green",
|
||||
"The Biscuit Eater",
|
||||
"The Black Cauldron",
|
||||
"The Black Hole",
|
||||
"The Boatniks",
|
||||
"The Book of Masters",
|
||||
"The Boys: The Sherman Brothers' Story",
|
||||
"The Castaway Cowboy",
|
||||
"The Cat from Outer Space",
|
||||
"The Chronicles of Narnia: Prince Caspian",
|
||||
"The Chronicles of Narnia: The Lion, the Witch and the Wardrobe",
|
||||
"The Computer Wore Tennis Shoes",
|
||||
"The Country Bears",
|
||||
"The Crimson Wing: Mystery of the Flamingos",
|
||||
"The Devil and Max Devlin",
|
||||
"The Emperor's New Groove",
|
||||
"The Fighting Prince of Donegal",
|
||||
"The Finest Hours",
|
||||
"The Fox and the Hound",
|
||||
"The Game Plan",
|
||||
"The Gnome-Mobile",
|
||||
"The Good Dinosaur",
|
||||
"The Great Locomotive Chase",
|
||||
"The Great Mouse Detective",
|
||||
"The Greatest Game Ever Played",
|
||||
"The Happiest Millionaire",
|
||||
"The Haunted Mansion",
|
||||
"The Horse in the Gray Flannel Suit",
|
||||
"The Hunchback of Notre Dame",
|
||||
"The Incredible Journey",
|
||||
"The Incredibles",
|
||||
"The Island at the Top of the World",
|
||||
"The Journey of Natty Gann",
|
||||
"The Jungle Book",
|
||||
"The Jungle Book",
|
||||
"The Jungle Book",
|
||||
"The Jungle Book 2",
|
||||
"The Last Flight of Noah's Ark",
|
||||
"The Legend of Lobo",
|
||||
"The Light in the Forest",
|
||||
"The Lion King",
|
||||
"The Lion King",
|
||||
"The Little Mermaid",
|
||||
"The Littlest Horse Thieves",
|
||||
"The Littlest Outlaw",
|
||||
"The Living Desert",
|
||||
"The Lizzie McGuire Movie",
|
||||
"The London Connection",
|
||||
"The Lone Ranger",
|
||||
"The Love Bug",
|
||||
"The Many Adventures of Winnie the Pooh",
|
||||
"The Mighty Ducks",
|
||||
"The Million Dollar Duck",
|
||||
"The Misadventures of Merlin Jones",
|
||||
"The Monkey's Uncle",
|
||||
"The Moon-Spinners",
|
||||
"The Muppet Christmas Carol",
|
||||
"The Muppets",
|
||||
"The Nightmare Before Christmas 3D TNBC",
|
||||
"The North Avenue Irregulars",
|
||||
"The Nutcracker and the Four Realms",
|
||||
"The Odd Life of Timothy Green",
|
||||
"The One and Only, Genuine, Original Family Band",
|
||||
"The Pacifier",
|
||||
"The Parent Trap",
|
||||
"The Parent Trap",
|
||||
"The Pixar Story",
|
||||
"The Princess Diaries",
|
||||
"The Princess Diaries 2: Royal Engagement",
|
||||
"The Princess and the Frog",
|
||||
"The Reluctant Dragon",
|
||||
"The Rescuers",
|
||||
"The Rescuers Down Under",
|
||||
"The Rocketeer TR",
|
||||
"The Rookie",
|
||||
"The Santa Clause 2",
|
||||
"The Santa Clause 3: The Escape Clause",
|
||||
"The Santa Clause TSC",
|
||||
"The Shaggy D.A.",
|
||||
"The Shaggy Dog",
|
||||
"The Shaggy Dog",
|
||||
"The Sign of Zorro",
|
||||
"The Sorcerer's Apprentice",
|
||||
"The Story of Robin Hood and His Merrie Men",
|
||||
"The Straight Story",
|
||||
"The Strongest Man in the World",
|
||||
"The Sword and the Rose",
|
||||
"The Sword in the Stone",
|
||||
"The Three Caballeros",
|
||||
"The Three Lives of Thomasina",
|
||||
"The Three Musketeers",
|
||||
"The Tigger Movie",
|
||||
"The Ugly Dachshund",
|
||||
"The Vanishing Prairie",
|
||||
"The Watcher in the Woods",
|
||||
"The Wild",
|
||||
"The Wild Country",
|
||||
"The World's Greatest Athlete",
|
||||
"The Young Black Stallion",
|
||||
"Third Man on the Mountain",
|
||||
"Those Calloways",
|
||||
"Toby Tyler",
|
||||
"Tom and Huck",
|
||||
"Tomorrowland",
|
||||
"Tonka",
|
||||
"Toy Story",
|
||||
"Toy Story 2",
|
||||
"Toy Story 3",
|
||||
"Toy Story 4",
|
||||
"Trail of the Panda",
|
||||
"Treasure Island",
|
||||
"Treasure Planet",
|
||||
"Treasure of Matecumbe",
|
||||
"Trenchcoat",
|
||||
"Tron",
|
||||
"Tron: Legacy",
|
||||
"Tuck Everlasting",
|
||||
"Underdog",
|
||||
"Unidentified Flying Oddball",
|
||||
"Up",
|
||||
"Valiant",
|
||||
"Victory Through Air Power",
|
||||
"WALL-E",
|
||||
"Waking Sleeping Beauty",
|
||||
"Walt & El Grupo",
|
||||
"Westward Ho the Wagons!",
|
||||
"White Fang",
|
||||
"White Fang 2: Myth of the White Wolf",
|
||||
"White Wilderness",
|
||||
"Wild Hearts Can't Be Broken",
|
||||
"Wings of Life",
|
||||
"Winnie the Pooh",
|
||||
"Wreck-It Ralph",
|
||||
"Zokkomon",
|
||||
"Zootopia",
|
||||
"Zorro the Avenger",
|
||||
"Iron Man",
|
||||
"Hulk",
|
||||
"Thor",
|
||||
"Avengers",
|
||||
"Guardians of the Galaxy",
|
||||
"Ant-Man",
|
||||
"Captain America",
|
||||
"Doctor Strange",
|
||||
"Guardians of the Galaxy",
|
||||
"Spider-Man",
|
||||
"Black Panther",
|
||||
"Marvel",
|
||||
"Spider Man",
|
||||
"SpiderMan",
|
||||
"Loki",
|
||||
"Winter Soldier",
|
||||
"Wanda",
|
||||
"Small Fry",
|
||||
"Rex",
|
||||
"Lamp life",
|
||||
"Toy",
|
||||
"Hawaiian"
|
||||
};
|
||||
}
|
||||
}
|
|
@ -6,8 +6,8 @@ namespace Ombi.Helpers
|
|||
{
|
||||
public interface ICacheService
|
||||
{
|
||||
Task<T> GetOrAdd<T>(string cacheKey, Func<Task<T>> factory, DateTime absoluteExpiration = default(DateTime), CancellationToken cancellationToken = default(CancellationToken));
|
||||
T GetOrAdd<T>(string cacheKey, Func<T> factory, DateTime absoluteExpiration);
|
||||
Task<T> GetOrAddAsync<T>(string cacheKey, Func<Task<T>> factory, DateTimeOffset absoluteExpiration = default);
|
||||
T GetOrAdd<T>(string cacheKey, Func<T> factory, DateTimeOffset absoluteExpiration);
|
||||
void Remove(string key);
|
||||
}
|
||||
}
|
61
src/Ombi.Helpers/MediaCacheService.cs
Normal file
61
src/Ombi.Helpers/MediaCacheService.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using LazyCache;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public interface IMediaCacheService
|
||||
{
|
||||
Task<T> GetOrAddAsync<T>(string cacheKey, System.Func<Task<T>> factory, DateTimeOffset absoluteExpiration = default);
|
||||
Task Purge();
|
||||
}
|
||||
public class MediaCacheService : CacheService, IMediaCacheService
|
||||
{
|
||||
private const string CacheKey = "MediaCacheServiceKeys";
|
||||
|
||||
public MediaCacheService(IAppCache memoryCache) : base(memoryCache)
|
||||
{
|
||||
}
|
||||
|
||||
public async override Task<T> GetOrAddAsync<T>(string cacheKey, System.Func<Task<T>> factory, DateTimeOffset absoluteExpiration = default)
|
||||
{
|
||||
if (absoluteExpiration == default)
|
||||
{
|
||||
absoluteExpiration = DateTimeOffset.Now.AddHours(1);
|
||||
}
|
||||
|
||||
if (_memoryCache.TryGetValue<T>($"MediaCacheService_{cacheKey}", out var result))
|
||||
{
|
||||
return (T)result;
|
||||
}
|
||||
|
||||
// Not in the cache, so add this Key into our MediaServiceCache
|
||||
await UpdateLocalCache(cacheKey);
|
||||
|
||||
return await _memoryCache.GetOrAddAsync<T>(cacheKey, () => factory(), absoluteExpiration);
|
||||
}
|
||||
|
||||
private async Task UpdateLocalCache(string cacheKey)
|
||||
{
|
||||
var mediaServiceCache = await _memoryCache.GetAsync<List<string>>(CacheKey);
|
||||
if (mediaServiceCache == null)
|
||||
{
|
||||
mediaServiceCache = new List<string>();
|
||||
}
|
||||
mediaServiceCache.Add(cacheKey);
|
||||
_memoryCache.Remove(CacheKey);
|
||||
_memoryCache.Add(CacheKey, mediaServiceCache);
|
||||
}
|
||||
|
||||
public async Task Purge()
|
||||
{
|
||||
var keys = await _memoryCache.GetAsync<List<string>>(CacheKey);
|
||||
foreach (var key in keys)
|
||||
{
|
||||
base.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="EasyCrypto" Version="3.3.2" />
|
||||
<PackageReference Include="LazyCache.AspNetCore" Version="2.1.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
|
|
|
@ -107,7 +107,7 @@ namespace Ombi.Helpers
|
|||
public static string GetPlexMediaUrl(string machineId, int mediaId)
|
||||
{
|
||||
var url =
|
||||
$"https://app.plex.tv/web/app#!/server/{machineId}/details?key=library%2Fmetadata%2F{mediaId}";
|
||||
$"https://app.plex.tv/web/app#!/server/{machineId}/details?key=%2flibrary%2Fmetadata%2F{mediaId}";
|
||||
return url;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ namespace Ombi.Mapping.Profiles
|
|||
.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.ReleaseDate, o => o.MapFrom(s => DateTime.Parse(s.release_date)))
|
||||
.ForMember(x => x.ReleaseDate, o => o.MapFrom(s => string.IsNullOrEmpty(s.release_date) ? (DateTime?)null : DateTime.Parse(s.release_date)))
|
||||
.ForMember(x => x.Title, o => o.MapFrom(s => s.title));
|
||||
|
||||
CreateMap<SearchMovieViewModel, MovieCollection>().ReverseMap();
|
||||
|
|
|
@ -81,7 +81,9 @@ namespace Ombi.Mapping.Profiles
|
|||
.ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.VoteAverage.ToString()))
|
||||
.ForMember(dest => dest.BackdropPath, opts => opts.MapFrom(src => src.PosterPath))
|
||||
//.ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.Runtime.ToString()))
|
||||
.ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.Title));
|
||||
.ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.Title))
|
||||
.ForMember(dest => dest.SeasonRequests, opts => opts.MapFrom(src => src.SeasonRequests))
|
||||
;
|
||||
//.ForMember(dest => dest.Status, opts => opts.MapFrom(src => TraktEnumHelper.GetDescription(src.Status)))
|
||||
//.ForMember(dest => dest.Trailer,
|
||||
// opts => opts.MapFrom(src => src.Trailer != null ? src.Trailer.ToString().ToHttpsUrl() : string.Empty))
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Ombi.Mapping.Profiles
|
|||
.ForMember(dest => dest.Images, opts => opts.MapFrom(src => src.Images))
|
||||
.ForMember(dest => dest.Cast, opts => opts.MapFrom(src => src.Credits.cast))
|
||||
.ForMember(dest => dest.Crew, opts => opts.MapFrom(src => src.Credits.crew))
|
||||
.ForMember(dest => dest.Banner, opts => opts.MapFrom(src => GetBanner(src.Images)))
|
||||
.ForMember(dest => dest.Banner, opts => opts.MapFrom(src => GetBanner(src.Images, src.backdrop_path)))
|
||||
.ForMember(dest => dest.Genres, opts => opts.MapFrom(src => src.genres))
|
||||
.ForMember(dest => dest.Keywords, opts => opts.MapFrom(src => src.Keywords))
|
||||
.ForMember(dest => dest.Tagline, opts => opts.MapFrom(src => src.tagline))
|
||||
|
@ -78,20 +78,20 @@ namespace Ombi.Mapping.Profiles
|
|||
CreateMap<SearchTvShowViewModel, SearchFullInfoTvShowViewModel>().ReverseMap();
|
||||
}
|
||||
|
||||
private string GetBanner(Api.TheMovieDb.Models.Images images)
|
||||
private string GetBanner(Api.TheMovieDb.Models.Images images, string backdropPath)
|
||||
{
|
||||
var hasBackdrop = images?.Backdrops?.Any();
|
||||
if (hasBackdrop ?? false)
|
||||
{
|
||||
return images.Backdrops?.OrderBy(x => x.VoteCount).ThenBy(x => x.VoteAverage).Select(x => x.FilePath).FirstOrDefault();
|
||||
}
|
||||
else if (images != null)
|
||||
else if (images?.Posters?.Any() ?? false)
|
||||
{
|
||||
return images.Posters?.OrderBy(x => x.VoteCount).ThenBy(x => x.VoteAverage).Select(x => x.FilePath).FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
return backdropPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
{
|
||||
public interface INewsletterTemplate
|
||||
{
|
||||
string LoadTemplate(string subject, string intro, string tableHtml, string logo);
|
||||
string LoadTemplate(string subject, string intro, string tableHtml, string logo, string unsubscribeLink);
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ namespace Ombi.Notifications.Templates
|
|||
if (string.IsNullOrEmpty(_templateLocation))
|
||||
{
|
||||
#if DEBUG
|
||||
_templateLocation = Path.Combine(Directory.GetCurrentDirectory(), "bin", "Debug", "netcoreapp3.0", "Templates", "NewsletterTemplate.html");
|
||||
_templateLocation = Path.Combine(Directory.GetCurrentDirectory(), "bin", "Debug", "net5.0", "Templates", "NewsletterTemplate.html");
|
||||
#else
|
||||
_templateLocation = Path.Combine(Directory.GetCurrentDirectory(), "Templates", "NewsletterTemplate.html");
|
||||
#endif
|
||||
|
@ -29,9 +29,10 @@ namespace Ombi.Notifications.Templates
|
|||
private const string Logo = "{@LOGO}";
|
||||
private const string TableLocation = "{@RECENTLYADDED}";
|
||||
private const string IntroText = "{@INTRO}";
|
||||
private const string Unsubscribe = "{@UNSUBSCRIBE}";
|
||||
|
||||
|
||||
public string LoadTemplate(string subject, string intro, string tableHtml, string logo)
|
||||
public string LoadTemplate(string subject, string intro, string tableHtml, string logo, string unsubscribeLink)
|
||||
{
|
||||
var sb = new StringBuilder(File.ReadAllText(TemplateLocation));
|
||||
sb.Replace(SubjectKey, subject);
|
||||
|
@ -39,6 +40,7 @@ namespace Ombi.Notifications.Templates
|
|||
sb.Replace(IntroText, intro);
|
||||
sb.Replace(DateKey, DateTime.Now.ToString("f"));
|
||||
sb.Replace(Logo, string.IsNullOrEmpty(logo) ? OmbiLogo : logo);
|
||||
sb.Replace(Unsubscribe, string.IsNullOrEmpty(unsubscribeLink) ? string.Empty : unsubscribeLink);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
|
|
@ -451,6 +451,11 @@
|
|||
<div class="footer" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="content-block powered-by" valign="top" align="center" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; color: #999999; font-size: 12px; text-align: center;">
|
||||
<a href="{@UNSUBSCRIBE}" style="font-weight: 400; font-size: 12px; text-align: center; color: #ff761b;">Unsubscribe</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block powered-by" valign="top" align="center" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; color: #999999; font-size: 12px; text-align: center;">
|
||||
Powered by <a href="https://github.com/Ombi-app/Ombi" style="font-weight: 400; font-size: 12px; text-align: center; text-decoration: none; color: #ff761b;">Ombi</a>
|
||||
|
|
342
src/Ombi.Notifications.Tests/NotificationMessageCurlysTests.cs
Normal file
342
src/Ombi.Notifications.Tests/NotificationMessageCurlysTests.cs
Normal file
|
@ -0,0 +1,342 @@
|
|||
using AutoFixture;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Notifications.Models;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ombi.Notifications.Tests
|
||||
{
|
||||
public class NotificationMessageCurlysTests
|
||||
{
|
||||
private NotificationMessageCurlys sut { get; set; }
|
||||
private Fixture F { get; set; }
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
F = new Fixture();
|
||||
F.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
|
||||
.ForEach(b => F.Behaviors.Remove(b));
|
||||
F.Behaviors.Add(new OmitOnRecursionBehavior());
|
||||
sut = new NotificationMessageCurlys();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MovieNotificationTests()
|
||||
{
|
||||
var notificationOptions = new NotificationOptions();
|
||||
var req = F.Build<MovieRequests>()
|
||||
.With(x => x.RequestType, RequestType.Movie)
|
||||
.With(x => x.Available, true)
|
||||
.Create();
|
||||
var customization = new CustomizationSettings
|
||||
{
|
||||
ApplicationUrl = "url",
|
||||
ApplicationName = "name"
|
||||
};
|
||||
var userPrefs = new UserNotificationPreferences();
|
||||
sut.Setup(notificationOptions, req, customization, userPrefs);
|
||||
|
||||
Assert.That(req.Id.ToString(), Is.EqualTo(sut.RequestId));
|
||||
Assert.That(req.TheMovieDbId.ToString(), Is.EqualTo(sut.ProviderId));
|
||||
Assert.That(req.Title.ToString(), Is.EqualTo(sut.Title));
|
||||
Assert.That(req.RequestedUser.UserName, Is.EqualTo(sut.RequestedUser));
|
||||
Assert.That(req.RequestedUser.Alias, Is.EqualTo(sut.Alias));
|
||||
Assert.That(req.RequestedDate.ToString("D"), Is.EqualTo(sut.RequestedDate));
|
||||
Assert.That("Movie", Is.EqualTo(sut.Type));
|
||||
Assert.That(req.Overview, Is.EqualTo(sut.Overview));
|
||||
Assert.That(req.ReleaseDate.Year.ToString(), Is.EqualTo(sut.Year));
|
||||
Assert.That(req.DeniedReason, Is.EqualTo(sut.DenyReason));
|
||||
Assert.That(req.MarkedAsAvailable?.ToString("D"), Is.EqualTo(sut.AvailableDate));
|
||||
Assert.That("https://image.tmdb.org/t/p/w300/" + req.PosterPath, Is.EqualTo(sut.PosterImage));
|
||||
Assert.That(req.DeniedReason, Is.EqualTo(sut.DenyReason));
|
||||
Assert.That(req.RequestedUser.Alias, Is.EqualTo(sut.UserPreference));
|
||||
Assert.That(string.Empty, Is.EqualTo(sut.AdditionalInformation));
|
||||
Assert.That("Available", Is.EqualTo(sut.RequestStatus));
|
||||
Assert.That("url", Is.EqualTo(sut.ApplicationUrl));
|
||||
Assert.That("name", Is.EqualTo(sut.ApplicationName));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MovieIssueNotificationTests()
|
||||
{
|
||||
var notificationOptions = new NotificationOptions
|
||||
{
|
||||
Substitutes = new Dictionary<string, string>
|
||||
{
|
||||
{ "IssueDescription", "Desc" },
|
||||
{ "IssueCategory", "Cat" },
|
||||
{ "IssueStatus", "state" },
|
||||
{ "IssueSubject", "sub" },
|
||||
{ "NewIssueComment", "a" },
|
||||
{ "IssueUser", "User" },
|
||||
{ "IssueUserAlias", "alias" },
|
||||
{ "RequestType", "Movie" },
|
||||
}
|
||||
};
|
||||
var req = F.Build<MovieRequests>()
|
||||
.With(x => x.RequestType, RequestType.Movie)
|
||||
.Create();
|
||||
var customization = new CustomizationSettings();
|
||||
var userPrefs = new UserNotificationPreferences();
|
||||
sut.Setup(notificationOptions, req, customization, userPrefs);
|
||||
|
||||
Assert.That("Desc", Is.EqualTo(sut.IssueDescription));
|
||||
Assert.That("Cat", Is.EqualTo(sut.IssueCategory));
|
||||
Assert.That("state", Is.EqualTo(sut.IssueStatus));
|
||||
Assert.That("a", Is.EqualTo(sut.NewIssueComment));
|
||||
Assert.That("User", Is.EqualTo(sut.UserName));
|
||||
Assert.That("alias", Is.EqualTo(sut.Alias));
|
||||
Assert.That("Movie", Is.EqualTo(sut.Type));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MovieNotificationUserPreferences()
|
||||
{
|
||||
var notificationOptions = new NotificationOptions
|
||||
{
|
||||
AdditionalInformation = "add"
|
||||
};
|
||||
var req = F.Build<MovieRequests>()
|
||||
.With(x => x.RequestType, RequestType.Movie)
|
||||
.Without(x => x.MarkedAsAvailable)
|
||||
.Create();
|
||||
var customization = new CustomizationSettings();
|
||||
var userPrefs = new UserNotificationPreferences
|
||||
{
|
||||
Value = "PrefValue"
|
||||
};
|
||||
sut.Setup(notificationOptions, req, customization, userPrefs);
|
||||
|
||||
Assert.That("PrefValue", Is.EqualTo(sut.UserPreference));
|
||||
Assert.That(string.Empty, Is.EqualTo(sut.AvailableDate));
|
||||
Assert.That("add", Is.EqualTo(sut.AdditionalInformation));
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(RequestStatusData))]
|
||||
public string MovieNotificationTests_RequestStatus(bool available, bool denied, bool approved)
|
||||
{
|
||||
var notificationOptions = new NotificationOptions();
|
||||
var req = F.Build<MovieRequests>()
|
||||
.With(x => x.RequestType, RequestType.Movie)
|
||||
.With(x => x.Available, available)
|
||||
.With(x => x.Denied, denied)
|
||||
.With(x => x.Approved, approved)
|
||||
.Create();
|
||||
var customization = new CustomizationSettings();
|
||||
var userPrefs = new UserNotificationPreferences();
|
||||
sut.Setup(notificationOptions, req, customization, userPrefs);
|
||||
return sut.RequestStatus;
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> RequestStatusData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(true, false, false).Returns("Available");
|
||||
yield return new TestCaseData(false, true, false).Returns("Denied");
|
||||
yield return new TestCaseData(false, false, true).Returns("Processing Request");
|
||||
yield return new TestCaseData(false, false, false).Returns("Pending Approval");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void NewsletterTests()
|
||||
{
|
||||
var customization = new CustomizationSettings
|
||||
{
|
||||
ApplicationUrl = "url",
|
||||
ApplicationName = "name"
|
||||
};
|
||||
sut.SetupNewsletter(customization);
|
||||
|
||||
Assert.That("url", Is.EqualTo(sut.ApplicationUrl));
|
||||
Assert.That("name", Is.EqualTo(sut.ApplicationName));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MusicNotificationTests()
|
||||
{
|
||||
var notificationOptions = new NotificationOptions();
|
||||
var req = F.Build<AlbumRequest>()
|
||||
.With(x => x.RequestType, RequestType.Album)
|
||||
.With(x => x.Available, true)
|
||||
.Create();
|
||||
var customization = new CustomizationSettings
|
||||
{
|
||||
ApplicationUrl = "url",
|
||||
ApplicationName = "name"
|
||||
};
|
||||
var userPrefs = new UserNotificationPreferences();
|
||||
sut.Setup(notificationOptions, req, customization, userPrefs);
|
||||
|
||||
Assert.That(req.Id.ToString(), Is.EqualTo(sut.RequestId));
|
||||
Assert.That(req.ForeignArtistId.ToString(), Is.EqualTo(sut.ProviderId));
|
||||
Assert.That(req.Title.ToString(), Is.EqualTo(sut.Title));
|
||||
Assert.That(req.RequestedUser.UserName, Is.EqualTo(sut.RequestedUser));
|
||||
Assert.That(req.RequestedUser.Alias, Is.EqualTo(sut.Alias));
|
||||
Assert.That(req.RequestedDate.ToString("D"), Is.EqualTo(sut.RequestedDate));
|
||||
Assert.That("Album", Is.EqualTo(sut.Type));
|
||||
Assert.That(req.ReleaseDate.Year.ToString(), Is.EqualTo(sut.Year));
|
||||
Assert.That(req.DeniedReason, Is.EqualTo(sut.DenyReason));
|
||||
Assert.That(req.MarkedAsAvailable?.ToString("D"), Is.EqualTo(sut.AvailableDate));
|
||||
Assert.That(req.Cover, Is.EqualTo(sut.PosterImage));
|
||||
Assert.That(req.DeniedReason, Is.EqualTo(sut.DenyReason));
|
||||
Assert.That(req.RequestedUser.Alias, Is.EqualTo(sut.UserPreference));
|
||||
Assert.That(string.Empty, Is.EqualTo(sut.AdditionalInformation));
|
||||
Assert.That("Available", Is.EqualTo(sut.RequestStatus));
|
||||
Assert.That("url", Is.EqualTo(sut.ApplicationUrl));
|
||||
Assert.That("name", Is.EqualTo(sut.ApplicationName));
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(RequestStatusData))]
|
||||
public string MusicNotificationTests_RequestStatus(bool available, bool denied, bool approved)
|
||||
{
|
||||
var notificationOptions = new NotificationOptions();
|
||||
var req = F.Build<AlbumRequest>()
|
||||
.With(x => x.RequestType, RequestType.Album)
|
||||
.With(x => x.Available, available)
|
||||
.With(x => x.Denied, denied)
|
||||
.With(x => x.Approved, approved)
|
||||
.Create();
|
||||
var customization = new CustomizationSettings();
|
||||
var userPrefs = new UserNotificationPreferences();
|
||||
sut.Setup(notificationOptions, req, customization, userPrefs);
|
||||
return sut.RequestStatus;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TvNotificationTests()
|
||||
{
|
||||
var notificationOptions = new NotificationOptions();
|
||||
var req = F.Build<ChildRequests>()
|
||||
.With(x => x.RequestType, RequestType.TvShow)
|
||||
.With(x => x.Available, true)
|
||||
.Create();
|
||||
var customization = new CustomizationSettings
|
||||
{
|
||||
ApplicationUrl = "url",
|
||||
ApplicationName = "name"
|
||||
};
|
||||
var userPrefs = new UserNotificationPreferences();
|
||||
sut.Setup(notificationOptions, req, customization, userPrefs);
|
||||
|
||||
Assert.That(req.Id.ToString(), Is.EqualTo(sut.RequestId));
|
||||
Assert.That(req.ParentRequest.ExternalProviderId.ToString(), Is.EqualTo(sut.ProviderId));
|
||||
Assert.That(req.ParentRequest.Title.ToString(), Is.EqualTo(sut.Title));
|
||||
Assert.That(req.RequestedUser.UserName, Is.EqualTo(sut.RequestedUser));
|
||||
Assert.That(req.RequestedUser.Alias, Is.EqualTo(sut.Alias));
|
||||
Assert.That(req.RequestedDate.ToString("D"), Is.EqualTo(sut.RequestedDate));
|
||||
Assert.That("TV Show", Is.EqualTo(sut.Type));
|
||||
Assert.That(req.ParentRequest.Overview, Is.EqualTo(sut.Overview));
|
||||
Assert.That(req.ParentRequest.ReleaseDate.Year.ToString(), Is.EqualTo(sut.Year));
|
||||
Assert.That(req.DeniedReason, Is.EqualTo(sut.DenyReason));
|
||||
Assert.That(req.MarkedAsAvailable?.ToString("D"), Is.EqualTo(sut.AvailableDate));
|
||||
Assert.That("https://image.tmdb.org/t/p/w300/" + req.ParentRequest.PosterPath, Is.EqualTo(sut.PosterImage));
|
||||
Assert.That(req.DeniedReason, Is.EqualTo(sut.DenyReason));
|
||||
Assert.That(req.RequestedUser.Alias, Is.EqualTo(sut.UserPreference));
|
||||
Assert.That(null, Is.EqualTo(sut.AdditionalInformation));
|
||||
Assert.That("Available", Is.EqualTo(sut.RequestStatus));
|
||||
Assert.That("url", Is.EqualTo(sut.ApplicationUrl));
|
||||
Assert.That("name", Is.EqualTo(sut.ApplicationName));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TvNotification_EpisodeList()
|
||||
{
|
||||
var episodeRequests = new List<EpisodeRequests>
|
||||
{
|
||||
new EpisodeRequests
|
||||
{
|
||||
EpisodeNumber = 1,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
EpisodeNumber = 2,
|
||||
},
|
||||
new EpisodeRequests
|
||||
{
|
||||
EpisodeNumber = 3,
|
||||
}
|
||||
};
|
||||
var seasonRequests = new List<SeasonRequests>
|
||||
{
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = episodeRequests,
|
||||
SeasonNumber = 1
|
||||
},
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = episodeRequests,
|
||||
SeasonNumber = 2
|
||||
},
|
||||
new SeasonRequests
|
||||
{
|
||||
Episodes = episodeRequests,
|
||||
SeasonNumber = 3
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var notificationOptions = new NotificationOptions();
|
||||
var req = F.Build<ChildRequests>()
|
||||
.With(x => x.RequestType, RequestType.TvShow)
|
||||
.With(x => x.Available, true)
|
||||
.With(x => x.SeasonRequests, seasonRequests)
|
||||
.Create();
|
||||
var customization = new CustomizationSettings
|
||||
{
|
||||
ApplicationUrl = "url",
|
||||
ApplicationName = "name"
|
||||
};
|
||||
var userPrefs = new UserNotificationPreferences();
|
||||
sut.Setup(notificationOptions, req, customization, userPrefs);
|
||||
|
||||
Assert.That(sut.EpisodesList, Is.EqualTo("1,1,1,2,2,2,3,3,3"));
|
||||
Assert.That(sut.SeasonsList, Is.EqualTo("1,2,3"));
|
||||
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(RequestStatusData))]
|
||||
public string TvShowNotificationTests_RequestStatus(bool available, bool denied, bool approved)
|
||||
{
|
||||
var notificationOptions = new NotificationOptions();
|
||||
var req = F.Build<ChildRequests>()
|
||||
.With(x => x.RequestType, RequestType.TvShow)
|
||||
.With(x => x.Available, available)
|
||||
.With(x => x.Denied, denied)
|
||||
.With(x => x.Approved, approved)
|
||||
.Create();
|
||||
var customization = new CustomizationSettings();
|
||||
var userPrefs = new UserNotificationPreferences();
|
||||
sut.Setup(notificationOptions, req, customization, userPrefs);
|
||||
return sut.RequestStatus;
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void EmailSetupTests()
|
||||
{
|
||||
var user = F.Create<OmbiUser>();
|
||||
var customization = new CustomizationSettings
|
||||
{
|
||||
ApplicationUrl = "url",
|
||||
ApplicationName = "name"
|
||||
};
|
||||
sut.Setup(user, customization);
|
||||
|
||||
Assert.That(user.UserName, Is.EqualTo(sut.RequestedUser));
|
||||
Assert.That(user.UserName, Is.EqualTo(sut.UserName));
|
||||
Assert.That(user.UserAlias, Is.EqualTo(sut.Alias));
|
||||
Assert.That(sut.ApplicationUrl, Is.EqualTo("url"));
|
||||
Assert.That(sut.ApplicationName, Is.EqualTo("name"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoFixture" Version="4.11.0" />
|
||||
<PackageReference Include="Nunit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
|
|
|
@ -106,21 +106,23 @@ namespace Ombi.Notifications.Agents
|
|||
};
|
||||
|
||||
var fields = new List<DiscordField>();
|
||||
|
||||
if (model.Data.TryGetValue("Alias", out var alias))
|
||||
if (!settings.HideUser)
|
||||
{
|
||||
if (alias.HasValue())
|
||||
if (model.Data.TryGetValue("Alias", out var alias))
|
||||
{
|
||||
fields.Add(new DiscordField { name = "Requested By", value = alias, inline = true });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (model.Data.TryGetValue("RequestedUser", out var requestedUser))
|
||||
{
|
||||
if (requestedUser.HasValue())
|
||||
if (alias.HasValue())
|
||||
{
|
||||
fields.Add(new DiscordField { name = "Requested By", value = requestedUser, inline = true });
|
||||
fields.Add(new DiscordField { name = "Requested By", value = alias, inline = true });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (model.Data.TryGetValue("RequestedUser", out var requestedUser))
|
||||
{
|
||||
if (requestedUser.HasValue())
|
||||
{
|
||||
fields.Add(new DiscordField { name = "Requested By", value = requestedUser, inline = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -240,9 +240,9 @@ namespace Ombi.Notifications.Agents
|
|||
|
||||
private async Task SendToSubscribers(EmailNotificationSettings settings, NotificationMessage message)
|
||||
{
|
||||
if (await SubsribedUsers.AnyAsync())
|
||||
if (await Subscribed.AnyAsync())
|
||||
{
|
||||
foreach (var user in SubsribedUsers)
|
||||
foreach (var user in Subscribed)
|
||||
{
|
||||
if (user.Email.IsNullOrEmpty())
|
||||
{
|
||||
|
|
|
@ -304,9 +304,9 @@ namespace Ombi.Notifications.Agents
|
|||
|
||||
private async Task AddSubscribedUsers(List<string> playerIds)
|
||||
{
|
||||
if (await SubsribedUsers.AnyAsync())
|
||||
if (await Subscribed.AnyAsync())
|
||||
{
|
||||
foreach (var user in SubsribedUsers)
|
||||
foreach (var user in Subscribed)
|
||||
{
|
||||
var notificationId = user.NotificationUserIds;
|
||||
if (notificationId.Any())
|
||||
|
|
|
@ -57,6 +57,7 @@ namespace Ombi.Notifications.Agents
|
|||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = parsed.Message,
|
||||
Subject = "New Request",
|
||||
Data = GetNotificationData(parsed, NotificationType.NewRequest)
|
||||
};
|
||||
|
||||
|
@ -76,6 +77,7 @@ namespace Ombi.Notifications.Agents
|
|||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = parsed.Message,
|
||||
Subject = "New Issue",
|
||||
Data = GetNotificationData(parsed, NotificationType.Issue)
|
||||
};
|
||||
|
||||
|
@ -127,6 +129,7 @@ namespace Ombi.Notifications.Agents
|
|||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = parsed.Message,
|
||||
Subject = "Issue Resolved",
|
||||
Data = GetNotificationData(parsed, NotificationType.IssueResolved)
|
||||
};
|
||||
|
||||
|
@ -149,6 +152,7 @@ namespace Ombi.Notifications.Agents
|
|||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = parsed.Message,
|
||||
Subject = "Request Error",
|
||||
Data = GetNotificationData(parsed, NotificationType.ItemAddedToFaultQueue)
|
||||
};
|
||||
|
||||
|
@ -168,6 +172,7 @@ namespace Ombi.Notifications.Agents
|
|||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = parsed.Message,
|
||||
Subject = "Request Declined",
|
||||
Data = GetNotificationData(parsed, NotificationType.RequestDeclined)
|
||||
};
|
||||
|
||||
|
@ -188,6 +193,7 @@ namespace Ombi.Notifications.Agents
|
|||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = parsed.Message,
|
||||
Subject = "Request Approved",
|
||||
Data = GetNotificationData(parsed, NotificationType.RequestApproved)
|
||||
};
|
||||
|
||||
|
@ -212,6 +218,7 @@ namespace Ombi.Notifications.Agents
|
|||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = parsed.Message,
|
||||
Subject = "Request Available",
|
||||
Data = data
|
||||
};
|
||||
// Send to user
|
||||
|
@ -259,6 +266,7 @@ namespace Ombi.Notifications.Agents
|
|||
var notification = new NotificationMessage
|
||||
{
|
||||
Message = message,
|
||||
Subject = "Test Notification"
|
||||
};
|
||||
// Send to user
|
||||
var user = await _userManager.Users.Include(x => x.NotificationUserIds).FirstOrDefaultAsync(x => x.Id.Equals(model.UserId));
|
||||
|
@ -338,9 +346,9 @@ namespace Ombi.Notifications.Agents
|
|||
|
||||
private async Task AddSubscribedUsers(List<string> playerIds)
|
||||
{
|
||||
if (await SubsribedUsers.AnyAsync())
|
||||
if (await Subscribed.AnyAsync())
|
||||
{
|
||||
foreach (var user in SubsribedUsers)
|
||||
foreach (var user in Subscribed)
|
||||
{
|
||||
var notificationIds = await _notifications.GetAll().Where(x => x.UserId == user.Id).ToListAsync();
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace Ombi.Notifications
|
|||
protected ChildRequests TvRequest { get; set; }
|
||||
protected AlbumRequest AlbumRequest { get; set; }
|
||||
protected MovieRequests MovieRequest { get; set; }
|
||||
protected IQueryable<OmbiUser> SubsribedUsers { get; private set; }
|
||||
protected IQueryable<OmbiUser> Subscribed { get; private set; }
|
||||
|
||||
public abstract string NotificationName { get; }
|
||||
|
||||
|
@ -75,7 +75,7 @@ namespace Ombi.Notifications
|
|||
if (model.RequestId > 0)
|
||||
{
|
||||
await LoadRequest(model.RequestId, model.RequestType);
|
||||
SubsribedUsers = GetSubscriptions(model.RequestId, model.RequestType);
|
||||
Subscribed = GetSubscriptions(model.RequestId, model.RequestType);
|
||||
}
|
||||
|
||||
Customization = await CustomizationSettings.GetSettingsAsync();
|
||||
|
@ -209,7 +209,6 @@ namespace Ombi.Notifications
|
|||
if (model.RequestType == RequestType.Movie)
|
||||
{
|
||||
_log.LogDebug("Notification options: {@model}, Req: {@MovieRequest}, Settings: {@Customization}", model, MovieRequest, Customization);
|
||||
|
||||
curlys.Setup(model, MovieRequest, Customization, preference);
|
||||
}
|
||||
else if (model.RequestType == RequestType.TvShow)
|
||||
|
|
|
@ -14,218 +14,156 @@ namespace Ombi.Notifications
|
|||
{
|
||||
public class NotificationMessageCurlys
|
||||
{
|
||||
public void Setup(NotificationOptions opts, MovieRequests req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||
{
|
||||
LoadIssues(opts);
|
||||
|
||||
RequestId = req?.Id.ToString();
|
||||
ProviderId = req?.TheMovieDbId.ToString() ?? string.Empty;
|
||||
string title;
|
||||
if (req == null)
|
||||
{
|
||||
opts.Substitutes.TryGetValue("Title", out title);
|
||||
}
|
||||
else
|
||||
{
|
||||
title = req?.Title;
|
||||
}
|
||||
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
|
||||
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
|
||||
RequestedUser = req?.RequestedUser?.UserName;
|
||||
if (UserName.IsNullOrEmpty())
|
||||
{
|
||||
// Can be set if it's an issue
|
||||
UserName = req?.RequestedUser?.UserName;
|
||||
}
|
||||
|
||||
if (Alias.IsNullOrEmpty())
|
||||
{
|
||||
// Can be set if it's an issue
|
||||
Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName;
|
||||
}
|
||||
|
||||
if (pref != null)
|
||||
{
|
||||
UserPreference = pref.Value.HasValue() ? pref.Value : Alias;
|
||||
}
|
||||
Title = title;
|
||||
RequestedDate = req?.RequestedDate.ToString("D");
|
||||
if (Type.IsNullOrEmpty())
|
||||
{
|
||||
Type = req?.RequestType.Humanize();
|
||||
}
|
||||
Overview = req?.Overview;
|
||||
Year = req?.ReleaseDate.Year.ToString();
|
||||
DenyReason = req?.DeniedReason;
|
||||
AvailableDate = req?.MarkedAsAvailable?.ToString("D") ?? string.Empty;
|
||||
|
||||
PosterImage = string.Format((req?.PosterPath ?? string.Empty).StartsWith("/", StringComparison.InvariantCultureIgnoreCase)
|
||||
? "https://image.tmdb.org/t/p/w300{0}" : "https://image.tmdb.org/t/p/w300/{0}", req?.PosterPath);
|
||||
|
||||
|
||||
AdditionalInformation = opts?.AdditionalInformation ?? string.Empty;
|
||||
|
||||
CalculateRequestStatus(req);
|
||||
}
|
||||
|
||||
public void Setup(NotificationOptions opts, AlbumRequest req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||
{
|
||||
LoadIssues(opts);
|
||||
|
||||
RequestId = req?.Id.ToString();
|
||||
ProviderId = req?.ForeignArtistId ?? string.Empty;
|
||||
|
||||
string title;
|
||||
if (req == null)
|
||||
{
|
||||
opts.Substitutes.TryGetValue("Title", out title);
|
||||
}
|
||||
else
|
||||
{
|
||||
title = req?.Title;
|
||||
}
|
||||
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
|
||||
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
|
||||
RequestedUser = req?.RequestedUser?.UserName;
|
||||
if (UserName.IsNullOrEmpty())
|
||||
{
|
||||
// Can be set if it's an issue
|
||||
UserName = req?.RequestedUser?.UserName;
|
||||
}
|
||||
|
||||
AvailableDate = req?.MarkedAsAvailable?.ToString("D") ?? string.Empty;
|
||||
DenyReason = req?.DeniedReason;
|
||||
if (Alias.IsNullOrEmpty())
|
||||
{
|
||||
Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName;
|
||||
}
|
||||
if (pref != null)
|
||||
{
|
||||
UserPreference = pref.Value.HasValue() ? pref.Value : Alias;
|
||||
}
|
||||
Title = title;
|
||||
RequestedDate = req?.RequestedDate.ToString("D");
|
||||
if (Type.IsNullOrEmpty())
|
||||
{
|
||||
Type = req?.RequestType.Humanize();
|
||||
}
|
||||
Year = req?.ReleaseDate.Year.ToString();
|
||||
PosterImage = (req?.Cover.HasValue() ?? false) ? req.Cover : req?.Disk ?? string.Empty;
|
||||
|
||||
AdditionalInformation = opts?.AdditionalInformation ?? string.Empty;
|
||||
CalculateRequestStatus(req);
|
||||
}
|
||||
|
||||
public void SetupNewsletter(CustomizationSettings s)
|
||||
{
|
||||
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
|
||||
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
|
||||
}
|
||||
|
||||
public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||
{
|
||||
LoadIssues(opts);
|
||||
RequestId = req?.Id.ToString();
|
||||
ProviderId = req?.ParentRequest?.ExternalProviderId.ToString() ?? string.Empty;
|
||||
string title;
|
||||
if (req == null)
|
||||
{
|
||||
opts.Substitutes.TryGetValue("Title", out title);
|
||||
}
|
||||
else
|
||||
{
|
||||
title = req?.ParentRequest.Title;
|
||||
}
|
||||
DenyReason = req?.DeniedReason;
|
||||
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
|
||||
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
|
||||
RequestedUser = req?.RequestedUser?.UserName;
|
||||
if (UserName.IsNullOrEmpty())
|
||||
{
|
||||
// Can be set if it's an issue
|
||||
UserName = req?.RequestedUser?.UserName;
|
||||
}
|
||||
AvailableDate = req?.MarkedAsAvailable?.ToString("D") ?? string.Empty;
|
||||
if (Alias.IsNullOrEmpty())
|
||||
{
|
||||
Alias = (req?.RequestedUser?.Alias.HasValue() ?? false) ? req?.RequestedUser?.Alias : req?.RequestedUser?.UserName;
|
||||
}
|
||||
if (pref != null)
|
||||
{
|
||||
UserPreference = pref.Value.HasValue() ? pref.Value : Alias;
|
||||
}
|
||||
Title = title;
|
||||
RequestedDate = req?.RequestedDate.ToString("D");
|
||||
if (Type.IsNullOrEmpty())
|
||||
{
|
||||
Type = req?.RequestType.Humanize();
|
||||
}
|
||||
|
||||
Overview = req?.ParentRequest.Overview;
|
||||
Year = req?.ParentRequest.ReleaseDate.Year.ToString();
|
||||
|
||||
PosterImage = string.Format((req?.ParentRequest.PosterPath ?? string.Empty).StartsWith("/", StringComparison.InvariantCultureIgnoreCase)
|
||||
? "https://image.tmdb.org/t/p/w300{0}" : "https://image.tmdb.org/t/p/w300/{0}", req?.ParentRequest.PosterPath);
|
||||
|
||||
AdditionalInformation = opts.AdditionalInformation;
|
||||
// DO Episode and Season Lists
|
||||
|
||||
var episodes = req?.SeasonRequests?.SelectMany(x => x.Episodes) ?? new List<EpisodeRequests>();
|
||||
var seasons = req?.SeasonRequests?.OrderBy(x => x.SeasonNumber).ToList() ?? new List<SeasonRequests>();
|
||||
var orderedEpisodes = episodes.OrderBy(x => x.EpisodeNumber).ToList();
|
||||
var epSb = new StringBuilder();
|
||||
var seasonSb = new StringBuilder();
|
||||
for (var i = 0; i < orderedEpisodes.Count; i++)
|
||||
{
|
||||
var ep = orderedEpisodes[i];
|
||||
if (i < orderedEpisodes.Count - 1)
|
||||
{
|
||||
epSb.Append($"{ep.EpisodeNumber},");
|
||||
}
|
||||
else
|
||||
{
|
||||
epSb.Append($"{ep.EpisodeNumber}");
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < seasons.Count; i++)
|
||||
{
|
||||
var ep = seasons[i];
|
||||
if (i < seasons.Count - 1)
|
||||
{
|
||||
seasonSb.Append($"{ep.SeasonNumber},");
|
||||
}
|
||||
else
|
||||
{
|
||||
seasonSb.Append($"{ep.SeasonNumber}");
|
||||
}
|
||||
}
|
||||
|
||||
EpisodesList = epSb.ToString();
|
||||
SeasonsList = seasonSb.ToString();
|
||||
CalculateRequestStatus(req);
|
||||
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s.ApplicationName;
|
||||
ApplicationUrl = s?.ApplicationUrl.HasValue() ?? false ? s.ApplicationUrl : string.Empty;
|
||||
}
|
||||
|
||||
public void Setup(OmbiUser user, CustomizationSettings s)
|
||||
{
|
||||
ApplicationUrl = (s?.ApplicationUrl.HasValue() ?? false) ? s.ApplicationUrl : string.Empty;
|
||||
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s?.ApplicationName;
|
||||
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s.ApplicationName;
|
||||
ApplicationUrl = s?.ApplicationUrl.HasValue() ?? false ? s.ApplicationUrl : string.Empty;
|
||||
RequestedUser = user.UserName;
|
||||
Alias = user.UserAlias;
|
||||
UserName = user.UserName;
|
||||
}
|
||||
|
||||
public void Setup(NotificationOptions opts, MovieRequests req, CustomizationSettings s,
|
||||
UserNotificationPreferences pref)
|
||||
{
|
||||
LoadIssues(opts);
|
||||
LoadCommon(req, s, pref);
|
||||
LoadTitle(opts, req);
|
||||
ProviderId = req?.TheMovieDbId.ToString() ?? string.Empty;
|
||||
Year = req?.ReleaseDate.Year.ToString();
|
||||
Overview = req?.Overview;
|
||||
AdditionalInformation = opts?.AdditionalInformation ?? string.Empty;
|
||||
PosterImage = $"https://image.tmdb.org/t/p/w300/{req?.PosterPath?.TrimStart('/') ?? string.Empty}";
|
||||
CalculateRequestStatus(req);
|
||||
}
|
||||
|
||||
public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s,
|
||||
UserNotificationPreferences pref)
|
||||
{
|
||||
LoadIssues(opts);
|
||||
LoadCommon(req, s, pref);
|
||||
LoadTitle(opts, req);
|
||||
ProviderId = req?.ParentRequest?.ExternalProviderId.ToString() ?? string.Empty;
|
||||
Year = req?.ParentRequest?.ReleaseDate.Year.ToString();
|
||||
Overview = req?.ParentRequest?.Overview;
|
||||
AdditionalInformation = opts.AdditionalInformation;
|
||||
PosterImage =
|
||||
$"https://image.tmdb.org/t/p/w300/{req?.ParentRequest?.PosterPath?.TrimStart('/') ?? string.Empty}";
|
||||
|
||||
// Generate episode list.
|
||||
StringBuilder epSb = new StringBuilder();
|
||||
IEnumerable<EpisodeRequests> episodes = req?.SeasonRequests?
|
||||
.SelectMany(x => x.Episodes) ?? new List<EpisodeRequests>();
|
||||
episodes
|
||||
.OrderBy(x => x.EpisodeNumber)
|
||||
.ToList()
|
||||
.ForEach(ep => epSb.Append($"{ep.EpisodeNumber},"));
|
||||
if (epSb.Length > 0) epSb.Remove(epSb.Length - 1, 1);
|
||||
EpisodesList = epSb.ToString();
|
||||
|
||||
// Generate season list.
|
||||
StringBuilder seasonSb = new StringBuilder();
|
||||
List<SeasonRequests> seasons = req?.SeasonRequests ?? new List<SeasonRequests>();
|
||||
seasons
|
||||
.OrderBy(x => x.SeasonNumber)
|
||||
.ToList()
|
||||
.ForEach(ep => seasonSb.Append($"{ep.SeasonNumber},"));
|
||||
if (seasonSb.Length > 0) seasonSb.Remove(seasonSb.Length - 1, 1);
|
||||
SeasonsList = seasonSb.ToString();
|
||||
CalculateRequestStatus(req);
|
||||
}
|
||||
|
||||
public void Setup(NotificationOptions opts, AlbumRequest req, CustomizationSettings s,
|
||||
UserNotificationPreferences pref)
|
||||
{
|
||||
LoadIssues(opts);
|
||||
LoadCommon(req, s, pref);
|
||||
LoadTitle(opts, req);
|
||||
ProviderId = req?.ForeignArtistId ?? string.Empty;
|
||||
Year = req?.ReleaseDate.Year.ToString();
|
||||
AdditionalInformation = opts?.AdditionalInformation ?? string.Empty;
|
||||
PosterImage = req?.Cover.HasValue() ?? false ? req.Cover : req?.Disk ?? string.Empty;
|
||||
CalculateRequestStatus(req);
|
||||
}
|
||||
|
||||
private void LoadIssues(NotificationOptions opts)
|
||||
{
|
||||
var val = string.Empty;
|
||||
IssueDescription = opts.Substitutes.TryGetValue("IssueDescription", out val) ? val : string.Empty;
|
||||
IssueDescription = opts.Substitutes.TryGetValue("IssueDescription", out string val) ? val : string.Empty;
|
||||
IssueCategory = opts.Substitutes.TryGetValue("IssueCategory", out val) ? val : string.Empty;
|
||||
IssueStatus = opts.Substitutes.TryGetValue("IssueStatus", out val) ? val : string.Empty;
|
||||
IssueSubject = opts.Substitutes.TryGetValue("IssueSubject", out val) ? val : string.Empty;
|
||||
NewIssueComment = opts.Substitutes.TryGetValue("NewIssueComment", out val) ? val : string.Empty;
|
||||
UserName = opts.Substitutes.TryGetValue("IssueUser", out val) ? val : string.Empty;
|
||||
Alias = opts.Substitutes.TryGetValue("IssueUserAlias", out val) ? val : string.Empty;
|
||||
Type = opts.Substitutes.TryGetValue("RequestType", out val) ? val.Humanize() : string.Empty;
|
||||
Type = opts.Substitutes.TryGetValue("RequestType", out val) && Enum.TryParse(val, out RequestType type)
|
||||
? HumanizeReturnType(type)
|
||||
: string.Empty;
|
||||
}
|
||||
|
||||
private void LoadCommon(BaseRequest req, CustomizationSettings s, UserNotificationPreferences pref)
|
||||
{
|
||||
ApplicationName = string.IsNullOrEmpty(s?.ApplicationName) ? "Ombi" : s.ApplicationName;
|
||||
ApplicationUrl = s?.ApplicationUrl.HasValue() ?? false ? s.ApplicationUrl : string.Empty;
|
||||
AvailableDate = req?.MarkedAsAvailable?.ToString("D") ?? string.Empty;
|
||||
DenyReason = req?.DeniedReason;
|
||||
RequestId = req?.Id.ToString();
|
||||
RequestedUser = req?.RequestedUser?.UserName;
|
||||
RequestedDate = req?.RequestedDate.ToString("D");
|
||||
|
||||
if (Type.IsNullOrEmpty())
|
||||
{
|
||||
Type = HumanizeReturnType(req?.RequestType);
|
||||
}
|
||||
|
||||
if (UserName.IsNullOrEmpty())
|
||||
{
|
||||
UserName = req?.RequestedUser?.UserName;
|
||||
}
|
||||
|
||||
if (Alias.IsNullOrEmpty())
|
||||
{
|
||||
Alias = req?.RequestedUser?.Alias.HasValue() ?? false
|
||||
? req.RequestedUser?.Alias
|
||||
: req?.RequestedUser?.UserName;
|
||||
}
|
||||
|
||||
if (pref != null)
|
||||
{
|
||||
UserPreference = pref.Value.HasValue() ? pref.Value : Alias;
|
||||
}
|
||||
}
|
||||
|
||||
private static string HumanizeReturnType(RequestType? requestType)
|
||||
{
|
||||
return requestType switch
|
||||
{
|
||||
null => string.Empty,
|
||||
RequestType.TvShow => "TV Show",
|
||||
_ => requestType.Humanize()
|
||||
};
|
||||
}
|
||||
|
||||
private void LoadTitle(NotificationOptions opts, BaseRequest req)
|
||||
{
|
||||
switch (req)
|
||||
{
|
||||
case null:
|
||||
opts.Substitutes.TryGetValue("Title", out string title);
|
||||
Title = title;
|
||||
break;
|
||||
case ChildRequests tvShowRequest:
|
||||
Title = tvShowRequest.ParentRequest?.Title;
|
||||
break;
|
||||
default:
|
||||
Title = req.Title;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateRequestStatus(BaseRequest req)
|
||||
|
@ -238,16 +176,19 @@ namespace Ombi.Notifications
|
|||
RequestStatus = "Available";
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.Denied ?? false)
|
||||
{
|
||||
RequestStatus = "Denied";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!req.Available && req.Approved)
|
||||
{
|
||||
RequestStatus = "Processing Request";
|
||||
return;
|
||||
}
|
||||
|
||||
RequestStatus = "Pending Approval";
|
||||
}
|
||||
}
|
||||
|
@ -288,36 +229,36 @@ namespace Ombi.Notifications
|
|||
|
||||
public Dictionary<string, string> Curlys => new Dictionary<string, string>
|
||||
{
|
||||
{nameof(RequestId), RequestId },
|
||||
{nameof(RequestedUser), RequestedUser },
|
||||
{nameof(Title), Title },
|
||||
{nameof(RequestedDate), RequestedDate },
|
||||
{nameof(Type), Type },
|
||||
{nameof(AdditionalInformation), AdditionalInformation },
|
||||
{nameof(LongDate),LongDate},
|
||||
{nameof(ShortDate),ShortDate},
|
||||
{nameof(LongTime),LongTime},
|
||||
{nameof(ShortTime),ShortTime},
|
||||
{nameof(Overview),Overview},
|
||||
{nameof(Year),Year},
|
||||
{nameof(EpisodesList),EpisodesList},
|
||||
{nameof(SeasonsList),SeasonsList},
|
||||
{nameof(PosterImage),PosterImage},
|
||||
{nameof(ApplicationName),ApplicationName},
|
||||
{nameof(ApplicationUrl),ApplicationUrl},
|
||||
{nameof(IssueDescription),IssueDescription},
|
||||
{nameof(IssueCategory),IssueCategory},
|
||||
{nameof(IssueStatus),IssueStatus},
|
||||
{nameof(IssueSubject),IssueSubject},
|
||||
{nameof(NewIssueComment),NewIssueComment},
|
||||
{nameof(IssueUser),IssueUser},
|
||||
{nameof(UserName),UserName},
|
||||
{nameof(Alias),Alias},
|
||||
{nameof(UserPreference),UserPreference},
|
||||
{nameof(DenyReason),DenyReason},
|
||||
{nameof(AvailableDate),AvailableDate},
|
||||
{nameof(RequestStatus),RequestStatus},
|
||||
{nameof(ProviderId),ProviderId},
|
||||
{ nameof(RequestId), RequestId },
|
||||
{ nameof(RequestedUser), RequestedUser },
|
||||
{ nameof(Title), Title },
|
||||
{ nameof(RequestedDate), RequestedDate },
|
||||
{ nameof(Type), Type },
|
||||
{ nameof(AdditionalInformation), AdditionalInformation },
|
||||
{ nameof(LongDate), LongDate },
|
||||
{ nameof(ShortDate), ShortDate },
|
||||
{ nameof(LongTime), LongTime },
|
||||
{ nameof(ShortTime), ShortTime },
|
||||
{ nameof(Overview), Overview },
|
||||
{ nameof(Year), Year },
|
||||
{ nameof(EpisodesList), EpisodesList },
|
||||
{ nameof(SeasonsList), SeasonsList },
|
||||
{ nameof(PosterImage), PosterImage },
|
||||
{ nameof(ApplicationName), ApplicationName },
|
||||
{ nameof(ApplicationUrl), ApplicationUrl },
|
||||
{ nameof(IssueDescription), IssueDescription },
|
||||
{ nameof(IssueCategory), IssueCategory },
|
||||
{ nameof(IssueStatus), IssueStatus },
|
||||
{ nameof(IssueSubject), IssueSubject },
|
||||
{ nameof(NewIssueComment), NewIssueComment },
|
||||
{ nameof(IssueUser), IssueUser },
|
||||
{ nameof(UserName), UserName },
|
||||
{ nameof(Alias), Alias },
|
||||
{ nameof(UserPreference), UserPreference },
|
||||
{ nameof(DenyReason), DenyReason },
|
||||
{ nameof(AvailableDate), AvailableDate },
|
||||
{ nameof(RequestStatus), RequestStatus },
|
||||
{ nameof(ProviderId), ProviderId },
|
||||
};
|
||||
}
|
||||
}
|
35
src/Ombi.Schedule.Tests/NewsletterUnsubscribeTests.cs
Normal file
35
src/Ombi.Schedule.Tests/NewsletterUnsubscribeTests.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using NUnit.Framework;
|
||||
using Ombi.Schedule.Jobs.Ombi;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Schedule.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class NewsletterUnsubscribeTests
|
||||
{
|
||||
[TestCaseSource(nameof(Data))]
|
||||
public string GenerateUnsubscribeLinkTest(string appUrl, string id)
|
||||
{
|
||||
return NewsletterJob.GenerateUnsubscribeLink(appUrl, id);
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> Data
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("https://google.com/", "1").Returns("https://google.com:443/unsubscribe/1").SetName("Fully Qualified");
|
||||
yield return new TestCaseData("https://google.com", "1").Returns("https://google.com:443/unsubscribe/1").SetName("Missing Slash");
|
||||
yield return new TestCaseData("google.com", "1").Returns("http://google.com:80/unsubscribe/1").SetName("Missing scheme");
|
||||
yield return new TestCaseData("ombi.google.com", "1").Returns("http://ombi.google.com:80/unsubscribe/1").SetName("Sub domain missing scheme");
|
||||
yield return new TestCaseData("https://ombi.google.com", "1").Returns("https://ombi.google.com:443/unsubscribe/1").SetName("Sub domain");
|
||||
yield return new TestCaseData("https://ombi.google.com/", "1").Returns("https://ombi.google.com:443/unsubscribe/1").SetName("Sub domain with slash");
|
||||
yield return new TestCaseData("https://google.com/ombi/", "1").Returns("https://google.com:443/ombi/unsubscribe/1").SetName("RP");
|
||||
yield return new TestCaseData("https://google.com/ombi", "1").Returns("https://google.com:443/ombi/unsubscribe/1").SetName("RP missing slash");
|
||||
yield return new TestCaseData("https://google.com:3577", "1").Returns("https://google.com:3577/unsubscribe/1").SetName("Port");
|
||||
yield return new TestCaseData("https://google.com:3577/", "1").Returns("https://google.com:3577/unsubscribe/1").SetName("Port With Slash");
|
||||
yield return new TestCaseData("", "1").Returns(string.Empty).SetName("Missing App URL empty");
|
||||
yield return new TestCaseData(null, "1").Returns(string.Empty).SetName("Missing App URL null");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ using Ombi.Store.Entities;
|
|||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Store.Repository.Requests;
|
||||
using Ombi.Helpers;
|
||||
|
||||
namespace Ombi.Schedule.Tests
|
||||
{
|
||||
|
@ -53,7 +54,7 @@ namespace Ombi.Schedule.Tests
|
|||
ImdbId = "test"
|
||||
};
|
||||
_movie.Setup(x => x.GetAll()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
||||
_repo.Setup(x => x.Get("test")).ReturnsAsync(new PlexServerContent());
|
||||
_repo.Setup(x => x.Get("test", ProviderType.ImdbId)).ReturnsAsync(new PlexServerContent());
|
||||
|
||||
await Checker.Execute(null);
|
||||
|
||||
|
|
|
@ -5,6 +5,6 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
public interface IOmbiAutomaticUpdater : IBaseJob
|
||||
{
|
||||
string[] GetVersion();
|
||||
Task<bool> UpdateAvailable(string branch, string currentVersion);
|
||||
Task<bool> UpdateAvailable(string currentVersion);
|
||||
}
|
||||
}
|
|
@ -130,11 +130,11 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
var jellyfinContent = _jellyfin.GetAll().Include(x => x.Episodes).AsNoTracking();
|
||||
var lidarrContent = _lidarrAlbumRepository.GetAll().AsNoTracking().ToList().Where(x => x.FullyAvailable);
|
||||
|
||||
var addedLog = _recentlyAddedLog.GetAll();
|
||||
var addedPlexMovieLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).Select(x => x.ContentId).ToHashSet();
|
||||
var addedEmbyMoviesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Parent).Select(x => x.ContentId).ToHashSet();
|
||||
var addedJellyfinMoviesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Jellyfin && x.ContentType == ContentType.Parent).Select(x => x.ContentId).ToHashSet();
|
||||
var addedAlbumLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Lidarr && x.ContentType == ContentType.Album).Select(x => x.AlbumId).ToHashSet();
|
||||
var addedLog = _recentlyAddedLog.GetAll().ToList();
|
||||
|
||||
HashSet<int> addedPlexMovieLogIds, addedEmbyMoviesLogIds, addedJellyfinMoviesLogIds;
|
||||
HashSet<string> addedAlbumLogIds;
|
||||
GetRecentlyAddedMoviesData(addedLog, out addedPlexMovieLogIds, out addedEmbyMoviesLogIds, out addedJellyfinMoviesLogIds, out addedAlbumLogIds);
|
||||
|
||||
var addedPlexEpisodesLogIds =
|
||||
addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode);
|
||||
|
@ -170,6 +170,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
|
||||
plexContentMoviesToSend = plexContentMoviesToSend.DistinctBy(x => x.Id).ToHashSet();
|
||||
embyContentMoviesToSend = embyContentMoviesToSend.DistinctBy(x => x.Id).ToHashSet();
|
||||
jellyfinContentMoviesToSend = jellyfinContentMoviesToSend.DistinctBy(x => x.Id).ToHashSet();
|
||||
|
||||
var plexEpisodesToSend =
|
||||
FilterPlexEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), addedPlexEpisodesLogIds);
|
||||
|
@ -226,32 +227,33 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
var messageContent = ParseTemplate(template, customization);
|
||||
var email = new NewsletterTemplate();
|
||||
|
||||
var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo);
|
||||
|
||||
var bodyBuilder = new BodyBuilder
|
||||
{
|
||||
HtmlBody = html,
|
||||
};
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = bodyBuilder.ToMessageBody(),
|
||||
Subject = messageContent.Subject
|
||||
};
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
var url = GenerateUnsubscribeLink(customization.ApplicationUrl, user.Id);
|
||||
var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo, url);
|
||||
|
||||
var bodyBuilder = new BodyBuilder
|
||||
{
|
||||
HtmlBody = html,
|
||||
};
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = bodyBuilder.ToMessageBody(),
|
||||
Subject = messageContent.Subject
|
||||
};
|
||||
|
||||
// Get the users to send it to
|
||||
if (user.Email.IsNullOrEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// BCC the messages
|
||||
message.Bcc.Add(new MailboxAddress(user.Email.Trim(), user.Email.Trim()));
|
||||
}
|
||||
// Send the message to the user
|
||||
message.To.Add(new MailboxAddress(user.Email.Trim(), user.Email.Trim()));
|
||||
|
||||
// Send the email
|
||||
await _email.Send(message, emailSettings);
|
||||
// Send the email
|
||||
await _email.Send(message, emailSettings);
|
||||
}
|
||||
|
||||
// Now add all of this to the Recently Added log
|
||||
var recentlyAddedLog = new HashSet<RecentlyAddedLog>();
|
||||
|
@ -344,11 +346,14 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var unsubscribeLink = GenerateUnsubscribeLink(customization.ApplicationUrl, a.Id);
|
||||
|
||||
var messageContent = ParseTemplate(template, customization);
|
||||
|
||||
var email = new NewsletterTemplate();
|
||||
|
||||
var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo);
|
||||
var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo, unsubscribeLink);
|
||||
|
||||
await _email.Send(
|
||||
new NotificationMessage { Message = html, Subject = messageContent.Subject, To = a.Email },
|
||||
|
@ -369,6 +374,36 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
.SendAsync(NotificationHub.NotificationEvent, "Newsletter Finished");
|
||||
}
|
||||
|
||||
private void GetRecentlyAddedMoviesData(List<RecentlyAddedLog> addedLog, out HashSet<int> addedPlexMovieLogIds, out HashSet<int> addedEmbyMoviesLogIds, out HashSet<int> addedJellyfinMoviesLogIds, out HashSet<string> addedAlbumLogIds)
|
||||
{
|
||||
var plexParent = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).ToList();
|
||||
addedPlexMovieLogIds = plexParent != null && plexParent.Any() ? (plexParent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet<int>()) : new HashSet<int>();
|
||||
|
||||
var embyParent = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Parent);
|
||||
addedEmbyMoviesLogIds = embyParent != null && embyParent.Any() ? (embyParent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet<int>()) : new HashSet<int>();
|
||||
|
||||
var jellyFinParent = addedLog.Where(x => x.Type == RecentlyAddedType.Jellyfin && x.ContentType == ContentType.Parent);
|
||||
addedJellyfinMoviesLogIds = jellyFinParent != null && jellyFinParent.Any() ? (jellyFinParent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet<int>()) : new HashSet<int>();
|
||||
|
||||
var lidarrParent = addedLog.Where(x => x.Type == RecentlyAddedType.Lidarr && x.ContentType == ContentType.Album);
|
||||
addedAlbumLogIds = lidarrParent != null && lidarrParent.Any() ? (lidarrParent?.Select(x => x.AlbumId)?.ToHashSet() ?? new HashSet<string>()) : new HashSet<string>();
|
||||
}
|
||||
|
||||
public static string GenerateUnsubscribeLink(string applicationUrl, string id)
|
||||
{
|
||||
if (!applicationUrl.HasValue())
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (!applicationUrl.EndsWith('/'))
|
||||
{
|
||||
applicationUrl += '/';
|
||||
}
|
||||
var b = new UriBuilder($"{applicationUrl}unsubscribe/{id}");
|
||||
return b.ToString();
|
||||
}
|
||||
|
||||
private async Task<HashSet<PlexServerContent>> GetMoviesWithoutId(HashSet<int> addedMovieLogIds, HashSet<PlexServerContent> needsMovieDbPlex)
|
||||
{
|
||||
foreach (var movie in needsMovieDbPlex)
|
||||
|
@ -466,7 +501,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
await Start(newsletterSettings, false);
|
||||
}
|
||||
|
||||
private HashSet<PlexEpisode> FilterPlexEpisodes(IEnumerable<PlexEpisode> source, IQueryable<RecentlyAddedLog> recentlyAdded)
|
||||
private HashSet<PlexEpisode> FilterPlexEpisodes(IEnumerable<PlexEpisode> source, IEnumerable<RecentlyAddedLog> recentlyAdded)
|
||||
{
|
||||
var itemsToReturn = new HashSet<PlexEpisode>();
|
||||
foreach (var ep in source.Where(x => x.Series.HasTvDb))
|
||||
|
@ -483,7 +518,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
return itemsToReturn;
|
||||
}
|
||||
|
||||
private HashSet<EmbyEpisode> FilterEmbyEpisodes(IEnumerable<EmbyEpisode> source, IQueryable<RecentlyAddedLog> recentlyAdded)
|
||||
private HashSet<EmbyEpisode> FilterEmbyEpisodes(IEnumerable<EmbyEpisode> source, IEnumerable<RecentlyAddedLog> recentlyAdded)
|
||||
{
|
||||
var itemsToReturn = new HashSet<EmbyEpisode>();
|
||||
foreach (var ep in source.Where(x => x.Series.HasTvDb))
|
||||
|
@ -500,7 +535,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
return itemsToReturn;
|
||||
}
|
||||
|
||||
private HashSet<JellyfinEpisode> FilterJellyfinEpisodes(IEnumerable<JellyfinEpisode> source, IQueryable<RecentlyAddedLog> recentlyAdded)
|
||||
private HashSet<JellyfinEpisode> FilterJellyfinEpisodes(IEnumerable<JellyfinEpisode> source, IEnumerable<RecentlyAddedLog> recentlyAdded)
|
||||
{
|
||||
var itemsToReturn = new HashSet<JellyfinEpisode>();
|
||||
foreach (var ep in source.Where(x => x.Series.HasTvDb))
|
||||
|
@ -537,7 +572,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
var plexMovies = plexContentToSend.Where(x => x.Type == PlexMediaTypeEntity.Movie);
|
||||
var embyMovies = embyContentToSend.Where(x => x.Type == EmbyMediaType.Movie);
|
||||
var jellyfinMovies = jellyfinContentToSend.Where(x => x.Type == JellyfinMediaType.Movie);
|
||||
if ((plexMovies.Any() || embyMovies.Any()) && !settings.DisableMovies)
|
||||
if ((plexMovies.Any() || embyMovies.Any() || jellyfinMovies.Any()) && !settings.DisableMovies)
|
||||
{
|
||||
sb.Append("<h1 style=\"text-align: center; max-width: 1042px;\">New Movies</h1><br /><br />");
|
||||
sb.Append(
|
||||
|
@ -568,7 +603,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
sb.Append("</table>");
|
||||
}
|
||||
|
||||
if ((plexEpisodes.Any() || embyEp.Any()) || jellyfinEp.Any() && !settings.DisableTv)
|
||||
if ((plexEpisodes.Any() || embyEp.Any() || jellyfinEp.Any()) && !settings.DisableTv)
|
||||
{
|
||||
sb.Append("<br /><br /><h1 style=\"text-align: center; max-width: 1042px;\">New TV</h1><br /><br />");
|
||||
sb.Append(
|
||||
|
|
|
@ -49,10 +49,10 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
var productArray = productVersion.Split('-');
|
||||
return productArray;
|
||||
}
|
||||
public async Task<bool> UpdateAvailable(string branch, string currentVersion)
|
||||
public async Task<bool> UpdateAvailable(string currentVersion)
|
||||
{
|
||||
|
||||
var updates = await Processor.Process(branch);
|
||||
var updates = await Processor.Process();
|
||||
var serverVersion = updates.UpdateVersionString;
|
||||
return !serverVersion.Equals(currentVersion, StringComparison.CurrentCultureIgnoreCase);
|
||||
|
||||
|
@ -88,7 +88,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Looking for updates now");
|
||||
//TODO this fails because the branch = featureupdater when it should be feature/updater
|
||||
var updates = await Processor.Process(branch);
|
||||
var updates = await Processor.Process();
|
||||
Logger.LogDebug(LoggingEvents.Updater, "Updates: {0}", updates);
|
||||
|
||||
|
||||
|
|
|
@ -183,13 +183,13 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
PlexServerContent item = null;
|
||||
if (movie.ImdbId.HasValue())
|
||||
{
|
||||
item = await _repo.Get(movie.ImdbId);
|
||||
item = await _repo.Get(movie.ImdbId, ProviderType.ImdbId);
|
||||
}
|
||||
if (item == null)
|
||||
{
|
||||
if (movie.TheMovieDbId.ToString().HasValue())
|
||||
{
|
||||
item = await _repo.Get(movie.TheMovieDbId.ToString());
|
||||
item = await _repo.Get(movie.TheMovieDbId.ToString(), ProviderType.TheMovieDbId);
|
||||
}
|
||||
}
|
||||
if (item == null)
|
||||
|
|
|
@ -175,7 +175,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
|||
|
||||
var allEps = Repo.GetAllEpisodes();
|
||||
|
||||
foreach (var content in allContent)
|
||||
foreach (var content in allContent.OrderByDescending(x => x.viewGroup))
|
||||
{
|
||||
Logger.LogDebug($"Got type '{content.viewGroup}' to process");
|
||||
if (content.viewGroup.Equals(PlexMediaType.Episode.ToString(), StringComparison.InvariantCultureIgnoreCase))
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Ombi.Schedule.Jobs.Radarr
|
|||
{
|
||||
public class RadarrSync : IRadarrSync
|
||||
{
|
||||
public RadarrSync(ISettingsService<RadarrSettings> radarr, IRadarrApi radarrApi, ILogger<RadarrSync> log, ExternalContext ctx)
|
||||
public RadarrSync(ISettingsService<RadarrSettings> radarr, IRadarrV3Api radarrApi, ILogger<RadarrSync> log, ExternalContext ctx)
|
||||
{
|
||||
RadarrSettings = radarr;
|
||||
RadarrApi = radarrApi;
|
||||
|
@ -27,7 +27,7 @@ namespace Ombi.Schedule.Jobs.Radarr
|
|||
}
|
||||
|
||||
private ISettingsService<RadarrSettings> RadarrSettings { get; }
|
||||
private IRadarrApi RadarrApi { get; }
|
||||
private IRadarrV3Api RadarrApi { get; }
|
||||
private ILogger<RadarrSync> Logger { get; }
|
||||
private readonly ExternalContext _ctx;
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Sonarr;
|
||||
using Ombi.Api.Sonarr.Models;
|
||||
using Ombi.Api.TheMovieDb;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Schedule.Jobs.Radarr;
|
||||
|
@ -21,12 +23,14 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
{
|
||||
public class SonarrSync : ISonarrSync
|
||||
{
|
||||
public SonarrSync(ISettingsService<SonarrSettings> s, ISonarrApi api, ILogger<SonarrSync> l, ExternalContext ctx)
|
||||
public SonarrSync(ISettingsService<SonarrSettings> s, ISonarrApi api, ILogger<SonarrSync> l, ExternalContext ctx,
|
||||
IMovieDbApi movieDbApi)
|
||||
{
|
||||
_settings = s;
|
||||
_api = api;
|
||||
_log = l;
|
||||
_ctx = ctx;
|
||||
_movieDbApi = movieDbApi;
|
||||
_settings.ClearCache();
|
||||
}
|
||||
|
||||
|
@ -34,6 +38,7 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
private readonly ISonarrApi _api;
|
||||
private readonly ILogger<SonarrSync> _log;
|
||||
private readonly ExternalContext _ctx;
|
||||
private readonly IMovieDbApi _movieDbApi;
|
||||
|
||||
public async Task Execute(IJobExecutionContext job)
|
||||
{
|
||||
|
@ -48,7 +53,17 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
if (series != null)
|
||||
{
|
||||
var sonarrSeries = series as ImmutableHashSet<SonarrSeries> ?? series.ToImmutableHashSet();
|
||||
var ids = sonarrSeries.Select(x => x.tvdbId);
|
||||
var ids = sonarrSeries.Select(x => new SonarrDto
|
||||
{
|
||||
TvDbId = x.tvdbId,
|
||||
ImdbId = x.imdbId,
|
||||
Title = x.title,
|
||||
MovieDbId = 0,
|
||||
Id = x.id,
|
||||
Monitored = x.monitored,
|
||||
EpisodeFileCount = x.episodeFileCount
|
||||
}).ToHashSet();
|
||||
|
||||
var strat = _ctx.Database.CreateExecutionStrategy();
|
||||
await strat.ExecuteAsync(async () =>
|
||||
{
|
||||
|
@ -60,12 +75,27 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
});
|
||||
|
||||
var existingSeries = await _ctx.SonarrCache.Select(x => x.TvDbId).ToListAsync();
|
||||
|
||||
//var entites = ids.Except(existingSeries).Select(id => new SonarrCache { TvDbId = id }).ToImmutableHashSet();
|
||||
var entites = ids.Select(id => new SonarrCache { TvDbId = id }).ToImmutableHashSet();
|
||||
|
||||
await _ctx.SonarrCache.AddRangeAsync(entites);
|
||||
entites.Clear();
|
||||
var sonarrCacheToSave = new HashSet<SonarrCache>();
|
||||
foreach (var id in ids)
|
||||
{
|
||||
var cache = new SonarrCache
|
||||
{
|
||||
TvDbId = id.TvDbId
|
||||
};
|
||||
|
||||
var findResult = await _movieDbApi.Find(id.TvDbId.ToString(), ExternalSource.tvdb_id);
|
||||
if (findResult.tv_results.Any())
|
||||
{
|
||||
cache.TheMovieDbId = findResult.tv_results.FirstOrDefault()?.id ?? -1;
|
||||
id.MovieDbId = cache.TheMovieDbId;
|
||||
}
|
||||
sonarrCacheToSave.Add(cache);
|
||||
}
|
||||
|
||||
await _ctx.SonarrCache.AddRangeAsync(sonarrCacheToSave);
|
||||
await _ctx.SaveChangesAsync();
|
||||
sonarrCacheToSave.Clear();
|
||||
strat = _ctx.Database.CreateExecutionStrategy();
|
||||
await strat.ExecuteAsync(async () =>
|
||||
{
|
||||
|
@ -76,15 +106,15 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
}
|
||||
});
|
||||
|
||||
foreach (var s in sonarrSeries)
|
||||
foreach (var s in ids)
|
||||
{
|
||||
if (!s.monitored || s.episodeFileCount == 0) // We have files
|
||||
if (!s.Monitored || s.EpisodeFileCount == 0) // We have files
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_log.LogDebug("Syncing series: {0}", s.title);
|
||||
var episodes = await _api.GetEpisodes(s.id, settings.ApiKey, settings.FullUri);
|
||||
_log.LogDebug("Syncing series: {0}", s.Title);
|
||||
var episodes = await _api.GetEpisodes(s.Id, settings.ApiKey, settings.FullUri);
|
||||
var monitoredEpisodes = episodes.Where(x => x.monitored || x.hasFile);
|
||||
|
||||
//var allExistingEpisodes = await _ctx.SonarrEpisodeCache.Where(x => x.TvDbId == s.tvdbId).ToListAsync();
|
||||
|
@ -95,7 +125,8 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
{
|
||||
EpisodeNumber = episode.episodeNumber,
|
||||
SeasonNumber = episode.seasonNumber,
|
||||
TvDbId = s.tvdbId,
|
||||
TvDbId = s.TvDbId,
|
||||
MovieDbId = s.MovieDbId,
|
||||
HasFile = episode.hasFile
|
||||
});
|
||||
//var episodesToAdd = new List<SonarrEpisodeCache>();
|
||||
|
@ -166,5 +197,16 @@ namespace Ombi.Schedule.Jobs.Sonarr
|
|||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private class SonarrDto
|
||||
{
|
||||
public int TvDbId { get; set; }
|
||||
public string ImdbId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public int MovieDbId { get; set; }
|
||||
public int Id { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public int EpisodeFileCount { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -109,8 +109,8 @@ namespace Ombi.Core.Processor
|
|||
public string UpdateVersionString { get; set; }
|
||||
public int UpdateVersion { get; set; }
|
||||
public DateTime UpdateDate { get; set; }
|
||||
|
||||
public List<ChangeLog> ChangeLogs { get; set; }
|
||||
public bool UpdateAvailable { get; set; }
|
||||
public string ChangeLogs { get; set; }
|
||||
public List<Downloads> Downloads { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
@ -16,94 +16,41 @@ namespace Ombi.Schedule.Processor
|
|||
{
|
||||
public class ChangeLogProcessor : IChangeLogProcessor
|
||||
{
|
||||
public ChangeLogProcessor(IApi api, IOmbiHttpClient client)
|
||||
public ChangeLogProcessor(IApi api, IHttpClientFactory client)
|
||||
{
|
||||
_api = api;
|
||||
_client = client;
|
||||
_client = client.CreateClient("OmbiClient");
|
||||
}
|
||||
|
||||
private readonly IApi _api;
|
||||
private readonly IOmbiHttpClient _client;
|
||||
private readonly HttpClient _client;
|
||||
private const string _changeLogUrl = "https://raw.githubusercontent.com/tidusjar/Ombi/{0}/CHANGELOG.md";
|
||||
private const string AppveyorApiUrl = "https://ci.appveyor.com/api";
|
||||
private string ChangeLogUrl(string branch) => string.Format(_changeLogUrl, branch);
|
||||
|
||||
public async Task<UpdateModel> Process(string branch)
|
||||
public async Task<UpdateModel> Process()
|
||||
{
|
||||
var masterBranch = branch.Equals("master", StringComparison.CurrentCultureIgnoreCase);
|
||||
string githubChangeLog;
|
||||
|
||||
githubChangeLog = await _client.GetStringAsync(new Uri(ChangeLogUrl(branch)));
|
||||
|
||||
|
||||
var html = Markdown.ToHtml(githubChangeLog);
|
||||
|
||||
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(html);
|
||||
|
||||
HtmlNode latestRelease;
|
||||
if (masterBranch)
|
||||
{
|
||||
latestRelease = doc.DocumentNode.Descendants("h2")
|
||||
.FirstOrDefault(x => x.InnerText != "(unreleased)");
|
||||
}
|
||||
else
|
||||
{
|
||||
latestRelease = doc.DocumentNode.Descendants("h2")
|
||||
.FirstOrDefault(x => x.InnerText == "(unreleased)");
|
||||
|
||||
if (latestRelease == null)
|
||||
{
|
||||
latestRelease = doc.DocumentNode.Descendants("h2")
|
||||
.FirstOrDefault(x => x.InnerText != "(unreleased)");
|
||||
}
|
||||
}
|
||||
|
||||
var newFeatureList = latestRelease.NextSibling.NextSibling.NextSibling.NextSibling;
|
||||
var featuresString = newFeatureList.ChildNodes.Where(x => x.Name != "#text").Select(x => x.InnerText.Replace("\\n", "")).ToList();
|
||||
var fixes = newFeatureList.NextSibling.NextSibling.NextSibling.NextSibling;
|
||||
var fixesString = fixes.ChildNodes.Where(x => x.Name != "#text").Select(x => x.InnerText.Replace("\\n", "")).ToList();
|
||||
|
||||
// Cleanup
|
||||
var featuresList = featuresString.Distinct().ToList();
|
||||
var fixesList = fixesString.Distinct().ToList();
|
||||
|
||||
// Get release
|
||||
var release = new Release
|
||||
{
|
||||
Version = latestRelease.InnerText,
|
||||
Features = featuresList,
|
||||
Fixes = fixesList,
|
||||
Downloads = new List<Downloads>()
|
||||
};
|
||||
|
||||
if (masterBranch)
|
||||
{
|
||||
var releaseTag = latestRelease.InnerText.Substring(0, 9);
|
||||
await GetGitubRelease(release, releaseTag);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get AppVeyor
|
||||
await GetAppVeyorRelease(release, branch);
|
||||
}
|
||||
|
||||
|
||||
return TransformUpdate(release,!masterBranch);
|
||||
|
||||
await GetGitubRelease(release);
|
||||
|
||||
return TransformUpdate(release);
|
||||
}
|
||||
|
||||
private UpdateModel TransformUpdate(Release release, bool develop)
|
||||
private UpdateModel TransformUpdate(Release release)
|
||||
{
|
||||
var newUpdate = new UpdateModel
|
||||
{
|
||||
UpdateVersionString = develop ? release.Version : release.Version.Substring(1,8),
|
||||
UpdateVersion = release.Version == "(unreleased)" ? 0 : int.Parse(release.Version.Substring(1, 5).Replace(".", "")),
|
||||
UpdateVersionString = release.Version,
|
||||
UpdateVersion = int.Parse(release.Version.Substring(1, 5).Replace(".", "")),
|
||||
UpdateDate = DateTime.Now,
|
||||
ChangeLogs = new List<ChangeLog>(),
|
||||
Downloads = new List<Downloads>()
|
||||
};
|
||||
ChangeLogs = release.Description,
|
||||
Downloads = new List<Downloads>(),
|
||||
UpdateAvailable = release.Version != "v" + AssemblyHelper.GetRuntimeVersion()
|
||||
};
|
||||
|
||||
foreach (var dl in release.Downloads)
|
||||
{
|
||||
|
@ -114,75 +61,16 @@ namespace Ombi.Schedule.Processor
|
|||
});
|
||||
}
|
||||
|
||||
foreach (var f in release.Features)
|
||||
{
|
||||
var change = new ChangeLog
|
||||
{
|
||||
Descripion = f,
|
||||
Type = "New",
|
||||
};
|
||||
|
||||
newUpdate.ChangeLogs.Add(change);
|
||||
}
|
||||
|
||||
foreach (var f in release.Fixes)
|
||||
{
|
||||
var change = new ChangeLog
|
||||
{
|
||||
Descripion = f,
|
||||
Type = "Fixed",
|
||||
};
|
||||
|
||||
newUpdate.ChangeLogs.Add(change);
|
||||
}
|
||||
|
||||
return newUpdate;
|
||||
}
|
||||
|
||||
private async Task GetAppVeyorRelease(Release release, string branch)
|
||||
private async Task GetGitubRelease(Release release)
|
||||
{
|
||||
var request = new Request($"/projects/tidusjar/requestplex/branch/{branch}", AppVeyorApi.AppveyorApiUrl, HttpMethod.Get);
|
||||
request.ApplicationJsonContentType();
|
||||
var client = new GitHubClient(Octokit.ProductHeaderValue.Parse("OmbiV4"));
|
||||
|
||||
var builds = await _api.Request<AppveyorBranchResult>(request);
|
||||
var jobId = builds.build.jobs.FirstOrDefault()?.jobId ?? string.Empty;
|
||||
var releases = await client.Repository.Release.GetAll("ombi-app", "ombi");
|
||||
var latest = releases.OrderByDescending(x => x.CreatedAt).FirstOrDefault();
|
||||
|
||||
if (builds.build.finished == DateTime.MinValue || builds.build.status.Equals("failed"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
release.Version = builds.build.version;
|
||||
// get the artifacts
|
||||
request = new Request($"/buildjobs/{jobId}/artifacts", AppVeyorApi.AppveyorApiUrl, HttpMethod.Get);
|
||||
request.ApplicationJsonContentType();
|
||||
|
||||
var artifacts = await _api.Request<List<BuildArtifacts>>(request);
|
||||
|
||||
foreach (var item in artifacts)
|
||||
{
|
||||
var d = new Downloads
|
||||
{
|
||||
Name = item.fileName,
|
||||
Url = $"{AppveyorApiUrl}/buildjobs/{jobId}/artifacts/{item.fileName}"
|
||||
};
|
||||
release.Downloads.Add(d);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetGitubRelease(Release release, string releaseTag)
|
||||
{
|
||||
var client = new GitHubClient(Octokit.ProductHeaderValue.Parse("OmbiV3"));
|
||||
|
||||
var releases = await client.Repository.Release.GetAll("tidusjar", "ombi");
|
||||
var latest = releases.FirstOrDefault(x => x.TagName.Equals(releaseTag, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (latest.Name.Contains("V2", CompareOptions.IgnoreCase))
|
||||
{
|
||||
latest = null;
|
||||
}
|
||||
if (latest == null)
|
||||
{
|
||||
latest = releases.OrderByDescending(x => x.CreatedAt).FirstOrDefault();
|
||||
}
|
||||
foreach (var item in latest.Assets)
|
||||
{
|
||||
var d = new Downloads
|
||||
|
@ -192,6 +80,8 @@ namespace Ombi.Schedule.Processor
|
|||
};
|
||||
release.Downloads.Add(d);
|
||||
}
|
||||
release.Description = Markdown.ToHtml(latest.Body);
|
||||
release.Version = latest.TagName;
|
||||
}
|
||||
}
|
||||
public class Release
|
||||
|
@ -199,8 +89,7 @@ namespace Ombi.Schedule.Processor
|
|||
public string Version { get; set; }
|
||||
public string CheckinVersion { get; set; }
|
||||
public List<Downloads> Downloads { get; set; }
|
||||
public List<string> Features { get; set; }
|
||||
public List<string> Fixes { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
|
||||
public class Downloads
|
||||
|
|
|
@ -4,6 +4,6 @@ namespace Ombi.Core.Processor
|
|||
{
|
||||
public interface IChangeLogProcessor
|
||||
{
|
||||
Task<UpdateModel> Process(string branch);
|
||||
Task<UpdateModel> Process();
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
public class RadarrSettings : ExternalSettings
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public bool V3 { get; set; }
|
||||
public string ApiKey { get; set; }
|
||||
public string DefaultQualityProfile { get; set; }
|
||||
public string DefaultRootPath { get; set; }
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
public bool AddOnly { get; set; }
|
||||
public bool V3 { get; set; }
|
||||
public int LanguageProfile { get; set; }
|
||||
public int LanguageProfileAnime { get; set; }
|
||||
public bool ScanForAvailability { get; set; }
|
||||
}
|
||||
}
|
|
@ -7,5 +7,9 @@ namespace Ombi.Core.Settings.Models.External
|
|||
public bool ShowAdultMovies { get; set; }
|
||||
|
||||
public List<int> ExcludedKeywordIds { get; set; }
|
||||
|
||||
public List<int> ExcludedMovieGenreIds { get; set; }
|
||||
|
||||
public List<int> ExcludedTvGenreIds { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Ombi.Settings.Settings.Models.Notifications
|
|||
public string WebhookUrl { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Icon { get; set; }
|
||||
public bool HideUser { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public string WebHookId => SplitWebUrl(4);
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
public bool CollectAnalyticData { get; set; }
|
||||
public bool Wizard { get; set; }
|
||||
public string ApiKey { get; set; }
|
||||
public bool IgnoreCertificateErrors { get; set; }
|
||||
public bool DoNotSendNotificationsForAutoApprove { get; set; }
|
||||
public bool HideRequestsUsers { get; set; }
|
||||
public bool DisableHealthChecks { get; set; }
|
||||
|
|
|
@ -41,12 +41,12 @@ namespace Ombi.Settings.Settings
|
|||
var model = obj;
|
||||
|
||||
return model;
|
||||
}, DateTime.Now.AddHours(2));
|
||||
}, DateTimeOffset.Now.AddHours(2));
|
||||
}
|
||||
|
||||
public async Task<T> GetSettingsAsync()
|
||||
{
|
||||
return await _cache.GetOrAdd(CacheName, async () =>
|
||||
return await _cache.GetOrAddAsync(CacheName, async () =>
|
||||
{
|
||||
var result = await Repo.GetAsync(EntityName);
|
||||
if (result == null)
|
||||
|
@ -61,7 +61,7 @@ namespace Ombi.Settings.Settings
|
|||
var model = obj;
|
||||
|
||||
return model;
|
||||
}, DateTime.Now.AddHours(5));
|
||||
}, DateTimeOffset.Now.AddHours(5));
|
||||
}
|
||||
|
||||
public bool SaveSettings(T model)
|
||||
|
|
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