mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-31 03:50:08 -07:00
commit
dde517cecc
129 changed files with 4120 additions and 842 deletions
|
@ -27,4 +27,4 @@ variables:
|
||||||
value: "4.0.$(Build.BuildId)"
|
value: "4.0.$(Build.BuildId)"
|
||||||
|
|
||||||
- name: isMain
|
- 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
|
# Ignore local vscode config
|
||||||
*.vscode
|
*.vscode
|
||||||
/src/Ombi/database.json
|
/src/Ombi/database.json
|
||||||
|
/src/Ombi/databases.json
|
||||||
/src/Ombi/healthchecksdb
|
/src/Ombi/healthchecksdb
|
||||||
/src/Ombi/ClientApp/package-lock.json
|
/src/Ombi/ClientApp/package-lock.json
|
||||||
|
|
|
@ -1,39 +1,122 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Mime;
|
||||||
|
|
||||||
namespace Ombi.Api.Radarr.Models
|
namespace Ombi.Api.Radarr.Models
|
||||||
{
|
{
|
||||||
public class MovieResponse
|
public class MovieResponse
|
||||||
{
|
{
|
||||||
public string title { get; set; }
|
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 string sortTitle { get; set; }
|
||||||
public double sizeOnDisk { get; set; }
|
public long sizeOnDisk { get; set; }
|
||||||
public string status { get; set; }
|
public string status { get; set; }
|
||||||
public string overview { get; set; }
|
public string overview { get; set; }
|
||||||
public string inCinemas { get; set; }
|
public DateTime inCinemas { get; set; }
|
||||||
public string physicalRelease { get; set; }
|
public DateTime physicalRelease { get; set; }
|
||||||
public List<Image> images { get; set; }
|
public DateTime digitalRelease { get; set; }
|
||||||
|
public Image[] images { get; set; }
|
||||||
public string website { get; set; }
|
public string website { get; set; }
|
||||||
public bool downloaded { get; set; }
|
|
||||||
public int year { get; set; }
|
public int year { get; set; }
|
||||||
public bool hasFile { get; set; }
|
public bool hasFile { get; set; }
|
||||||
public string youTubeTrailerId { get; set; }
|
public string youTubeTrailerId { get; set; }
|
||||||
public string studio { get; set; }
|
public string studio { get; set; }
|
||||||
public string path { get; set; }
|
public string path { get; set; }
|
||||||
public int profileId { get; set; }
|
public int qualityProfileId { get; set; }
|
||||||
public string minimumAvailability { get; set; }
|
|
||||||
public bool monitored { 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 int runtime { get; set; }
|
||||||
public string lastInfoSync { get; set; }
|
|
||||||
public string cleanTitle { get; set; }
|
public string cleanTitle { get; set; }
|
||||||
public string imdbId { get; set; }
|
public string imdbId { get; set; }
|
||||||
public int tmdbId { get; set; }
|
public int tmdbId { get; set; }
|
||||||
public string titleSlug { get; set; }
|
public string titleSlug { get; set; }
|
||||||
public List<string> genres { get; set; }
|
public string certification { get; set; }
|
||||||
public List<object> tags { get; set; }
|
public string[] genres { get; set; }
|
||||||
public string added { get; set; }
|
public object[] tags { get; set; }
|
||||||
|
public DateTime added { get; set; }
|
||||||
public Ratings ratings { get; set; }
|
public Ratings ratings { get; set; }
|
||||||
//public List<string> alternativeTitles { get; set; }
|
public Moviefile movieFile { get; set; }
|
||||||
public int qualityProfileId { get; set; }
|
public Collection collection { get; set; }
|
||||||
public int id { 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 string titleSlug { get; set; }
|
||||||
public int year { get; set; }
|
public int year { get; set; }
|
||||||
public string minimumAvailability { get; set; }
|
public string minimumAvailability { get; set; }
|
||||||
|
public long sizeOnDisk { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -82,7 +82,8 @@ namespace Ombi.Api.Radarr
|
||||||
titleSlug = title + year,
|
titleSlug = title + year,
|
||||||
monitored = true,
|
monitored = true,
|
||||||
year = year,
|
year = year,
|
||||||
minimumAvailability = minimumAvailability
|
minimumAvailability = minimumAvailability,
|
||||||
|
sizeOnDisk = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
if (searchNow)
|
if (searchNow)
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace Ombi.Api.Radarr
|
||||||
|
|
||||||
public async Task<MovieResponse> UpdateMovie(MovieResponse movie, string apiKey, string baseUrl)
|
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);
|
AddHeaders(request, apiKey);
|
||||||
request.AddJsonBody(movie);
|
request.AddJsonBody(movie);
|
||||||
|
|
||||||
|
@ -85,7 +85,8 @@ namespace Ombi.Api.Radarr
|
||||||
titleSlug = title + year,
|
titleSlug = title + year,
|
||||||
monitored = true,
|
monitored = true,
|
||||||
year = year,
|
year = year,
|
||||||
minimumAvailability = minimumAvailability
|
minimumAvailability = minimumAvailability,
|
||||||
|
sizeOnDisk = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
if (searchNow)
|
if (searchNow)
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Ombi.Api.Webhook
|
||||||
|
|
||||||
public async Task PushAsync(string baseUrl, string accessToken, IDictionary<string, string> parameters)
|
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))
|
if (!string.IsNullOrWhiteSpace(accessToken))
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,14 +16,14 @@ namespace Ombi.Api
|
||||||
{
|
{
|
||||||
public class Api : IApi
|
public class Api : IApi
|
||||||
{
|
{
|
||||||
public Api(ILogger<Api> log, IOmbiHttpClient client)
|
public Api(ILogger<Api> log, HttpClient client)
|
||||||
{
|
{
|
||||||
Logger = log;
|
Logger = log;
|
||||||
_client = client;
|
_client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ILogger<Api> Logger { get; }
|
private ILogger<Api> Logger { get; }
|
||||||
private readonly IOmbiHttpClient _client;
|
private readonly HttpClient _client;
|
||||||
|
|
||||||
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
|
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
|
||||||
{
|
{
|
||||||
|
|
|
@ -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>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="Polly" Version="7.1.0" />
|
<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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -30,7 +30,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
public async Task Should_Not_Be_Monitored_Or_Available()
|
public async Task Should_Not_Be_Monitored_Or_Available()
|
||||||
{
|
{
|
||||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
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.True(result.Success);
|
||||||
Assert.False(request.Approved);
|
Assert.False(request.Approved);
|
||||||
|
@ -49,7 +49,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
}
|
}
|
||||||
}.AsQueryable());
|
}.AsQueryable());
|
||||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
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.True(result.Success);
|
||||||
Assert.False(request.Approved);
|
Assert.False(request.Approved);
|
||||||
|
@ -71,7 +71,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
}
|
}
|
||||||
}.AsQueryable());
|
}.AsQueryable());
|
||||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
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.True(result.Success);
|
||||||
Assert.False(request.Approved);
|
Assert.False(request.Approved);
|
||||||
|
@ -93,7 +93,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
}
|
}
|
||||||
}.AsQueryable());
|
}.AsQueryable());
|
||||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
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.True(result.Success);
|
||||||
Assert.False(request.Approved);
|
Assert.False(request.Approved);
|
||||||
|
@ -114,7 +114,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
}
|
}
|
||||||
}.AsQueryable());
|
}.AsQueryable());
|
||||||
var request = new SearchAlbumViewModel { ForeignAlbumId = "abc" };
|
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.True(result.Success);
|
||||||
Assert.False(request.Approved);
|
Assert.False(request.Approved);
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
public async Task Should_Not_Be_Monitored()
|
public async Task Should_Not_Be_Monitored()
|
||||||
{
|
{
|
||||||
var request = new SearchArtistViewModel { ForignArtistId = "abc" };
|
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(result.Success);
|
||||||
Assert.False(request.Monitored);
|
Assert.False(request.Monitored);
|
||||||
|
@ -46,7 +46,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
}
|
}
|
||||||
}.AsQueryable());
|
}.AsQueryable());
|
||||||
var request = new SearchArtistViewModel { ForignArtistId = "abc" };
|
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(result.Success);
|
||||||
Assert.True(request.Monitored);
|
Assert.True(request.Monitored);
|
||||||
|
@ -64,7 +64,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
}
|
}
|
||||||
}.AsQueryable());
|
}.AsQueryable());
|
||||||
var request = new SearchArtistViewModel { ForignArtistId = "abc" };
|
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(result.Success);
|
||||||
Assert.True(request.Monitored);
|
Assert.True(request.Monitored);
|
||||||
|
|
|
@ -9,6 +9,7 @@ using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Ombi.Core.Authentication;
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine.Interfaces
|
namespace Ombi.Core.Engine.Interfaces
|
||||||
{
|
{
|
||||||
|
@ -29,6 +30,10 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
private OmbiUser _user;
|
private OmbiUser _user;
|
||||||
protected async Task<OmbiUser> GetUser()
|
protected async Task<OmbiUser> GetUser()
|
||||||
{
|
{
|
||||||
|
if(!Username.HasValue())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
var username = Username.ToUpper();
|
var username = Username.ToUpper();
|
||||||
return _user ?? (_user = await UserManager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username));
|
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);
|
var ruleResults = await Rules.StartSearchRules(model);
|
||||||
return ruleResults;
|
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;
|
return ruleResults;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies(int currentPosition, int amountToLoad);
|
Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies(int currentPosition, int amountToLoad);
|
||||||
Task<MovieCollectionsViewModel> GetCollection(int collectionId, CancellationToken cancellationToken, string langCode = null);
|
Task<MovieCollectionsViewModel> GetCollection(int collectionId, CancellationToken cancellationToken, string langCode = null);
|
||||||
Task<int> GetTvDbId(int theMovieDbId);
|
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>> TopRatedMovies(int currentlyLoaded, int toLoad);
|
||||||
Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies(int currentlyLoaded, int toLoad);
|
Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies(int currentlyLoaded, int toLoad);
|
||||||
Task<ActorCredits> GetMoviesByActor(int actorId, string langCode);
|
Task<ActorCredits> GetMoviesByActor(int actorId, string langCode);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ombi.Core.Models;
|
using Ombi.Core.Models;
|
||||||
using Ombi.Core.Models.Requests;
|
using Ombi.Core.Models.Requests;
|
||||||
|
@ -24,5 +25,6 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
Task UnSubscribeRequest(int requestId, RequestType type);
|
Task UnSubscribeRequest(int requestId, RequestType type);
|
||||||
Task SubscribeToRequest(int requestId, RequestType type);
|
Task SubscribeToRequest(int requestId, RequestType type);
|
||||||
Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user = null);
|
Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user = null);
|
||||||
|
Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ namespace Ombi.Core
|
||||||
Task<SearchFullInfoTvShowViewModel> GetShowInformation(string tvdbid, CancellationToken token);
|
Task<SearchFullInfoTvShowViewModel> GetShowInformation(string tvdbid, CancellationToken token);
|
||||||
Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId, CancellationToken token);
|
Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId, CancellationToken token);
|
||||||
Task<IEnumerable<StreamingData>> GetStreamInformation(int movieDbId, CancellationToken cancellationToken);
|
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>> Anticipated(int currentlyLoaded, int amountToLoad);
|
||||||
Task<IEnumerable<SearchTvShowViewModel>> Trending(int currentlyLoaded, int amountToLoad);
|
Task<IEnumerable<SearchTvShowViewModel>> Trending(int currentlyLoaded, int amountToLoad);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ using Ombi.Settings.Settings.Models;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
using Ombi.Core.Models;
|
using Ombi.Core.Models;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
|
@ -70,7 +71,7 @@ namespace Ombi.Core.Engine
|
||||||
var canRequestOnBehalf = model.RequestOnBehalf.HasValue();
|
var canRequestOnBehalf = model.RequestOnBehalf.HasValue();
|
||||||
|
|
||||||
var isAdmin = await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser) || await UserManager.IsInRoleAsync(userDetails, OmbiRoles.Admin);
|
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
|
return new RequestEngineResult
|
||||||
{
|
{
|
||||||
|
@ -549,12 +550,17 @@ namespace Ombi.Core.Engine
|
||||||
request.Denied = false;
|
request.Denied = false;
|
||||||
await MovieRepository.Update(request);
|
await MovieRepository.Update(request);
|
||||||
|
|
||||||
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification);
|
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification, string.Empty);
|
||||||
if (canNotify.Success)
|
if (canNotify.Success)
|
||||||
{
|
{
|
||||||
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return await ProcessSendingMovie(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<RequestEngineResult> ProcessSendingMovie(MovieRequests request)
|
||||||
|
{
|
||||||
if (request.Approved)
|
if (request.Approved)
|
||||||
{
|
{
|
||||||
var result = await Sender.Send(request);
|
var result = await Sender.Send(request);
|
||||||
|
@ -634,6 +640,21 @@ namespace Ombi.Core.Engine
|
||||||
return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId);
|
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)
|
public async Task<RequestEngineResult> MarkUnavailable(int modelId)
|
||||||
{
|
{
|
||||||
var request = await MovieRepository.Find(modelId);
|
var request = await MovieRepository.Find(modelId);
|
||||||
|
@ -682,7 +703,7 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
await MovieRepository.Add(model);
|
await MovieRepository.Add(model);
|
||||||
|
|
||||||
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification);
|
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification, requestOnBehalf);
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
await NotificationHelper.NewRequest(model);
|
await NotificationHelper.NewRequest(model);
|
||||||
|
|
|
@ -362,7 +362,7 @@ namespace Ombi.Core.Engine
|
||||||
await MusicRepository.Update(request);
|
await MusicRepository.Update(request);
|
||||||
|
|
||||||
|
|
||||||
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification);
|
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification, string.Empty);
|
||||||
if (canNotify.Success)
|
if (canNotify.Success)
|
||||||
{
|
{
|
||||||
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
||||||
|
@ -506,7 +506,7 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
await MusicRepository.Add(model);
|
await MusicRepository.Add(model);
|
||||||
|
|
||||||
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification);
|
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification, string.Empty);
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
await NotificationHelper.NewRequest(model);
|
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;
|
return vm;
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
vm.Cover = a.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url?.ToHttpsUrl();
|
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);
|
await RunSearchRules(vm);
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ namespace Ombi.Core.Engine
|
||||||
vm.Cover = a.remoteCover;
|
vm.Cover = a.remoteCover;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum);
|
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum, string.Empty);
|
||||||
|
|
||||||
await RunSearchRules(vm);
|
await RunSearchRules(vm);
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ namespace Ombi.Core.Engine
|
||||||
vm.Cover = fullAlbum.remoteCover;
|
vm.Cover = fullAlbum.remoteCover;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum);
|
await Rules.StartSpecificRules(vm, SpecificRules.LidarrAlbum, string.Empty);
|
||||||
|
|
||||||
await RunSearchRules(vm);
|
await RunSearchRules(vm);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ using Ombi.Settings.Settings.Models;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
using Ombi.Core.Models;
|
using Ombi.Core.Models;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
|
@ -164,7 +165,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
|
return new RequestEngineResult
|
||||||
{
|
{
|
||||||
|
@ -250,7 +251,7 @@ namespace Ombi.Core.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a new request
|
// 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);
|
return await AddRequest(newRequest.NewRequest, tv.RequestOnBehalf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -896,9 +897,25 @@ namespace Ombi.Core.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId, cancellationToken);
|
||||||
|
if (request == null)
|
||||||
|
{
|
||||||
|
return new RequestEngineResult
|
||||||
|
{
|
||||||
|
Result = false,
|
||||||
|
ErrorMessage = "Request does not exist"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return await ProcessSendingShow(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task<RequestEngineResult> AfterRequest(ChildRequests model, string requestOnBehalf)
|
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)
|
if (sendRuleResult.Success)
|
||||||
{
|
{
|
||||||
await NotificationHelper.NewRequest(model);
|
await NotificationHelper.NewRequest(model);
|
||||||
|
@ -913,6 +930,11 @@ namespace Ombi.Core.Engine
|
||||||
EpisodeCount = model.SeasonRequests.Select(m => m.Episodes.Count).Sum(),
|
EpisodeCount = model.SeasonRequests.Select(m => m.Episodes.Count).Sum(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return await ProcessSendingShow(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<RequestEngineResult> ProcessSendingShow(ChildRequests model)
|
||||||
|
{
|
||||||
if (model.Approved)
|
if (model.Approved)
|
||||||
{
|
{
|
||||||
// Autosend
|
// Autosend
|
||||||
|
@ -997,6 +1019,10 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
request.QualityOverride = options.QualityOverride;
|
request.QualityOverride = options.QualityOverride;
|
||||||
request.RootFolder = options.RootPathOverride;
|
request.RootFolder = options.RootPathOverride;
|
||||||
|
if (options.LanguageProfile > 0)
|
||||||
|
{
|
||||||
|
request.LanguageProfile = options.LanguageProfile;
|
||||||
|
}
|
||||||
|
|
||||||
await TvRepository.Update(request);
|
await TvRepository.Update(request);
|
||||||
|
|
||||||
|
|
|
@ -124,9 +124,9 @@ namespace Ombi.Core.Engine.V2
|
||||||
/// Gets popular movies by paging
|
/// Gets popular movies by paging
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <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 pages = PaginationHelper.GetNextPages(currentlyLoaded, toLoad, _theMovieDbMaxPageItems);
|
||||||
|
|
||||||
|
@ -371,6 +371,7 @@ namespace Ombi.Core.Engine.V2
|
||||||
mapped.Requested = movie.Requested;
|
mapped.Requested = movie.Requested;
|
||||||
mapped.PlexUrl = movie.PlexUrl;
|
mapped.PlexUrl = movie.PlexUrl;
|
||||||
mapped.EmbyUrl = movie.EmbyUrl;
|
mapped.EmbyUrl = movie.EmbyUrl;
|
||||||
|
mapped.JellyfinUrl = movie.JellyfinUrl;
|
||||||
mapped.Subscribed = movie.Subscribed;
|
mapped.Subscribed = movie.Subscribed;
|
||||||
mapped.ShowSubscribe = movie.ShowSubscribe;
|
mapped.ShowSubscribe = movie.ShowSubscribe;
|
||||||
mapped.ReleaseDate = movie.ReleaseDate;
|
mapped.ReleaseDate = movie.ReleaseDate;
|
||||||
|
|
|
@ -22,6 +22,7 @@ using Microsoft.EntityFrameworkCore;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Ombi.Api.TheMovieDb;
|
using Ombi.Api.TheMovieDb;
|
||||||
using Ombi.Api.TheMovieDb.Models;
|
using Ombi.Api.TheMovieDb.Models;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine.V2
|
namespace Ombi.Core.Engine.V2
|
||||||
{
|
{
|
||||||
|
@ -49,13 +50,14 @@ namespace Ombi.Core.Engine.V2
|
||||||
public async Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId, CancellationToken token)
|
public async Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId, CancellationToken token)
|
||||||
{
|
{
|
||||||
var request = await RequestService.TvRequestService.Get().FirstOrDefaultAsync(x => x.Id == requestId);
|
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)
|
public async Task<SearchFullInfoTvShowViewModel> GetShowInformation(string tvdbid, CancellationToken token)
|
||||||
{
|
{
|
||||||
var show = await Cache.GetOrAdd(nameof(GetShowInformation) + tvdbid,
|
var langCode = await DefaultLanguageCode(null);
|
||||||
async () => await _movieApi.GetTVInfo(tvdbid), DateTime.Now.AddHours(12));
|
var show = await Cache.GetOrAdd(nameof(GetShowInformation) + langCode + tvdbid,
|
||||||
|
async () => await _movieApi.GetTVInfo(tvdbid, langCode), DateTime.Now.AddHours(12));
|
||||||
if (show == null || show.name == null)
|
if (show == null || show.name == null)
|
||||||
{
|
{
|
||||||
// We don't have enough information
|
// We don't have enough information
|
||||||
|
@ -69,47 +71,15 @@ namespace Ombi.Core.Engine.V2
|
||||||
{
|
{
|
||||||
var seasonEpisodes = (await _movieApi.GetSeasonEpisodes(show.id, tvSeason.season_number, token));
|
var seasonEpisodes = (await _movieApi.GetSeasonEpisodes(show.id, tvSeason.season_number, token));
|
||||||
|
|
||||||
foreach (var episode in seasonEpisodes.episodes)
|
MapSeasons(mapped.SeasonRequests, tvSeason, seasonEpisodes);
|
||||||
{
|
|
||||||
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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return await ProcessResult(mapped);
|
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 pages = PaginationHelper.GetNextPages(currentlyLoaded, amountToLoad, ResultLimit);
|
||||||
var results = new List<MovieDbSearchResult>();
|
var results = new List<MovieDbSearchResult>();
|
||||||
|
@ -152,6 +122,7 @@ namespace Ombi.Core.Engine.V2
|
||||||
async () => await _movieApi.TopRatedTv(langCode, pagesToLoad.Page), DateTime.Now.AddHours(12));
|
async () => await _movieApi.TopRatedTv(langCode, pagesToLoad.Page), DateTime.Now.AddHours(12));
|
||||||
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
results.AddRange(apiResult.Skip(pagesToLoad.Skip).Take(pagesToLoad.Take));
|
||||||
}
|
}
|
||||||
|
|
||||||
var processed = ProcessResults(results);
|
var processed = ProcessResults(results);
|
||||||
return await processed;
|
return await processed;
|
||||||
}
|
}
|
||||||
|
@ -177,22 +148,77 @@ namespace Ombi.Core.Engine.V2
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IEnumerable<SearchTvShowViewModel>> ProcessResults<T>(IEnumerable<T> items)
|
private async Task<IEnumerable<SearchTvShowViewModel>> ProcessResults(List<MovieDbSearchResult> items)
|
||||||
{
|
{
|
||||||
var retVal = new List<SearchTvShowViewModel>();
|
var retVal = new List<SearchTvShowViewModel>();
|
||||||
var settings = await _customization.GetSettingsAsync();
|
var settings = await _customization.GetSettingsAsync();
|
||||||
|
|
||||||
foreach (var tvMazeSearch in items)
|
foreach (var tvMazeSearch in items)
|
||||||
{
|
{
|
||||||
|
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.GetOrAdd(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.GetOrAdd("SeasonEpisodes" + show.id + tvSeason.season_number, async () =>
|
||||||
|
{
|
||||||
|
return await _movieApi.GetSeasonEpisodes(show.id, tvSeason.season_number, CancellationToken.None);
|
||||||
|
}, DateTime.Now.AddHours(12));
|
||||||
|
|
||||||
|
MapSeasons(tvMazeSearch.SeasonRequests, tvSeason, seasonEpisodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var result = await ProcessResult(tvMazeSearch);
|
var result = await ProcessResult(tvMazeSearch);
|
||||||
if (result == null || settings.HideAvailableFromDiscover && result.Available)
|
if (result == null || settings.HideAvailableFromDiscover && result.FullyAvailable)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
retVal.Add(result);
|
retVal.Add(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
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)
|
private async Task<SearchTvShowViewModel> ProcessResult<T>(T tvMazeSearch)
|
||||||
{
|
{
|
||||||
var item = _mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
var item = _mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
|
||||||
|
@ -216,6 +242,9 @@ namespace Ombi.Core.Engine.V2
|
||||||
item.Approved = oldModel.Approved;
|
item.Approved = oldModel.Approved;
|
||||||
item.SeasonRequests = oldModel.SeasonRequests;
|
item.SeasonRequests = oldModel.SeasonRequests;
|
||||||
item.RequestId = oldModel.RequestId;
|
item.RequestId = oldModel.RequestId;
|
||||||
|
item.PlexUrl = oldModel.PlexUrl;
|
||||||
|
item.EmbyUrl = oldModel.EmbyUrl;
|
||||||
|
item.JellyfinUrl = oldModel.JellyfinUrl;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(item.Images?.Medium))
|
if (!string.IsNullOrEmpty(item.Images?.Medium))
|
||||||
{
|
{
|
||||||
|
|
|
@ -217,7 +217,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);
|
int.TryParse(TheMovieDbRecord.ExternalIds?.TvDbId, out var tvdbId);
|
||||||
NewRequest = new TvRequests
|
NewRequest = new TvRequests
|
||||||
|
@ -234,7 +234,8 @@ namespace Ombi.Core.Helpers
|
||||||
TotalSeasons = tv.Seasons.Count(),
|
TotalSeasons = tv.Seasons.Count(),
|
||||||
Background = BackdropPath,
|
Background = BackdropPath,
|
||||||
RootFolder = rootPathOverride,
|
RootFolder = rootPathOverride,
|
||||||
QualityOverride = qualityOverride
|
QualityOverride = qualityOverride,
|
||||||
|
LanguageProfile = langProfile
|
||||||
};
|
};
|
||||||
NewRequest.ChildRequests.Add(ChildRequest);
|
NewRequest.ChildRequests.Add(ChildRequest);
|
||||||
|
|
||||||
|
|
|
@ -5,5 +5,6 @@
|
||||||
public int RequestId { get; set; }
|
public int RequestId { get; set; }
|
||||||
public int RootPathOverride { get; set; }
|
public int RootPathOverride { get; set; }
|
||||||
public int QualityOverride { 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 RequestAll { get; set; }
|
||||||
public bool LatestSeason { get; set; }
|
public bool LatestSeason { get; set; }
|
||||||
|
public int? LanguageProfile { get; set; }
|
||||||
public bool FirstSeason { get; set; }
|
public bool FirstSeason { get; set; }
|
||||||
public List<SeasonsViewModel> Seasons { get; set; } = new List<SeasonsViewModel>();
|
public List<SeasonsViewModel> Seasons { get; set; } = new List<SeasonsViewModel>();
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
|
|
|
@ -58,9 +58,6 @@ namespace Ombi.Core.Models.Search
|
||||||
public bool PartlyAvailable { get; set; }
|
public bool PartlyAvailable { get; set; }
|
||||||
public override RequestType Type => RequestType.TvShow;
|
public override RequestType Type => RequestType.TvShow;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Only set on the images call
|
|
||||||
/// </summary>
|
|
||||||
public string BackdropPath { get; set; }
|
public string BackdropPath { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,6 +9,6 @@ namespace Ombi.Core.Rule.Interfaces
|
||||||
{
|
{
|
||||||
Task<IEnumerable<RuleResult>> StartRequestRules(BaseRequest obj);
|
Task<IEnumerable<RuleResult>> StartRequestRules(BaseRequest obj);
|
||||||
Task<IEnumerable<RuleResult>> StartSearchRules(SearchViewModel 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()
|
public interface ISpecificRule<T> where T : new()
|
||||||
{
|
{
|
||||||
Task<RuleResult> Execute(T obj);
|
Task<RuleResult> Execute(T obj, string requestOnBehalf);
|
||||||
SpecificRules Rule { get; }
|
SpecificRules Rule { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -58,13 +58,13 @@ namespace Ombi.Core.Rule
|
||||||
return results;
|
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)
|
foreach (var rule in SpecificRules)
|
||||||
{
|
{
|
||||||
if (selectedRule == rule.Rule)
|
if (selectedRule == rule.Rule)
|
||||||
{
|
{
|
||||||
var result = await rule.Execute(obj);
|
var result = await rule.Execute(obj, requestOnBehalf);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
{
|
{
|
||||||
public static void CheckForUnairedEpisodes(SearchTvShowViewModel 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 we have all the episodes for this season, then this season is available
|
||||||
if (season.Episodes.All(x => x.Available))
|
if (season.Episodes.All(x => x.Available))
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
var s = await EmbySettings.GetSettingsAsync();
|
var s = await EmbySettings.GetSettingsAsync();
|
||||||
if (s.Enable)
|
if (s.Enable)
|
||||||
{
|
{
|
||||||
var server = s.Servers.FirstOrDefault(x => x.ServerHostname != null);
|
var server = s.Servers.FirstOrDefault();
|
||||||
if ((server?.ServerHostname ?? string.Empty).HasValue())
|
if ((server?.ServerHostname ?? string.Empty).HasValue())
|
||||||
{
|
{
|
||||||
obj.EmbyUrl = EmbyHelper.GetEmbyMediaUrl(item.EmbyId, server?.ServerId, server?.ServerHostname);
|
obj.EmbyUrl = EmbyHelper.GetEmbyMediaUrl(item.EmbyId, server?.ServerId, server?.ServerHostname);
|
||||||
|
|
|
@ -9,7 +9,7 @@ using Ombi.Store.Repository;
|
||||||
|
|
||||||
namespace Ombi.Core.Rule.Rules.Search
|
namespace Ombi.Core.Rule.Rules.Search
|
||||||
{
|
{
|
||||||
public class LidarrAlbumCacheRule : BaseSearchRule, IRules<SearchViewModel>
|
public class LidarrAlbumCacheRule : SpecificRule, ISpecificRule<object>
|
||||||
{
|
{
|
||||||
public LidarrAlbumCacheRule(IExternalRepository<LidarrAlbumCache> db)
|
public LidarrAlbumCacheRule(IExternalRepository<LidarrAlbumCache> db)
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,9 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
|
|
||||||
private readonly IExternalRepository<LidarrAlbumCache> _db;
|
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)
|
if (objec is SearchAlbumViewModel obj)
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
|
|
||||||
private readonly IExternalRepository<LidarrArtistCache> _db;
|
private readonly IExternalRepository<LidarrArtistCache> _db;
|
||||||
|
|
||||||
public Task<RuleResult> Execute(object objec)
|
public Task<RuleResult> Execute(object objec, string requestOnBehalf)
|
||||||
{
|
{
|
||||||
var obj = (SearchArtistViewModel) objec;
|
var obj = (SearchArtistViewModel) objec;
|
||||||
// Check if it's in Lidarr
|
// Check if it's in Lidarr
|
||||||
|
@ -30,6 +30,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
return Task.FromResult(Success());
|
return Task.FromResult(Success());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override SpecificRules Rule => SpecificRules.LidarrArtist;
|
public override SpecificRules Rule => SpecificRules.LidarrArtist;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,10 +25,11 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
PlexServerContent item = null;
|
PlexServerContent item = null;
|
||||||
var useImdb = false;
|
var useImdb = false;
|
||||||
var useTheMovieDb = false;
|
var useTheMovieDb = false;
|
||||||
|
var useId = false;
|
||||||
var useTvDb = false;
|
var useTvDb = false;
|
||||||
if (obj.ImdbId.HasValue())
|
if (obj.ImdbId.HasValue())
|
||||||
{
|
{
|
||||||
item = await PlexContentRepository.Get(obj.ImdbId);
|
item = await PlexContentRepository.Get(obj.ImdbId, ProviderType.ImdbId);
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
useImdb = true;
|
useImdb = true;
|
||||||
|
@ -36,9 +37,17 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
}
|
}
|
||||||
if (item == null)
|
if (item == null)
|
||||||
{
|
{
|
||||||
|
if (obj.Id > 0)
|
||||||
|
{
|
||||||
|
item = await PlexContentRepository.Get(obj.Id.ToString(), ProviderType.TheMovieDbId);
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
useId = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (obj.TheMovieDbId.HasValue())
|
if (obj.TheMovieDbId.HasValue())
|
||||||
{
|
{
|
||||||
item = await PlexContentRepository.Get(obj.TheMovieDbId);
|
item = await PlexContentRepository.Get(obj.TheMovieDbId, ProviderType.TheMovieDbId);
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
useTheMovieDb = true;
|
useTheMovieDb = true;
|
||||||
|
@ -49,7 +58,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
{
|
{
|
||||||
if (obj.TheTvDbId.HasValue())
|
if (obj.TheTvDbId.HasValue())
|
||||||
{
|
{
|
||||||
item = await PlexContentRepository.Get(obj.TheTvDbId);
|
item = await PlexContentRepository.Get(obj.TheTvDbId, ProviderType.TvDbId);
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
useTvDb = true;
|
useTvDb = true;
|
||||||
|
@ -60,6 +69,11 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
|
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
|
if (useId)
|
||||||
|
{
|
||||||
|
obj.TheMovieDbId = obj.Id.ToString();
|
||||||
|
useTheMovieDb = true;
|
||||||
|
}
|
||||||
obj.Available = true;
|
obj.Available = true;
|
||||||
obj.PlexUrl = item.Url;
|
obj.PlexUrl = item.Url;
|
||||||
obj.Quality = item.Quality;
|
obj.Quality = item.Quality;
|
||||||
|
@ -71,9 +85,9 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
if (search.SeasonRequests.Any())
|
if (search.SeasonRequests.Any())
|
||||||
{
|
{
|
||||||
var allEpisodes = PlexContentRepository.GetAllEpisodes();
|
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);
|
await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb, Log);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,20 @@ namespace Ombi.Core.Rule.Rules.Specific
|
||||||
private OmbiUserManager UserManager { get; }
|
private OmbiUserManager UserManager { get; }
|
||||||
private ISettingsService<OmbiSettings> Settings { 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 req = (BaseRequest)obj;
|
||||||
|
var canRequestonBehalf = requestOnBehalf.HasValue();
|
||||||
var settings = await Settings.GetSettingsAsync();
|
var settings = await Settings.GetSettingsAsync();
|
||||||
var sendNotification = true;
|
var sendNotification = true;
|
||||||
|
|
||||||
|
if (settings.DoNotSendNotificationsForAutoApprove && canRequestonBehalf)
|
||||||
|
{
|
||||||
|
return new RuleResult
|
||||||
|
{
|
||||||
|
Success = false
|
||||||
|
};
|
||||||
|
}
|
||||||
var requestedUser = await UserManager.Users.FirstOrDefaultAsync(x => x.Id == req.RequestedUserId);
|
var requestedUser = await UserManager.Users.FirstOrDefaultAsync(x => x.Id == req.RequestedUserId);
|
||||||
if (req.RequestType == RequestType.Movie)
|
if (req.RequestType == RequestType.Movie)
|
||||||
{
|
{
|
||||||
|
|
|
@ -158,6 +158,8 @@ namespace Ombi.Core.Senders
|
||||||
}
|
}
|
||||||
|
|
||||||
int qualityToUse;
|
int qualityToUse;
|
||||||
|
var sonarrV3 = s.V3;
|
||||||
|
var languageProfileId = s.LanguageProfile;
|
||||||
string rootFolderPath;
|
string rootFolderPath;
|
||||||
string seriesType;
|
string seriesType;
|
||||||
|
|
||||||
|
@ -167,8 +169,17 @@ namespace Ombi.Core.Senders
|
||||||
{
|
{
|
||||||
// Get the root path from the rootfolder selected.
|
// Get the root path from the rootfolder selected.
|
||||||
// For some reason, if we haven't got one use the first root folder in Sonarr
|
// For some reason, if we haven't got one use the first root folder in Sonarr
|
||||||
rootFolderPath = await GetSonarrRootPath(int.Parse(s.RootPathAnime), s);
|
if (!int.TryParse(s.RootPathAnime, out int animePath))
|
||||||
int.TryParse(s.QualityProfileAnime, out qualityToUse);
|
{
|
||||||
|
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 != null)
|
||||||
{
|
{
|
||||||
if (profiles.SonarrRootPathAnime > 0)
|
if (profiles.SonarrRootPathAnime > 0)
|
||||||
|
@ -181,7 +192,6 @@ namespace Ombi.Core.Senders
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
seriesType = "anime";
|
seriesType = "anime";
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -221,9 +231,14 @@ namespace Ombi.Core.Senders
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are we using v3 sonarr?
|
if (model.ParentRequest.LanguageProfile.HasValue)
|
||||||
var sonarrV3 = s.V3;
|
{
|
||||||
var languageProfileId = s.LanguageProfile;
|
var languageProfile = model.ParentRequest.LanguageProfile.Value;
|
||||||
|
if (languageProfile > 0)
|
||||||
|
{
|
||||||
|
languageProfileId = languageProfile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -264,6 +279,10 @@ namespace Ombi.Core.Senders
|
||||||
var seasonsToAdd = GetSeasonsToCreate(model);
|
var seasonsToAdd = GetSeasonsToCreate(model);
|
||||||
newSeries.seasons = seasonsToAdd;
|
newSeries.seasons = seasonsToAdd;
|
||||||
var result = await SonarrApi.AddSeries(newSeries, s.ApiKey, s.FullUri);
|
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);
|
existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri);
|
||||||
await SendToSonarr(model, existingSeries, s);
|
await SendToSonarr(model, existingSeries, s);
|
||||||
}
|
}
|
||||||
|
@ -407,7 +426,6 @@ namespace Ombi.Core.Senders
|
||||||
await SonarrApi.SeasonPass(s.ApiKey, s.FullUri, result);
|
await SonarrApi.SeasonPass(s.ApiKey, s.FullUri, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!s.AddOnly)
|
if (!s.AddOnly)
|
||||||
{
|
{
|
||||||
await SearchForRequest(model, sonarrEpList, result, s, episodesToUpdate);
|
await SearchForRequest(model, sonarrEpList, result, s, episodesToUpdate);
|
||||||
|
|
|
@ -23,7 +23,6 @@ using Ombi.Notifications;
|
||||||
using Ombi.Schedule;
|
using Ombi.Schedule;
|
||||||
using Ombi.Schedule.Jobs;
|
using Ombi.Schedule.Jobs;
|
||||||
using Ombi.Settings.Settings;
|
using Ombi.Settings.Settings;
|
||||||
using Ombi.Store.Context;
|
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
using Ombi.Notifications.Agents;
|
using Ombi.Notifications.Agents;
|
||||||
using Ombi.Schedule.Jobs.Radarr;
|
using Ombi.Schedule.Jobs.Radarr;
|
||||||
|
@ -68,6 +67,8 @@ using Ombi.Api.MusicBrainz;
|
||||||
using Ombi.Api.Twilio;
|
using Ombi.Api.Twilio;
|
||||||
using Ombi.Api.CloudService;
|
using Ombi.Api.CloudService;
|
||||||
using Ombi.Api.RottenTomatoes;
|
using Ombi.Api.RottenTomatoes;
|
||||||
|
using System.Net.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Ombi.DependencyInjection
|
namespace Ombi.DependencyInjection
|
||||||
{
|
{
|
||||||
|
@ -119,14 +120,24 @@ namespace Ombi.DependencyInjection
|
||||||
|
|
||||||
public static void RegisterHttp(this IServiceCollection services)
|
public static void RegisterHttp(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
var runtimeVersion = AssemblyHelper.GetRuntimeVersion();
|
||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
services.AddScoped<IPrincipal>(sp => sp.GetService<IHttpContextAccessor>().HttpContext.User);
|
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)
|
public static void RegisterApi(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddScoped<IApi, Api.Api>();
|
services.AddScoped<IApi, Api.Api>(s => new Api.Api(s.GetRequiredService<ILogger<Api.Api>>(), s.GetRequiredService<IHttpClientFactory>().CreateClient("OmbiClient")));
|
||||||
services.AddScoped<IOmbiHttpClient, OmbiHttpClient>(); // https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/
|
|
||||||
services.AddTransient<IMovieDbApi, Api.TheMovieDb.TheMovieDbApi>();
|
services.AddTransient<IMovieDbApi, Api.TheMovieDb.TheMovieDbApi>();
|
||||||
services.AddTransient<IPlexApi, PlexApi>();
|
services.AddTransient<IPlexApi, PlexApi>();
|
||||||
services.AddTransient<IEmbyApi, EmbyApi>();
|
services.AddTransient<IEmbyApi, EmbyApi>();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -61,6 +61,7 @@ namespace Ombi.Helpers.Tests
|
||||||
get
|
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", 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|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|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");
|
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 Microsoft.Extensions.PlatformAbstractions;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Ombi.Helpers
|
namespace Ombi.Helpers
|
||||||
|
@ -8,7 +9,8 @@ namespace Ombi.Helpers
|
||||||
public static string GetRuntimeVersion()
|
public static string GetRuntimeVersion()
|
||||||
{
|
{
|
||||||
ApplicationEnvironment app = PlatformServices.Default.Application;
|
ApplicationEnvironment app = PlatformServices.Default.Application;
|
||||||
return app.ApplicationVersion;
|
var split = app.ApplicationVersion.Split('.');
|
||||||
|
return string.Join('.', split.Take(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -81,7 +81,9 @@ namespace Ombi.Mapping.Profiles
|
||||||
.ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.VoteAverage.ToString()))
|
.ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.VoteAverage.ToString()))
|
||||||
.ForMember(dest => dest.BackdropPath, opts => opts.MapFrom(src => src.PosterPath))
|
.ForMember(dest => dest.BackdropPath, opts => opts.MapFrom(src => src.PosterPath))
|
||||||
//.ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.Runtime.ToString()))
|
//.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.Status, opts => opts.MapFrom(src => TraktEnumHelper.GetDescription(src.Status)))
|
||||||
//.ForMember(dest => dest.Trailer,
|
//.ForMember(dest => dest.Trailer,
|
||||||
// opts => opts.MapFrom(src => src.Trailer != null ? src.Trailer.ToString().ToHttpsUrl() : string.Empty))
|
// opts => opts.MapFrom(src => src.Trailer != null ? src.Trailer.ToString().ToHttpsUrl() : string.Empty))
|
||||||
|
|
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>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AutoFixture" Version="4.11.0" />
|
||||||
<PackageReference Include="Nunit" Version="3.11.0" />
|
<PackageReference Include="Nunit" Version="3.11.0" />
|
||||||
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
<PackageReference Include="NUnit.ConsoleRunner" Version="3.9.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||||
|
|
|
@ -106,21 +106,23 @@ namespace Ombi.Notifications.Agents
|
||||||
};
|
};
|
||||||
|
|
||||||
var fields = new List<DiscordField>();
|
var fields = new List<DiscordField>();
|
||||||
|
if (!settings.HideUser)
|
||||||
if (model.Data.TryGetValue("Alias", out var alias))
|
|
||||||
{
|
{
|
||||||
if (alias.HasValue())
|
if (model.Data.TryGetValue("Alias", out var alias))
|
||||||
{
|
{
|
||||||
fields.Add(new DiscordField { name = "Requested By", value = alias, inline = true });
|
if (alias.HasValue())
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (model.Data.TryGetValue("RequestedUser", out var requestedUser))
|
|
||||||
{
|
|
||||||
if (requestedUser.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)
|
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())
|
if (user.Email.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -304,9 +304,9 @@ namespace Ombi.Notifications.Agents
|
||||||
|
|
||||||
private async Task AddSubscribedUsers(List<string> playerIds)
|
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;
|
var notificationId = user.NotificationUserIds;
|
||||||
if (notificationId.Any())
|
if (notificationId.Any())
|
||||||
|
|
|
@ -57,6 +57,7 @@ namespace Ombi.Notifications.Agents
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = parsed.Message,
|
Message = parsed.Message,
|
||||||
|
Subject = "New Request",
|
||||||
Data = GetNotificationData(parsed, NotificationType.NewRequest)
|
Data = GetNotificationData(parsed, NotificationType.NewRequest)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,6 +77,7 @@ namespace Ombi.Notifications.Agents
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = parsed.Message,
|
Message = parsed.Message,
|
||||||
|
Subject = "New Issue",
|
||||||
Data = GetNotificationData(parsed, NotificationType.Issue)
|
Data = GetNotificationData(parsed, NotificationType.Issue)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -127,6 +129,7 @@ namespace Ombi.Notifications.Agents
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = parsed.Message,
|
Message = parsed.Message,
|
||||||
|
Subject = "Issue Resolved",
|
||||||
Data = GetNotificationData(parsed, NotificationType.IssueResolved)
|
Data = GetNotificationData(parsed, NotificationType.IssueResolved)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -149,6 +152,7 @@ namespace Ombi.Notifications.Agents
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = parsed.Message,
|
Message = parsed.Message,
|
||||||
|
Subject = "Request Error",
|
||||||
Data = GetNotificationData(parsed, NotificationType.ItemAddedToFaultQueue)
|
Data = GetNotificationData(parsed, NotificationType.ItemAddedToFaultQueue)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -168,6 +172,7 @@ namespace Ombi.Notifications.Agents
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = parsed.Message,
|
Message = parsed.Message,
|
||||||
|
Subject = "Request Declined",
|
||||||
Data = GetNotificationData(parsed, NotificationType.RequestDeclined)
|
Data = GetNotificationData(parsed, NotificationType.RequestDeclined)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -188,6 +193,7 @@ namespace Ombi.Notifications.Agents
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = parsed.Message,
|
Message = parsed.Message,
|
||||||
|
Subject = "Request Approved",
|
||||||
Data = GetNotificationData(parsed, NotificationType.RequestApproved)
|
Data = GetNotificationData(parsed, NotificationType.RequestApproved)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -212,6 +218,7 @@ namespace Ombi.Notifications.Agents
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = parsed.Message,
|
Message = parsed.Message,
|
||||||
|
Subject = "Request Available",
|
||||||
Data = data
|
Data = data
|
||||||
};
|
};
|
||||||
// Send to user
|
// Send to user
|
||||||
|
@ -259,6 +266,7 @@ namespace Ombi.Notifications.Agents
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = message,
|
Message = message,
|
||||||
|
Subject = "Test Notification"
|
||||||
};
|
};
|
||||||
// Send to user
|
// Send to user
|
||||||
var user = await _userManager.Users.Include(x => x.NotificationUserIds).FirstOrDefaultAsync(x => x.Id.Equals(model.UserId));
|
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)
|
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();
|
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 ChildRequests TvRequest { get; set; }
|
||||||
protected AlbumRequest AlbumRequest { get; set; }
|
protected AlbumRequest AlbumRequest { get; set; }
|
||||||
protected MovieRequests MovieRequest { 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; }
|
public abstract string NotificationName { get; }
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ namespace Ombi.Notifications
|
||||||
if (model.RequestId > 0)
|
if (model.RequestId > 0)
|
||||||
{
|
{
|
||||||
await LoadRequest(model.RequestId, model.RequestType);
|
await LoadRequest(model.RequestId, model.RequestType);
|
||||||
SubsribedUsers = GetSubscriptions(model.RequestId, model.RequestType);
|
Subscribed = GetSubscriptions(model.RequestId, model.RequestType);
|
||||||
}
|
}
|
||||||
|
|
||||||
Customization = await CustomizationSettings.GetSettingsAsync();
|
Customization = await CustomizationSettings.GetSettingsAsync();
|
||||||
|
@ -209,7 +209,6 @@ namespace Ombi.Notifications
|
||||||
if (model.RequestType == RequestType.Movie)
|
if (model.RequestType == RequestType.Movie)
|
||||||
{
|
{
|
||||||
_log.LogDebug("Notification options: {@model}, Req: {@MovieRequest}, Settings: {@Customization}", model, MovieRequest, Customization);
|
_log.LogDebug("Notification options: {@model}, Req: {@MovieRequest}, Settings: {@Customization}", model, MovieRequest, Customization);
|
||||||
|
|
||||||
curlys.Setup(model, MovieRequest, Customization, preference);
|
curlys.Setup(model, MovieRequest, Customization, preference);
|
||||||
}
|
}
|
||||||
else if (model.RequestType == RequestType.TvShow)
|
else if (model.RequestType == RequestType.TvShow)
|
||||||
|
|
|
@ -14,218 +14,156 @@ namespace Ombi.Notifications
|
||||||
{
|
{
|
||||||
public class NotificationMessageCurlys
|
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)
|
public void SetupNewsletter(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;
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Setup(OmbiUser user, CustomizationSettings s)
|
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;
|
RequestedUser = user.UserName;
|
||||||
Alias = user.UserAlias;
|
Alias = user.UserAlias;
|
||||||
UserName = user.UserName;
|
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)
|
private void LoadIssues(NotificationOptions opts)
|
||||||
{
|
{
|
||||||
var val = string.Empty;
|
IssueDescription = opts.Substitutes.TryGetValue("IssueDescription", out string val) ? val : string.Empty;
|
||||||
IssueDescription = opts.Substitutes.TryGetValue("IssueDescription", out val) ? val : string.Empty;
|
|
||||||
IssueCategory = opts.Substitutes.TryGetValue("IssueCategory", out val) ? val : string.Empty;
|
IssueCategory = opts.Substitutes.TryGetValue("IssueCategory", out val) ? val : string.Empty;
|
||||||
IssueStatus = opts.Substitutes.TryGetValue("IssueStatus", 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;
|
IssueSubject = opts.Substitutes.TryGetValue("IssueSubject", out val) ? val : string.Empty;
|
||||||
NewIssueComment = opts.Substitutes.TryGetValue("NewIssueComment", 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;
|
UserName = opts.Substitutes.TryGetValue("IssueUser", out val) ? val : string.Empty;
|
||||||
Alias = opts.Substitutes.TryGetValue("IssueUserAlias", 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)
|
private void CalculateRequestStatus(BaseRequest req)
|
||||||
|
@ -238,16 +176,19 @@ namespace Ombi.Notifications
|
||||||
RequestStatus = "Available";
|
RequestStatus = "Available";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.Denied ?? false)
|
if (req.Denied ?? false)
|
||||||
{
|
{
|
||||||
RequestStatus = "Denied";
|
RequestStatus = "Denied";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!req.Available && req.Approved)
|
if (!req.Available && req.Approved)
|
||||||
{
|
{
|
||||||
RequestStatus = "Processing Request";
|
RequestStatus = "Processing Request";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestStatus = "Pending Approval";
|
RequestStatus = "Pending Approval";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,36 +229,36 @@ namespace Ombi.Notifications
|
||||||
|
|
||||||
public Dictionary<string, string> Curlys => new Dictionary<string, string>
|
public Dictionary<string, string> Curlys => new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{nameof(RequestId), RequestId },
|
{ nameof(RequestId), RequestId },
|
||||||
{nameof(RequestedUser), RequestedUser },
|
{ nameof(RequestedUser), RequestedUser },
|
||||||
{nameof(Title), Title },
|
{ nameof(Title), Title },
|
||||||
{nameof(RequestedDate), RequestedDate },
|
{ nameof(RequestedDate), RequestedDate },
|
||||||
{nameof(Type), Type },
|
{ nameof(Type), Type },
|
||||||
{nameof(AdditionalInformation), AdditionalInformation },
|
{ nameof(AdditionalInformation), AdditionalInformation },
|
||||||
{nameof(LongDate),LongDate},
|
{ nameof(LongDate), LongDate },
|
||||||
{nameof(ShortDate),ShortDate},
|
{ nameof(ShortDate), ShortDate },
|
||||||
{nameof(LongTime),LongTime},
|
{ nameof(LongTime), LongTime },
|
||||||
{nameof(ShortTime),ShortTime},
|
{ nameof(ShortTime), ShortTime },
|
||||||
{nameof(Overview),Overview},
|
{ nameof(Overview), Overview },
|
||||||
{nameof(Year),Year},
|
{ nameof(Year), Year },
|
||||||
{nameof(EpisodesList),EpisodesList},
|
{ nameof(EpisodesList), EpisodesList },
|
||||||
{nameof(SeasonsList),SeasonsList},
|
{ nameof(SeasonsList), SeasonsList },
|
||||||
{nameof(PosterImage),PosterImage},
|
{ nameof(PosterImage), PosterImage },
|
||||||
{nameof(ApplicationName),ApplicationName},
|
{ nameof(ApplicationName), ApplicationName },
|
||||||
{nameof(ApplicationUrl),ApplicationUrl},
|
{ nameof(ApplicationUrl), ApplicationUrl },
|
||||||
{nameof(IssueDescription),IssueDescription},
|
{ nameof(IssueDescription), IssueDescription },
|
||||||
{nameof(IssueCategory),IssueCategory},
|
{ nameof(IssueCategory), IssueCategory },
|
||||||
{nameof(IssueStatus),IssueStatus},
|
{ nameof(IssueStatus), IssueStatus },
|
||||||
{nameof(IssueSubject),IssueSubject},
|
{ nameof(IssueSubject), IssueSubject },
|
||||||
{nameof(NewIssueComment),NewIssueComment},
|
{ nameof(NewIssueComment), NewIssueComment },
|
||||||
{nameof(IssueUser),IssueUser},
|
{ nameof(IssueUser), IssueUser },
|
||||||
{nameof(UserName),UserName},
|
{ nameof(UserName), UserName },
|
||||||
{nameof(Alias),Alias},
|
{ nameof(Alias), Alias },
|
||||||
{nameof(UserPreference),UserPreference},
|
{ nameof(UserPreference), UserPreference },
|
||||||
{nameof(DenyReason),DenyReason},
|
{ nameof(DenyReason), DenyReason },
|
||||||
{nameof(AvailableDate),AvailableDate},
|
{ nameof(AvailableDate), AvailableDate },
|
||||||
{nameof(RequestStatus),RequestStatus},
|
{ nameof(RequestStatus), RequestStatus },
|
||||||
{nameof(ProviderId),ProviderId},
|
{ nameof(ProviderId), ProviderId },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,6 +17,7 @@ using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
using Ombi.Store.Repository.Requests;
|
using Ombi.Store.Repository.Requests;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
|
||||||
namespace Ombi.Schedule.Tests
|
namespace Ombi.Schedule.Tests
|
||||||
{
|
{
|
||||||
|
@ -53,7 +54,7 @@ namespace Ombi.Schedule.Tests
|
||||||
ImdbId = "test"
|
ImdbId = "test"
|
||||||
};
|
};
|
||||||
_movie.Setup(x => x.GetAll()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
_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);
|
await Checker.Execute(null);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,6 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
public interface IOmbiAutomaticUpdater : IBaseJob
|
public interface IOmbiAutomaticUpdater : IBaseJob
|
||||||
{
|
{
|
||||||
string[] GetVersion();
|
string[] GetVersion();
|
||||||
Task<bool> UpdateAvailable(string branch, string currentVersion);
|
Task<bool> UpdateAvailable(string currentVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -49,10 +49,10 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
var productArray = productVersion.Split('-');
|
var productArray = productVersion.Split('-');
|
||||||
return productArray;
|
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;
|
var serverVersion = updates.UpdateVersionString;
|
||||||
return !serverVersion.Equals(currentVersion, StringComparison.CurrentCultureIgnoreCase);
|
return !serverVersion.Equals(currentVersion, StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
||||||
|
|
||||||
Logger.LogDebug(LoggingEvents.Updater, "Looking for updates now");
|
Logger.LogDebug(LoggingEvents.Updater, "Looking for updates now");
|
||||||
//TODO this fails because the branch = featureupdater when it should be feature/updater
|
//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);
|
Logger.LogDebug(LoggingEvents.Updater, "Updates: {0}", updates);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -183,13 +183,13 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
PlexServerContent item = null;
|
PlexServerContent item = null;
|
||||||
if (movie.ImdbId.HasValue())
|
if (movie.ImdbId.HasValue())
|
||||||
{
|
{
|
||||||
item = await _repo.Get(movie.ImdbId);
|
item = await _repo.Get(movie.ImdbId, ProviderType.ImdbId);
|
||||||
}
|
}
|
||||||
if (item == null)
|
if (item == null)
|
||||||
{
|
{
|
||||||
if (movie.TheMovieDbId.ToString().HasValue())
|
if (movie.TheMovieDbId.ToString().HasValue())
|
||||||
{
|
{
|
||||||
item = await _repo.Get(movie.TheMovieDbId.ToString());
|
item = await _repo.Get(movie.TheMovieDbId.ToString(), ProviderType.TheMovieDbId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item == null)
|
if (item == null)
|
||||||
|
|
|
@ -109,8 +109,8 @@ namespace Ombi.Core.Processor
|
||||||
public string UpdateVersionString { get; set; }
|
public string UpdateVersionString { get; set; }
|
||||||
public int UpdateVersion { get; set; }
|
public int UpdateVersion { get; set; }
|
||||||
public DateTime UpdateDate { get; set; }
|
public DateTime UpdateDate { get; set; }
|
||||||
|
public bool UpdateAvailable { get; set; }
|
||||||
public List<ChangeLog> ChangeLogs { get; set; }
|
public string ChangeLogs { get; set; }
|
||||||
public List<Downloads> Downloads { get; set; }
|
public List<Downloads> Downloads { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,94 +16,41 @@ namespace Ombi.Schedule.Processor
|
||||||
{
|
{
|
||||||
public class ChangeLogProcessor : IChangeLogProcessor
|
public class ChangeLogProcessor : IChangeLogProcessor
|
||||||
{
|
{
|
||||||
public ChangeLogProcessor(IApi api, IOmbiHttpClient client)
|
public ChangeLogProcessor(IApi api, IHttpClientFactory client)
|
||||||
{
|
{
|
||||||
_api = api;
|
_api = api;
|
||||||
_client = client;
|
_client = client.CreateClient("OmbiClient");
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IApi _api;
|
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 _changeLogUrl = "https://raw.githubusercontent.com/tidusjar/Ombi/{0}/CHANGELOG.md";
|
||||||
private const string AppveyorApiUrl = "https://ci.appveyor.com/api";
|
private const string AppveyorApiUrl = "https://ci.appveyor.com/api";
|
||||||
private string ChangeLogUrl(string branch) => string.Format(_changeLogUrl, branch);
|
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
|
var release = new Release
|
||||||
{
|
{
|
||||||
Version = latestRelease.InnerText,
|
|
||||||
Features = featuresList,
|
|
||||||
Fixes = fixesList,
|
|
||||||
Downloads = new List<Downloads>()
|
Downloads = new List<Downloads>()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (masterBranch)
|
await GetGitubRelease(release);
|
||||||
{
|
|
||||||
var releaseTag = latestRelease.InnerText.Substring(0, 9);
|
|
||||||
await GetGitubRelease(release, releaseTag);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Get AppVeyor
|
|
||||||
await GetAppVeyorRelease(release, branch);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return TransformUpdate(release,!masterBranch);
|
|
||||||
|
|
||||||
|
return TransformUpdate(release);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UpdateModel TransformUpdate(Release release, bool develop)
|
private UpdateModel TransformUpdate(Release release)
|
||||||
{
|
{
|
||||||
var newUpdate = new UpdateModel
|
var newUpdate = new UpdateModel
|
||||||
{
|
{
|
||||||
UpdateVersionString = develop ? release.Version : release.Version.Substring(1,8),
|
UpdateVersionString = release.Version,
|
||||||
UpdateVersion = release.Version == "(unreleased)" ? 0 : int.Parse(release.Version.Substring(1, 5).Replace(".", "")),
|
UpdateVersion = int.Parse(release.Version.Substring(1, 5).Replace(".", "")),
|
||||||
UpdateDate = DateTime.Now,
|
UpdateDate = DateTime.Now,
|
||||||
ChangeLogs = new List<ChangeLog>(),
|
ChangeLogs = release.Description,
|
||||||
Downloads = new List<Downloads>()
|
Downloads = new List<Downloads>(),
|
||||||
};
|
UpdateAvailable = release.Version != "v" + AssemblyHelper.GetRuntimeVersion()
|
||||||
|
};
|
||||||
|
|
||||||
foreach (var dl in release.Downloads)
|
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;
|
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);
|
var client = new GitHubClient(Octokit.ProductHeaderValue.Parse("OmbiV4"));
|
||||||
request.ApplicationJsonContentType();
|
|
||||||
|
|
||||||
var builds = await _api.Request<AppveyorBranchResult>(request);
|
var releases = await client.Repository.Release.GetAll("ombi-app", "ombi");
|
||||||
var jobId = builds.build.jobs.FirstOrDefault()?.jobId ?? string.Empty;
|
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)
|
foreach (var item in latest.Assets)
|
||||||
{
|
{
|
||||||
var d = new Downloads
|
var d = new Downloads
|
||||||
|
@ -192,6 +80,8 @@ namespace Ombi.Schedule.Processor
|
||||||
};
|
};
|
||||||
release.Downloads.Add(d);
|
release.Downloads.Add(d);
|
||||||
}
|
}
|
||||||
|
release.Description = Markdown.ToHtml(latest.Body);
|
||||||
|
release.Version = latest.TagName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class Release
|
public class Release
|
||||||
|
@ -199,8 +89,7 @@ namespace Ombi.Schedule.Processor
|
||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
public string CheckinVersion { get; set; }
|
public string CheckinVersion { get; set; }
|
||||||
public List<Downloads> Downloads { get; set; }
|
public List<Downloads> Downloads { get; set; }
|
||||||
public List<string> Features { get; set; }
|
public string Description { get; set; }
|
||||||
public List<string> Fixes { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Downloads
|
public class Downloads
|
||||||
|
|
|
@ -4,6 +4,6 @@ namespace Ombi.Core.Processor
|
||||||
{
|
{
|
||||||
public interface IChangeLogProcessor
|
public interface IChangeLogProcessor
|
||||||
{
|
{
|
||||||
Task<UpdateModel> Process(string branch);
|
Task<UpdateModel> Process();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,6 +20,7 @@
|
||||||
public bool AddOnly { get; set; }
|
public bool AddOnly { get; set; }
|
||||||
public bool V3 { get; set; }
|
public bool V3 { get; set; }
|
||||||
public int LanguageProfile { get; set; }
|
public int LanguageProfile { get; set; }
|
||||||
|
public int LanguageProfileAnime { get; set; }
|
||||||
public bool ScanForAvailability { get; set; }
|
public bool ScanForAvailability { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,6 +9,7 @@ namespace Ombi.Settings.Settings.Models.Notifications
|
||||||
public string WebhookUrl { get; set; }
|
public string WebhookUrl { get; set; }
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
public string Icon { get; set; }
|
public string Icon { get; set; }
|
||||||
|
public bool HideUser { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string WebHookId => SplitWebUrl(4);
|
public string WebHookId => SplitWebUrl(4);
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
public bool CollectAnalyticData { get; set; }
|
public bool CollectAnalyticData { get; set; }
|
||||||
public bool Wizard { get; set; }
|
public bool Wizard { get; set; }
|
||||||
public string ApiKey { get; set; }
|
public string ApiKey { get; set; }
|
||||||
public bool IgnoreCertificateErrors { get; set; }
|
|
||||||
public bool DoNotSendNotificationsForAutoApprove { get; set; }
|
public bool DoNotSendNotificationsForAutoApprove { get; set; }
|
||||||
public bool HideRequestsUsers { get; set; }
|
public bool HideRequestsUsers { get; set; }
|
||||||
public bool DisableHealthChecks { get; set; }
|
public bool DisableHealthChecks { get; set; }
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace Ombi.Store.Entities.Requests
|
||||||
public string ImdbId { get; set; }
|
public string ImdbId { get; set; }
|
||||||
public int? QualityOverride { get; set; }
|
public int? QualityOverride { get; set; }
|
||||||
public int? RootFolder { get; set; }
|
public int? RootFolder { get; set; }
|
||||||
|
public int? LanguageProfile { get; set; }
|
||||||
public string Overview { get; set; }
|
public string Overview { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string PosterPath { get; set; }
|
public string PosterPath { get; set; }
|
||||||
|
|
1235
src/Ombi.Store/Migrations/OmbiMySql/20210408073336_SonarrProfileOnRequest.Designer.cs
generated
Normal file
1235
src/Ombi.Store/Migrations/OmbiMySql/20210408073336_SonarrProfileOnRequest.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,23 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Migrations.OmbiMySql
|
||||||
|
{
|
||||||
|
public partial class SonarrProfileOnRequest : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "LanguageProfile",
|
||||||
|
table: "TvRequests",
|
||||||
|
type: "int",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LanguageProfile",
|
||||||
|
table: "TvRequests");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -771,6 +771,9 @@ namespace Ombi.Store.Migrations.OmbiMySql
|
||||||
b.Property<string>("ImdbId")
|
b.Property<string>("ImdbId")
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int?>("LanguageProfile")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<string>("Overview")
|
b.Property<string>("Overview")
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
|
1234
src/Ombi.Store/Migrations/OmbiSqlite/20210408073232_SonarrProfileOnRequest.Designer.cs
generated
Normal file
1234
src/Ombi.Store/Migrations/OmbiSqlite/20210408073232_SonarrProfileOnRequest.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,23 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Migrations.OmbiSqlite
|
||||||
|
{
|
||||||
|
public partial class SonarrProfileOnRequest : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "LanguageProfile",
|
||||||
|
table: "TvRequests",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LanguageProfile",
|
||||||
|
table: "TvRequests");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -770,6 +770,9 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
||||||
b.Property<string>("ImdbId")
|
b.Property<string>("ImdbId")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("LanguageProfile")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("Overview")
|
b.Property<string>("Overview")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Data.Sqlite;
|
using Microsoft.Data.Sqlite;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -28,6 +29,11 @@ namespace Ombi.Store.Repository
|
||||||
return await _db.FindAsync(key);
|
return await _db.FindAsync(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<T> Find(object key, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await _db.FindAsync(new[] { key }, cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
public IQueryable<T> GetAll()
|
public IQueryable<T> GetAll()
|
||||||
{
|
{
|
||||||
return _db.AsQueryable();
|
return _db.AsQueryable();
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Helpers;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
namespace Ombi.Store.Repository
|
namespace Ombi.Store.Repository
|
||||||
|
@ -10,7 +11,7 @@ namespace Ombi.Store.Repository
|
||||||
public interface IPlexContentRepository : IExternalRepository<PlexServerContent>
|
public interface IPlexContentRepository : IExternalRepository<PlexServerContent>
|
||||||
{
|
{
|
||||||
Task<bool> ContentExists(string providerId);
|
Task<bool> ContentExists(string providerId);
|
||||||
Task<PlexServerContent> Get(string providerId);
|
Task<PlexServerContent> Get(string providerId, ProviderType type);
|
||||||
Task<PlexServerContent> GetByKey(int key);
|
Task<PlexServerContent> GetByKey(int key);
|
||||||
Task Update(PlexServerContent existingContent);
|
Task Update(PlexServerContent existingContent);
|
||||||
IQueryable<PlexEpisode> GetAllEpisodes();
|
IQueryable<PlexEpisode> GetAllEpisodes();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Query;
|
using Microsoft.EntityFrameworkCore.Query;
|
||||||
|
@ -12,6 +13,7 @@ namespace Ombi.Store.Repository
|
||||||
public interface IRepository<T> where T : Entity
|
public interface IRepository<T> where T : Entity
|
||||||
{
|
{
|
||||||
Task<T> Find(object key);
|
Task<T> Find(object key);
|
||||||
|
Task<T> Find(object key, CancellationToken cancellationToken);
|
||||||
IQueryable<T> GetAll();
|
IQueryable<T> GetAll();
|
||||||
Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate);
|
Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate);
|
||||||
Task AddRange(IEnumerable<T> content, bool save = true);
|
Task AddRange(IEnumerable<T> content, bool save = true);
|
||||||
|
|
|
@ -31,6 +31,7 @@ using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Ombi.Helpers;
|
||||||
using Ombi.Store.Context;
|
using Ombi.Store.Context;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
@ -61,18 +62,21 @@ namespace Ombi.Store.Repository
|
||||||
return any;
|
return any;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PlexServerContent> Get(string providerId)
|
public async Task<PlexServerContent> Get(string providerId, ProviderType type)
|
||||||
{
|
{
|
||||||
var item = await Db.PlexServerContent.FirstOrDefaultAsync(x => x.ImdbId == providerId);
|
switch (type)
|
||||||
if (item == null)
|
|
||||||
{
|
{
|
||||||
item = await Db.PlexServerContent.FirstOrDefaultAsync(x => x.TheMovieDbId == providerId);
|
case ProviderType.ImdbId:
|
||||||
if (item == null)
|
return await Db.PlexServerContent.FirstOrDefaultAsync(x => x.ImdbId == providerId);
|
||||||
{
|
case ProviderType.TheMovieDbId:
|
||||||
item = await Db.PlexServerContent.FirstOrDefaultAsync(x => x.TvDbId == providerId);
|
return await Db.PlexServerContent.FirstOrDefaultAsync(x => x.TheMovieDbId == providerId);
|
||||||
}
|
case ProviderType.TvDbId:
|
||||||
|
return await Db.PlexServerContent.FirstOrDefaultAsync(x => x.TvDbId == providerId);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return item;
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PlexServerContent> GetByKey(int key)
|
public async Task<PlexServerContent> GetByKey(int key)
|
||||||
|
|
|
@ -97,6 +97,8 @@ namespace Ombi.Api.TheMovieDb.Models
|
||||||
{
|
{
|
||||||
[JsonProperty("results")]
|
[JsonProperty("results")]
|
||||||
public List<KeywordsValue> KeywordsValue { get; set; }
|
public List<KeywordsValue> KeywordsValue { get; set; }
|
||||||
|
[JsonProperty("keywords")]
|
||||||
|
private List<KeywordsValue> _movieKeywordValue { set { KeywordsValue = value; }}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class KeywordsValue
|
public class KeywordsValue
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
namespace Ombi.Api.TheMovieDb.Models
|
using Ombi.Store.Repository.Requests;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ombi.Api.TheMovieDb.Models
|
||||||
{
|
{
|
||||||
public class MovieDbSearchResult
|
public class MovieDbSearchResult
|
||||||
{
|
{
|
||||||
|
@ -16,5 +19,10 @@
|
||||||
public int VoteCount { get; set; }
|
public int VoteCount { get; set; }
|
||||||
public bool Video { get; set; }
|
public bool Video { get; set; }
|
||||||
public float VoteAverage { get; set; }
|
public float VoteAverage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mapped Property and not set from the API
|
||||||
|
/// </summary>
|
||||||
|
public List<SeasonRequests> SeasonRequests { get; set; } = new List<SeasonRequests>();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -59,6 +59,7 @@ export interface IDiscordNotifcationSettings extends INotificationSettings {
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
username: string;
|
username: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
|
hideUser: boolean;
|
||||||
notificationTemplates: INotificationTemplates[];
|
notificationTemplates: INotificationTemplates[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { IChildRequests, IMovieRequests } from ".";
|
import { IChildRequests, IMovieRequests } from ".";
|
||||||
import { ITvRequests } from "./IRequestModel";
|
import { ITvRequests } from "./IRequestModel";
|
||||||
|
import { ILanguageProfiles } from "./ISonarr";
|
||||||
|
|
||||||
export interface IRadarrRootFolder {
|
export interface IRadarrRootFolder {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -27,6 +28,9 @@ export interface IAdvancedData {
|
||||||
rootFolder: IRadarrRootFolder;
|
rootFolder: IRadarrRootFolder;
|
||||||
rootFolders: IRadarrRootFolder[];
|
rootFolders: IRadarrRootFolder[];
|
||||||
rootFolderId: number;
|
rootFolderId: number;
|
||||||
|
language: ILanguageProfiles;
|
||||||
|
languages: ILanguageProfiles[];
|
||||||
|
languageId: number;
|
||||||
movieRequest: IMovieRequests;
|
movieRequest: IMovieRequests;
|
||||||
tvRequest: ITvRequests;
|
tvRequest: ITvRequests;
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@ export interface IMovieAdvancedOptions {
|
||||||
requestId: number;
|
requestId: number;
|
||||||
qualityOverride: number;
|
qualityOverride: number;
|
||||||
rootPathOverride: number;
|
rootPathOverride: number;
|
||||||
|
languageProfile: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAlbumRequest extends IBaseRequest {
|
export interface IAlbumRequest extends IBaseRequest {
|
||||||
|
@ -110,6 +111,7 @@ export interface ITvRequests {
|
||||||
status: string;
|
status: string;
|
||||||
childRequests: IChildRequests[];
|
childRequests: IChildRequests[];
|
||||||
qualityOverride: number;
|
qualityOverride: number;
|
||||||
|
languageProfile: number;
|
||||||
background: any;
|
background: any;
|
||||||
totalSeasons: number;
|
totalSeasons: number;
|
||||||
tvDbId: number; // NO LONGER USED
|
tvDbId: number; // NO LONGER USED
|
||||||
|
@ -119,6 +121,7 @@ export interface ITvRequests {
|
||||||
// For UI display
|
// For UI display
|
||||||
qualityOverrideTitle: string;
|
qualityOverrideTitle: string;
|
||||||
rootPathOverrideTitle: string;
|
rootPathOverrideTitle: string;
|
||||||
|
languageOverrideTitle: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IChildRequests extends IBaseRequest {
|
export interface IChildRequests extends IBaseRequest {
|
||||||
|
|
|
@ -51,6 +51,7 @@ export interface ITvRequestViewModelBase extends BaseRequestOptions {
|
||||||
requestAll: boolean;
|
requestAll: boolean;
|
||||||
firstSeason: boolean;
|
firstSeason: boolean;
|
||||||
latestSeason: boolean;
|
latestSeason: boolean;
|
||||||
|
languageProfile: number | undefined;
|
||||||
seasons: ISeasonsViewModel[];
|
seasons: ISeasonsViewModel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ export interface IOmbiSettings extends ISettings {
|
||||||
collectAnalyticData: boolean;
|
collectAnalyticData: boolean;
|
||||||
wizard: boolean;
|
wizard: boolean;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
ignoreCertificateErrors: boolean;
|
|
||||||
doNotSendNotificationsForAutoApprove: boolean;
|
doNotSendNotificationsForAutoApprove: boolean;
|
||||||
hideRequestsUsers: boolean;
|
hideRequestsUsers: boolean;
|
||||||
defaultLanguageCode: string;
|
defaultLanguageCode: string;
|
||||||
|
@ -104,6 +103,7 @@ export interface ISonarrSettings extends IExternalSettings {
|
||||||
addOnly: boolean;
|
addOnly: boolean;
|
||||||
v3: boolean;
|
v3: boolean;
|
||||||
languageProfile: number;
|
languageProfile: number;
|
||||||
|
languageProfileAnime: number;
|
||||||
scanForAvailability: boolean;
|
scanForAvailability: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,3 +285,19 @@ export interface ITheMovieDbSettings extends ISettings {
|
||||||
showAdultMovies: boolean;
|
showAdultMovies: boolean;
|
||||||
excludedKeywordIds: number[];
|
excludedKeywordIds: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IUpdateModel
|
||||||
|
{
|
||||||
|
updateVersionString: string;
|
||||||
|
updateVersion: number;
|
||||||
|
updateDate: Date,
|
||||||
|
updateAvailable: boolean;
|
||||||
|
changeLogs: string;
|
||||||
|
downloads: IUpdateDonloads[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IUpdateDonloads
|
||||||
|
{
|
||||||
|
name: string;
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
|
|
@ -146,6 +146,9 @@ export class LoginComponent implements OnDestroy, OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
public oauth() {
|
public oauth() {
|
||||||
|
if (this.oAuthWindow) {
|
||||||
|
this.oAuthWindow.close();
|
||||||
|
}
|
||||||
this.oAuthWindow = window.open(window.location.toString(), "_blank", `toolbar=0,
|
this.oAuthWindow = window.open(window.location.toString(), "_blank", `toolbar=0,
|
||||||
location=0,
|
location=0,
|
||||||
status=0,
|
status=0,
|
||||||
|
@ -159,16 +162,22 @@ export class LoginComponent implements OnDestroy, OnInit {
|
||||||
this.authService.login({ usePlexOAuth: true, password: "", rememberMe: true, username: "", plexTvPin: pin }).subscribe(x => {
|
this.authService.login({ usePlexOAuth: true, password: "", rememberMe: true, username: "", plexTvPin: pin }).subscribe(x => {
|
||||||
this.oAuthWindow!.location.replace(x.url);
|
this.oAuthWindow!.location.replace(x.url);
|
||||||
|
|
||||||
this.pinTimer = setInterval(() => {
|
if (this.pinTimer) {
|
||||||
|
clearInterval(this.pinTimer);
|
||||||
|
}
|
||||||
|
|
||||||
this.oauthLoading = true;
|
this.pinTimer = setInterval(() => {
|
||||||
this.getPinResult(x.pinId);
|
if(this.oAuthWindow.closed) {
|
||||||
}, 4000);
|
this.oauthLoading = true;
|
||||||
|
this.getPinResult(x.pinId);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPinResult(pinId: number) {
|
public getPinResult(pinId: number) {
|
||||||
|
clearInterval(this.pinTimer);
|
||||||
this.authService.oAuth(pinId).subscribe(x => {
|
this.authService.oAuth(pinId).subscribe(x => {
|
||||||
if(x.access_token) {
|
if(x.access_token) {
|
||||||
this.store.save("id_token", x.access_token);
|
this.store.save("id_token", x.access_token);
|
||||||
|
@ -176,7 +185,7 @@ export class LoginComponent implements OnDestroy, OnInit {
|
||||||
if (this.authService.loggedIn()) {
|
if (this.authService.loggedIn()) {
|
||||||
this.ngOnDestroy();
|
this.ngOnDestroy();
|
||||||
|
|
||||||
if(this.oAuthWindow) {
|
if (this.oAuthWindow) {
|
||||||
this.oAuthWindow.close();
|
this.oAuthWindow.close();
|
||||||
}
|
}
|
||||||
this.oauthLoading = false;
|
this.oauthLoading = false;
|
||||||
|
@ -184,6 +193,10 @@ export class LoginComponent implements OnDestroy, OnInit {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.notify.open("Could not log you in!", "OK", {
|
||||||
|
duration: 3000
|
||||||
|
});
|
||||||
|
this.oauthLoading = false;
|
||||||
|
|
||||||
}, err => {
|
}, err => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
[type]="requestType"
|
[type]="requestType"
|
||||||
(openTrailer)="openDialog()"
|
(openTrailer)="openDialog()"
|
||||||
(onAdvancedOptions)="openAdvancedOptions()"
|
(onAdvancedOptions)="openAdvancedOptions()"
|
||||||
|
(onReProcessRequest)="reProcessRequest()"
|
||||||
>
|
>
|
||||||
</social-icons>
|
</social-icons>
|
||||||
|
|
||||||
|
|
|
@ -184,12 +184,22 @@ export class MovieDetailsComponent {
|
||||||
if (result) {
|
if (result) {
|
||||||
result.rootFolder = result.rootFolders.filter(f => f.id === +result.rootFolderId)[0];
|
result.rootFolder = result.rootFolders.filter(f => f.id === +result.rootFolderId)[0];
|
||||||
result.profile = result.profiles.filter(f => f.id === +result.profileId)[0];
|
result.profile = result.profiles.filter(f => f.id === +result.profileId)[0];
|
||||||
await this.requestService2.updateMovieAdvancedOptions({ qualityOverride: result.profileId, rootPathOverride: result.rootFolderId, requestId: this.movieRequest.id }).toPromise();
|
await this.requestService2.updateMovieAdvancedOptions({ qualityOverride: result.profileId, rootPathOverride: result.rootFolderId, languageProfile: 0, requestId: this.movieRequest.id }).toPromise();
|
||||||
this.setAdvancedOptions(result);
|
this.setAdvancedOptions(result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public reProcessRequest() {
|
||||||
|
this.requestService2.reprocessRequest(this.movieRequest.id, RequestType.movie).subscribe(result => {
|
||||||
|
if (result.result) {
|
||||||
|
this.messageService.send(result.message ? result.message : "Successfully Re-processed the request", "Ok");
|
||||||
|
} else {
|
||||||
|
this.messageService.send(result.errorMessage, "Ok");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private loadBanner() {
|
private loadBanner() {
|
||||||
this.imageService.getMovieBanner(this.theMovidDbId.toString()).subscribe(x => {
|
this.imageService.getMovieBanner(this.theMovidDbId.toString()).subscribe(x => {
|
||||||
if (!this.movie.backdropPath) {
|
if (!this.movie.backdropPath) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="rating medium-font">
|
<div class="rating medium-font">
|
||||||
<span *ngIf="movie.voteAverage"
|
<span *ngIf="movie.voteAverage"
|
||||||
matTooltip="{{'MediaDetails.Votes' | translate }} {{movie.voteCount | thousandShort: 1}}">
|
matTooltip="{{'MediaDetails.Votes' | translate }} {{movie.voteCount | thousandShort: 1}}">
|
||||||
<img class="rating-small" src="{{baseUrl}}images/tmdb-logo.svg"> {{movie.voteAverage | number:'1.0-1'}}/10
|
<img class="rating-small" src="{{baseUrl}}/images/tmdb-logo.svg"> {{movie.voteAverage | number:'1.0-1'}}/10
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="ratings?.critics_rating && ratings?.critics_score">
|
<span *ngIf="ratings?.critics_rating && ratings?.critics_score">
|
||||||
<img class="rating-small"
|
<img class="rating-small"
|
||||||
|
|
|
@ -35,5 +35,9 @@
|
||||||
<span *ngIf="type === RequestType.movie"> {{ 'MediaDetails.RadarrConfiguration' | translate}}</span>
|
<span *ngIf="type === RequestType.movie"> {{ 'MediaDetails.RadarrConfiguration' | translate}}</span>
|
||||||
<span *ngIf="type === RequestType.tvShow"> {{ 'MediaDetails.SonarrConfiguration' | translate}}</span>
|
<span *ngIf="type === RequestType.tvShow"> {{ 'MediaDetails.SonarrConfiguration' | translate}}</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button *ngIf="type === RequestType.movie" mat-menu-item (click)="reProcessRequest()">
|
||||||
|
<i class="fas fa-sync icon-spacing"></i>
|
||||||
|
<span> {{ 'MediaDetails.ReProcessRequest' | translate}}</span>
|
||||||
|
</button>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -26,6 +26,7 @@ export class SocialIconsComponent {
|
||||||
|
|
||||||
@Output() openTrailer: EventEmitter<any> = new EventEmitter();
|
@Output() openTrailer: EventEmitter<any> = new EventEmitter();
|
||||||
@Output() onAdvancedOptions: EventEmitter<any> = new EventEmitter();
|
@Output() onAdvancedOptions: EventEmitter<any> = new EventEmitter();
|
||||||
|
@Output() onReProcessRequest: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
public RequestType = RequestType;
|
public RequestType = RequestType;
|
||||||
|
|
||||||
|
@ -37,4 +38,8 @@ export class SocialIconsComponent {
|
||||||
public openAdvancedOptions() {
|
public openAdvancedOptions() {
|
||||||
this.onAdvancedOptions.emit();
|
this.onAdvancedOptions.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public reProcessRequest() {
|
||||||
|
this.onReProcessRequest.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<i class="fas fa-x7 fa-exclamation-triangle glyphicon"></i>
|
<i class="fas fa-x7 fa-exclamation-triangle glyphicon"></i>
|
||||||
<span>{{'MediaDetails.AutoApproveOptionsTvShort' | translate }}</span>
|
<span>{{'MediaDetails.AutoApproveOptionsTvShort' | translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
<mat-form-field>
|
<mat-form-field *ngIf="sonarrEnabled">
|
||||||
<mat-label>{{'MediaDetails.QualityProfilesSelect' | translate }}</mat-label>
|
<mat-label>{{'MediaDetails.QualityProfilesSelect' | translate }}</mat-label>
|
||||||
<mat-select [(value)]="data.profileId">
|
<mat-select [(value)]="data.profileId">
|
||||||
<mat-option *ngFor="let profile of sonarrProfiles" value="{{profile.id}}">{{profile.name}}</mat-option>
|
<mat-option *ngFor="let profile of sonarrProfiles" value="{{profile.id}}">{{profile.name}}</mat-option>
|
||||||
|
@ -13,13 +13,21 @@
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-content>
|
<div mat-dialog-content>
|
||||||
<mat-form-field>
|
<mat-form-field *ngIf="sonarrEnabled">
|
||||||
<mat-label>{{'MediaDetails.RootFolderSelect' | translate }}</mat-label>
|
<mat-label>{{'MediaDetails.RootFolderSelect' | translate }}</mat-label>
|
||||||
<mat-select [(value)]="data.rootFolderId">
|
<mat-select [(value)]="data.rootFolderId">
|
||||||
<mat-option *ngFor="let profile of sonarrRootFolders" value="{{profile.id}}">{{profile.path}}</mat-option>
|
<mat-option *ngFor="let profile of sonarrRootFolders" value="{{profile.id}}">{{profile.path}}</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<mat-form-field *ngIf="sonarrEnabled">
|
||||||
|
<mat-label>{{'MediaDetails.LanguageProfileSelect' | translate }}</mat-label>
|
||||||
|
<mat-select [(value)]="data.languageId">
|
||||||
|
<mat-option *ngFor="let profile of sonarrLanguageProfiles" value="{{profile.id}}">{{profile.name}}</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
<div mat-dialog-actions>
|
<div mat-dialog-actions>
|
||||||
<button mat-raised-button [mat-dialog-close]="" color="warn"><i class="fas fa-times"></i> {{ 'Common.Cancel' | translate }}</button>
|
<button mat-raised-button [mat-dialog-close]="" color="warn"><i class="fas fa-times"></i> {{ 'Common.Cancel' | translate }}</button>
|
||||||
<button mat-raised-button [mat-dialog-close]="data" color="accent" cdkFocusInitial><i class="fas fa-plus"></i> {{ 'Common.Submit' | translate }}</button>
|
<button mat-raised-button [mat-dialog-close]="data" color="accent" cdkFocusInitial><i class="fas fa-plus"></i> {{ 'Common.Submit' | translate }}</button>
|
||||||
|
|
|
@ -1,55 +1,92 @@
|
||||||
import { Component, Inject, OnInit } from "@angular/core";
|
import { Component, Inject, OnInit } from "@angular/core";
|
||||||
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
|
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
|
||||||
import { IAdvancedData, ISonarrProfile, ISonarrRootFolder } from "../../../../../interfaces";
|
import {
|
||||||
import { SonarrService } from "../../../../../services";
|
IAdvancedData,
|
||||||
|
ILanguageProfiles,
|
||||||
|
ISonarrProfile,
|
||||||
|
ISonarrRootFolder,
|
||||||
|
ISonarrSettings,
|
||||||
|
} from "../../../../../interfaces";
|
||||||
|
import { SettingsService, SonarrService } from "../../../../../services";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: "./tv-advanced-options.component.html",
|
templateUrl: "./tv-advanced-options.component.html",
|
||||||
selector: "tv-advanced-options",
|
selector: "tv-advanced-options",
|
||||||
})
|
})
|
||||||
export class TvAdvancedOptionsComponent implements OnInit {
|
export class TvAdvancedOptionsComponent implements OnInit {
|
||||||
|
public sonarrProfiles: ISonarrProfile[];
|
||||||
|
public sonarrRootFolders: ISonarrRootFolder[];
|
||||||
|
public sonarrLanguageProfiles: ILanguageProfiles[];
|
||||||
|
public sonarrEnabled: boolean;
|
||||||
|
|
||||||
public sonarrProfiles: ISonarrProfile[];
|
constructor(
|
||||||
public sonarrRootFolders: ISonarrRootFolder[];
|
public dialogRef: MatDialogRef<TvAdvancedOptionsComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: IAdvancedData,
|
||||||
|
private sonarrService: SonarrService,
|
||||||
|
private settingsService: SettingsService
|
||||||
|
) {}
|
||||||
|
|
||||||
constructor(public dialogRef: MatDialogRef<TvAdvancedOptionsComponent>, @Inject(MAT_DIALOG_DATA) public data: IAdvancedData,
|
public async ngOnInit() {
|
||||||
private sonarrService: SonarrService
|
this.settingsService.getSonarr().subscribe((settings: ISonarrSettings) => {
|
||||||
) {
|
if (!settings.enabled) {
|
||||||
|
this.sonarrEnabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sonarrEnabled = true;
|
||||||
|
this.sonarrService.getQualityProfilesWithoutSettings().subscribe((c) => {
|
||||||
|
this.sonarrProfiles = c;
|
||||||
|
this.data.profiles = c;
|
||||||
|
this.setQualityOverrides();
|
||||||
|
});
|
||||||
|
this.sonarrService.getRootFoldersWithoutSettings().subscribe((c) => {
|
||||||
|
this.sonarrRootFolders = c;
|
||||||
|
this.data.rootFolders = c;
|
||||||
|
this.setRootFolderOverrides();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (settings.v3) {
|
||||||
|
this.sonarrService
|
||||||
|
.getV3LanguageProfiles(settings)
|
||||||
|
.subscribe((profiles: ILanguageProfiles[]) => {
|
||||||
|
this.sonarrLanguageProfiles = profiles;
|
||||||
|
this.data.languages = profiles;
|
||||||
|
this.setLanguageOverride();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private setQualityOverrides(): void {
|
||||||
|
if (this.sonarrProfiles) {
|
||||||
|
const profile = this.sonarrProfiles.filter((p) => {
|
||||||
|
return p.id === this.data.tvRequest.qualityOverride;
|
||||||
|
});
|
||||||
|
if (profile.length > 0) {
|
||||||
|
this.data.tvRequest.qualityOverrideTitle = profile[0].name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setRootFolderOverrides(): void {
|
||||||
public async ngOnInit() {
|
if (this.sonarrRootFolders) {
|
||||||
this.sonarrService.getQualityProfilesWithoutSettings().subscribe(c => {
|
const path = this.sonarrRootFolders.filter((folder) => {
|
||||||
this.sonarrProfiles = c;
|
return folder.id === this.data.tvRequest.rootFolder;
|
||||||
this.data.profiles = c;
|
});
|
||||||
this.setQualityOverrides();
|
if (path.length > 0) {
|
||||||
});
|
this.data.tvRequest.rootPathOverrideTitle = path[0].path;
|
||||||
this.sonarrService.getRootFoldersWithoutSettings().subscribe(c => {
|
}
|
||||||
this.sonarrRootFolders = c;
|
|
||||||
this.data.rootFolders = c;
|
|
||||||
this.setRootFolderOverrides();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private setQualityOverrides(): void {
|
private setLanguageOverride(): void {
|
||||||
if (this.sonarrProfiles) {
|
if (this.sonarrLanguageProfiles) {
|
||||||
const profile = this.sonarrProfiles.filter((p) => {
|
const profile = this.sonarrLanguageProfiles.filter((p) => {
|
||||||
return p.id === this.data.tvRequest.qualityOverride;
|
return p.id === this.data.tvRequest.languageProfile;
|
||||||
});
|
});
|
||||||
if (profile.length > 0) {
|
if (profile.length > 0) {
|
||||||
this.data.movieRequest.qualityOverrideTitle = profile[0].name;
|
this.data.tvRequest.languageOverrideTitle = profile[0].name;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private setRootFolderOverrides(): void {
|
|
||||||
if (this.sonarrRootFolders) {
|
|
||||||
const path = this.sonarrRootFolders.filter((folder) => {
|
|
||||||
return folder.id === this.data.tvRequest.rootFolder;
|
|
||||||
});
|
|
||||||
if (path.length > 0) {
|
|
||||||
this.data.movieRequest.rootPathOverrideTitle = path[0].path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ export class TvRequestGridComponent {
|
||||||
viewModel.requestOnBehalf = result.username?.id;
|
viewModel.requestOnBehalf = result.username?.id;
|
||||||
viewModel.qualityPathOverride = result?.sonarrPathId;
|
viewModel.qualityPathOverride = result?.sonarrPathId;
|
||||||
viewModel.rootFolderOverride = result?.sonarrFolderId;
|
viewModel.rootFolderOverride = result?.sonarrFolderId;
|
||||||
|
viewModel.languageProfile = result?.sonarrLanguageId;
|
||||||
|
|
||||||
const requestResult = await this.requestServiceV2.requestTv(viewModel).toPromise();
|
const requestResult = await this.requestServiceV2.requestTv(viewModel).toPromise();
|
||||||
this.postRequest(requestResult);
|
this.postRequest(requestResult);
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
<button *ngIf="request.available" mat-raised-button color="warn" (click)="changeAvailability(request, false);">{{ 'Requests.MarkUnavailable' | translate }}</button>
|
<button *ngIf="request.available" mat-raised-button color="warn" (click)="changeAvailability(request, false);">{{ 'Requests.MarkUnavailable' | translate }}</button>
|
||||||
<button *ngIf="!request.denied" mat-raised-button color="danger" (click)="deny(request);">{{ 'Requests.Deny' | translate }}</button>
|
<button *ngIf="!request.denied" mat-raised-button color="danger" (click)="deny(request);">{{ 'Requests.Deny' | translate }}</button>
|
||||||
<button mat-raised-button color="danger" (click)="delete(request);">{{ 'Requests.RequestPanel.Delete' | translate }}</button>
|
<button mat-raised-button color="danger" (click)="delete(request);">{{ 'Requests.RequestPanel.Delete' | translate }}</button>
|
||||||
|
<button mat-raised-button color="accent" (click)="reProcessRequest(request);">{{ 'MediaDetails.ReProcessRequest' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { RequestService } from "../../../../../services/request.service";
|
||||||
import { MessageService } from "../../../../../services";
|
import { MessageService } from "../../../../../services";
|
||||||
import { MatDialog } from "@angular/material/dialog";
|
import { MatDialog } from "@angular/material/dialog";
|
||||||
import { DenyDialogComponent } from "../../../shared/deny-dialog/deny-dialog.component";
|
import { DenyDialogComponent } from "../../../shared/deny-dialog/deny-dialog.component";
|
||||||
|
import { RequestServiceV2 } from "../../../../../services/requestV2.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: "./tv-requests-panel.component.html",
|
templateUrl: "./tv-requests-panel.component.html",
|
||||||
|
@ -16,7 +17,9 @@ export class TvRequestsPanelComponent {
|
||||||
|
|
||||||
public displayedColumns: string[] = ['number', 'title', 'airDate', 'status'];
|
public displayedColumns: string[] = ['number', 'title', 'airDate', 'status'];
|
||||||
|
|
||||||
constructor(private requestService: RequestService, private messageService: MessageService,
|
constructor(private requestService: RequestService,
|
||||||
|
private requestService2: RequestServiceV2,
|
||||||
|
private messageService: MessageService,
|
||||||
public dialog: MatDialog) {
|
public dialog: MatDialog) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -93,4 +96,14 @@ export class TvRequestsPanelComponent {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public reProcessRequest(request: IChildRequests) {
|
||||||
|
this.requestService2.reprocessRequest(request.id, RequestType.tvShow).subscribe(result => {
|
||||||
|
if (result.result) {
|
||||||
|
this.messageService.send(result.message ? result.message : "Successfully Re-processed the request", "Ok");
|
||||||
|
} else {
|
||||||
|
this.messageService.send(result.errorMessage, "Ok");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,8 @@ export class TvDetailsComponent implements OnInit {
|
||||||
// get the name and ids
|
// get the name and ids
|
||||||
result.rootFolder = result.rootFolders.filter(f => f.id === +result.rootFolderId)[0];
|
result.rootFolder = result.rootFolders.filter(f => f.id === +result.rootFolderId)[0];
|
||||||
result.profile = result.profiles.filter(f => f.id === +result.profileId)[0];
|
result.profile = result.profiles.filter(f => f.id === +result.profileId)[0];
|
||||||
await this.requestService2.updateTvAdvancedOptions({ qualityOverride: result.profileId, rootPathOverride: result.rootFolderId, requestId: this.showRequest.id }).toPromise();
|
result.language = result.languages.filter(x => x.id === +result.langaugeId)[0];
|
||||||
|
await this.requestService2.updateTvAdvancedOptions({ qualityOverride: result.profileId, rootPathOverride: result.rootFolderId, languageProfile: result.languageId, requestId: this.showRequest.id }).toPromise();
|
||||||
this.setAdvancedOptions(result);
|
this.setAdvancedOptions(result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -117,15 +118,20 @@ export class TvDetailsComponent implements OnInit {
|
||||||
if (data.profileId) {
|
if (data.profileId) {
|
||||||
this.showRequest.rootPathOverrideTitle = data.rootFolders.filter(x => x.id == data.rootFolderId)[0].path;
|
this.showRequest.rootPathOverrideTitle = data.rootFolders.filter(x => x.id == data.rootFolderId)[0].path;
|
||||||
}
|
}
|
||||||
|
if (data.languageId) {
|
||||||
|
this.showRequest.languageOverrideTitle = data.languages.filter(x => x.id == data.languageId)[0].name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadAdvancedInfo() {
|
private loadAdvancedInfo() {
|
||||||
const profile = this.sonarrService.getQualityProfilesWithoutSettings();
|
const profile = this.sonarrService.getQualityProfilesWithoutSettings();
|
||||||
const folders = this.sonarrService.getRootFoldersWithoutSettings();
|
const folders = this.sonarrService.getRootFoldersWithoutSettings();
|
||||||
|
const languages = this.sonarrService.getV3LanguageProfilesWithoutSettings();
|
||||||
|
|
||||||
forkJoin([profile, folders]).subscribe(x => {
|
forkJoin([profile, folders, languages]).subscribe(x => {
|
||||||
const sonarrProfiles = x[0];
|
const sonarrProfiles = x[0];
|
||||||
const sonarrRootFolders = x[1];
|
const sonarrRootFolders = x[1];
|
||||||
|
const languageProfiles = x[2];
|
||||||
|
|
||||||
const profile = sonarrProfiles.filter((p) => {
|
const profile = sonarrProfiles.filter((p) => {
|
||||||
return p.id === this.showRequest.qualityOverride;
|
return p.id === this.showRequest.qualityOverride;
|
||||||
|
@ -141,6 +147,13 @@ export class TvDetailsComponent implements OnInit {
|
||||||
this.showRequest.rootPathOverrideTitle = path[0].path;
|
this.showRequest.rootPathOverrideTitle = path[0].path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lang = languageProfiles.filter((folder) => {
|
||||||
|
return folder.id === this.showRequest.languageProfile;
|
||||||
|
});
|
||||||
|
if (lang.length > 0) {
|
||||||
|
this.showRequest.languageOverrideTitle = lang[0].name;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
<mat-toolbar class="application-name" id="nav-applicationName">{{applicationName}}</mat-toolbar>
|
<mat-toolbar class="application-name" id="nav-applicationName">{{applicationName}}</mat-toolbar>
|
||||||
|
|
||||||
<mat-nav-list>
|
<mat-nav-list>
|
||||||
<span *ngFor="let nav of navItems">
|
<span mat-list-item *ngFor="let nav of navItems">
|
||||||
|
|
||||||
<div class="menu-spacing" *ngIf="(nav.requiresAdmin && isAdmin || !nav.requiresAdmin) && nav.enabled">
|
<div class="menu-spacing mat-ripple" mat-ripple *ngIf="(nav.requiresAdmin && isAdmin || !nav.requiresAdmin) && nav.enabled">
|
||||||
|
|
||||||
|
|
||||||
<a id="{{nav.id}}" *ngIf="nav.externalLink" mat-list-item [href]="nav.link" target="_blank"
|
<a [disableRipple]="true" mat-list-item id="{{nav.id}}" *ngIf="nav.externalLink" [href]="nav.link" target="_blank"
|
||||||
matTooltip="{{nav.toolTipMessage | translate}}" matTooltipPosition="right"
|
matTooltip="{{nav.toolTipMessage | translate}}" matTooltipPosition="right"
|
||||||
[routerLinkActive]="'active-list-item'">
|
[routerLinkActive]="'active-list-item'">
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
style="padding-left: 5px; padding-right: 5px;" aria-hidden="true"></i>
|
style="padding-left: 5px; padding-right: 5px;" aria-hidden="true"></i>
|
||||||
{{nav.name | translate}}
|
{{nav.name | translate}}
|
||||||
</a>
|
</a>
|
||||||
<a id="{{nav.id}}" *ngIf="!nav.externalLink" mat-list-item [routerLink]="nav.link" [style]="nav.color"
|
<a [disableRipple]="true" mat-list-item id="{{nav.id}}" *ngIf="!nav.externalLink" [routerLink]="nav.link" [style]="nav.color"
|
||||||
[routerLinkActive]="'active-list-item'">
|
[routerLinkActive]="'active-list-item'">
|
||||||
|
|
||||||
<i class="fa-lg {{nav.icon}} icon-spacing"></i>
|
<i class="fa-lg {{nav.icon}} icon-spacing"></i>
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<a class="menu-spacing" id="nav-logout" mat-list-item [routerLinkActive]="'active-list-item'"
|
<a mat-list-item [disableRipple]="true" class="menu-spacing" id="nav-logout" [routerLinkActive]="'active-list-item'"
|
||||||
aria-label="Toggle sidenav" (click)="logOut();">
|
aria-label="Toggle sidenav" (click)="logOut();">
|
||||||
<i class="fa-lg fas fa-sign-out-alt icon-spacing"></i>
|
<i class="fa-lg fas fa-sign-out-alt icon-spacing"></i>
|
||||||
{{ 'NavigationBar.Logout' | translate }}
|
{{ 'NavigationBar.Logout' | translate }}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<form [formGroup]='searchForm'>
|
<form [formGroup]='searchForm'>
|
||||||
<mat-form-field floatLabel="never" style="width: 100%;">
|
<mat-form-field floatLabel="never" style="width: 100%;">
|
||||||
<input id="nav-search" matInput placeholder="{{'NavigationBar.Search' | translate}}" formControlName='input'>
|
<input id="nav-search" autofocus="autofocus" matInput placeholder="{{'NavigationBar.Search' | translate}}" formControlName='input'>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
|
@ -32,6 +32,10 @@ export class SonarrService extends ServiceHelpers {
|
||||||
return this.http.post<ILanguageProfiles[]>(`${this.url}/v3/languageprofiles/`, JSON.stringify(settings), {headers: this.headers});
|
return this.http.post<ILanguageProfiles[]>(`${this.url}/v3/languageprofiles/`, JSON.stringify(settings), {headers: this.headers});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getV3LanguageProfilesWithoutSettings(): Observable<ILanguageProfiles[]> {
|
||||||
|
return this.http.get<ILanguageProfiles[]>(`${this.url}/v3/languageprofiles/`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
|
||||||
public isEnabled(): Promise<boolean> {
|
public isEnabled(): Promise<boolean> {
|
||||||
return this.http.get<boolean>(`${this.url}/enabled/`, { headers: this.headers }).toPromise();
|
return this.http.get<boolean>(`${this.url}/enabled/`, { headers: this.headers }).toPromise();
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,5 +187,4 @@ export class RequestService extends ServiceHelpers {
|
||||||
public removeAlbumRequest(request: number): any {
|
public removeAlbumRequest(request: number): any {
|
||||||
return this.http.delete(`${this.url}music/${request}`, {headers: this.headers});
|
return this.http.delete(`${this.url}music/${request}`, {headers: this.headers});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Injectable, Inject } from "@angular/core";
|
||||||
import { HttpClient } from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import { ServiceHelpers } from "./service.helpers";
|
import { ServiceHelpers } from "./service.helpers";
|
||||||
import { IRequestsViewModel, IMovieRequests, IChildRequests, IMovieAdvancedOptions as IMediaAdvancedOptions, IRequestEngineResult, IAlbumRequest, ITvRequestViewModelV2 } from "../interfaces";
|
import { IRequestsViewModel, IMovieRequests, IChildRequests, IMovieAdvancedOptions as IMediaAdvancedOptions, IRequestEngineResult, IAlbumRequest, ITvRequestViewModelV2, RequestType } from "../interfaces";
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -92,4 +92,8 @@ export class RequestServiceV2 extends ServiceHelpers {
|
||||||
public requestTv(tv: ITvRequestViewModelV2): Observable<IRequestEngineResult> {
|
public requestTv(tv: ITvRequestViewModelV2): Observable<IRequestEngineResult> {
|
||||||
return this.http.post<IRequestEngineResult>(`${this.url}TV/`, JSON.stringify(tv), {headers: this.headers});
|
return this.http.post<IRequestEngineResult>(`${this.url}TV/`, JSON.stringify(tv), {headers: this.headers});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public reprocessRequest(requestId: number, type: RequestType): Observable<IRequestEngineResult> {
|
||||||
|
return this.http.post<IRequestEngineResult>(`${this.url}reprocess/${type}/${requestId}`, undefined, { headers: this.headers });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
18
src/Ombi/ClientApp/src/app/services/update.service.ts
Normal file
18
src/Ombi/ClientApp/src/app/services/update.service.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { PlatformLocation, APP_BASE_HREF } from "@angular/common";
|
||||||
|
import { Injectable, Inject } from "@angular/core";
|
||||||
|
|
||||||
|
import { HttpClient } from "@angular/common/http";
|
||||||
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
|
import { ServiceHelpers } from "./service.helpers";
|
||||||
|
import { IUpdateModel } from "../interfaces";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UpdateService extends ServiceHelpers {
|
||||||
|
constructor(http: HttpClient, @Inject(APP_BASE_HREF) href:string) {
|
||||||
|
super(http, "/api/v1/Update/", href);
|
||||||
|
}
|
||||||
|
public checkForUpdate(): Observable<IUpdateModel> {
|
||||||
|
return this.http.get<IUpdateModel>(`${this.url}`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,8 +13,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="mat-row">
|
<div class="mat-row">
|
||||||
<div class="mat-cell">Version</div>
|
<div class="mat-cell">Version</div>
|
||||||
<div class="mat-cell">{{about.version}} <a [routerLink]="['/Settings/Update']" *ngIf="newUpdate"
|
<div class="mat-cell">{{about.version}} <a (click)="openUpdate()" *ngIf="newUpdate"
|
||||||
style="color:#df691a"><b>(New Update Available)</b></a></div>
|
style="color:#df691a; text-decoration: underline; cursor: pointer;"><b><i class="fas fa-code-branch"></i> (New Update Available)</b></a>
|
||||||
|
<span *ngIf="!newUpdate"> <i class="far fa-thumbs-up" matTooltip="Nice work bro! Latest version FTW!"></i></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="mat-row">
|
<!-- <div class="mat-row">
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { IAbout } from "../../interfaces/ISettings";
|
import { IAbout, IUpdateModel } from "../../interfaces/ISettings";
|
||||||
import { JobService, SettingsService, HubService, SystemService } from "../../services";
|
import { SettingsService, HubService, SystemService } from "../../services";
|
||||||
import { IConnectedUser } from "../../interfaces";
|
import { IConnectedUser } from "../../interfaces";
|
||||||
|
import { UpdateService } from "../../services/update.service";
|
||||||
|
import { MatDialog } from "@angular/material/dialog";
|
||||||
|
import { UpdateDialogComponent } from "./update-dialog.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: "./about.component.html",
|
templateUrl: "./about.component.html",
|
||||||
|
@ -14,22 +17,29 @@ export class AboutComponent implements OnInit {
|
||||||
public connectedUsers: IConnectedUser[];
|
public connectedUsers: IConnectedUser[];
|
||||||
public newsHtml: string;
|
public newsHtml: string;
|
||||||
|
|
||||||
|
private update: IUpdateModel;
|
||||||
|
|
||||||
constructor(private readonly settingsService: SettingsService,
|
constructor(private readonly settingsService: SettingsService,
|
||||||
private readonly jobService: JobService,
|
private readonly jobService: UpdateService,
|
||||||
private readonly hubService: HubService,
|
private readonly hubService: HubService,
|
||||||
private readonly systemService: SystemService) { }
|
private readonly systemService: SystemService,
|
||||||
|
private readonly dialog: MatDialog) { }
|
||||||
|
|
||||||
public async ngOnInit() {
|
public async ngOnInit() {
|
||||||
this.settingsService.about().subscribe(x => this.about = x);
|
this.settingsService.about().subscribe(x => this.about = x);
|
||||||
this.newsHtml = await this.systemService.getNews().toPromise();
|
this.newsHtml = await this.systemService.getNews().toPromise();
|
||||||
|
|
||||||
// TODO
|
this.jobService.checkForUpdate().subscribe(x => {
|
||||||
// this.jobService.getCachedUpdate().subscribe(x => {
|
this.update = x;
|
||||||
// if (x === true) {
|
if (x.updateAvailable) {
|
||||||
// // this.newUpdate = true; // TODO
|
this.newUpdate = true;
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
|
|
||||||
this.connectedUsers = await this.hubService.getConnectedUsers();
|
this.connectedUsers = await this.hubService.getConnectedUsers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public openUpdate() {
|
||||||
|
this.dialog.open(UpdateDialogComponent, { width: "700px", data: this.update, panelClass: 'modal-panel' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
|
||||||
|
<h1 mat-dialog-title><i class="fas fa-code-branch"></i> Latest Version: {{data.updateVersionString}}</h1>
|
||||||
|
<mat-dialog-content>
|
||||||
|
<div [innerHTML]="data.changeLogs">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="mat-table">
|
||||||
|
<div class="mat-header-row">
|
||||||
|
<div class="mat-header-cell">Binary</div>
|
||||||
|
<div class="mat-header-cell">Download</div></div>
|
||||||
|
<div *ngFor="let d of data.downloads" class="mat-row" >
|
||||||
|
<div class="mat-cell">{{d.name}}</div>
|
||||||
|
<div class="mat-cell"><a href="{{d.url}}">Download</a></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<small>Updated at {{data.updateDate | date}}</small>
|
||||||
|
</mat-dialog-content>
|
||||||
|
|
||||||
|
|
||||||
|
<div mat-dialog-actions class="right-buttons">
|
||||||
|
<button mat-raised-button id="cancelButton" [mat-dialog-close]="" color="warn"><i class="fas fa-times"></i> Close</button>
|
||||||
|
</div>
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
.mat-table {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-row,
|
||||||
|
.mat-header-row {
|
||||||
|
display: flex;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 48px;
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-cell,
|
||||||
|
.mat-header-cell {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-middle-container{
|
||||||
|
margin: auto;
|
||||||
|
width: 85%;
|
||||||
|
margin-top:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host ::ng-deep strong {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #007bff;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.25em 0.4em;
|
||||||
|
font-size: 75%;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: baseline;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
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