mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-19 21:03:17 -07:00
commit
2e8736de46
122 changed files with 4120 additions and 564 deletions
38
Ombi.Api.Interfaces/IDiscordApi.cs
Normal file
38
Ombi.Api.Interfaces/IDiscordApi.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: IDiscordApi.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.Threading.Tasks;
|
||||||
|
using Ombi.Api.Models.Notifications;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Interfaces
|
||||||
|
{
|
||||||
|
public interface IDiscordApi
|
||||||
|
{
|
||||||
|
void SendMessage(string message, string webhookId, string webhookToken, string username = null);
|
||||||
|
Task SendMessageAsync(string message, string webhookId, string webhookToken, string username = null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,6 @@ namespace Ombi.Api.Interfaces
|
||||||
{
|
{
|
||||||
public interface INetflixApi
|
public interface INetflixApi
|
||||||
{
|
{
|
||||||
NetflixMovieResult GetMovies(string movieName, string year = null);
|
NetflixMovieResult CheckNetflix(string title, string year = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
15
Ombi.Api.Interfaces/IRadarrApi.cs
Normal file
15
Ombi.Api.Interfaces/IRadarrApi.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Api.Models.Radarr;
|
||||||
|
using Ombi.Api.Models.Sonarr;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Interfaces
|
||||||
|
{
|
||||||
|
public interface IRadarrApi
|
||||||
|
{
|
||||||
|
RadarrAddMovie AddMovie(int tmdbId, string title, int year, int qualityId, string rootPath, string apiKey, Uri baseUrl, bool searchNow = false);
|
||||||
|
List<RadarrMovieResponse> GetMovies(string apiKey, Uri baseUrl);
|
||||||
|
List<SonarrProfile> GetProfiles(string apiKey, Uri baseUrl);
|
||||||
|
SystemStatus SystemStatus(string apiKey, Uri baseUrl);
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,10 +40,11 @@ namespace Ombi.Api.Interfaces
|
||||||
bool searchForMissingEpisodes = false);
|
bool searchForMissingEpisodes = false);
|
||||||
|
|
||||||
SonarrAddSeries AddSeriesNew(int tvdbId, string title, int qualityId, bool seasonFolders, string rootPath,
|
SonarrAddSeries AddSeriesNew(int tvdbId, string title, int qualityId, bool seasonFolders, string rootPath,
|
||||||
int[] seasons, string apiKey, Uri baseUrl, bool monitor = true,
|
int[] seasons, string apiKey, Uri baseUrl, bool monitor = true,
|
||||||
bool searchForMissingEpisodes = false);
|
bool searchForMissingEpisodes = false);
|
||||||
|
|
||||||
SystemStatus SystemStatus(string apiKey, Uri baseUrl);
|
SystemStatus SystemStatus(string apiKey, Uri baseUrl);
|
||||||
|
List<SonarrRootFolder> GetRootFolders(string apiKey, Uri baseUrl);
|
||||||
|
|
||||||
List<Series> GetSeries(string apiKey, Uri baseUrl);
|
List<Series> GetSeries(string apiKey, Uri baseUrl);
|
||||||
Series GetSeries(string seriesId, string apiKey, Uri baseUrl);
|
Series GetSeries(string seriesId, string apiKey, Uri baseUrl);
|
||||||
|
|
16
Ombi.Api.Interfaces/ITraktApi.cs
Normal file
16
Ombi.Api.Interfaces/ITraktApi.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TraktApiSharp.Enums;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows.Common;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Interfaces
|
||||||
|
{
|
||||||
|
public interface ITraktApi
|
||||||
|
{
|
||||||
|
Task<IEnumerable<TraktMostAnticipatedShow>> GetAnticipatedShows(int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
|
Task<IEnumerable<TraktMostWatchedShow>> GetMostWatchesShows(TraktTimePeriod period = null, int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
|
Task<IEnumerable<TraktShow>> GetPopularShows(int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
|
Task<IEnumerable<TraktTrendingShow>> GetTrendingShows(int? page = default(int?), int? limitPerPage = default(int?));
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,10 @@
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
|
<HintPath>..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
@ -43,19 +47,26 @@
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="TraktApiSharp, Version=0.8.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\TraktApiSharp.0.8.0\lib\portable-net45+netcore45+wpa81\TraktApiSharp.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="IApiRequest.cs" />
|
<Compile Include="IApiRequest.cs" />
|
||||||
<Compile Include="ICouchPotatoApi.cs" />
|
<Compile Include="ICouchPotatoApi.cs" />
|
||||||
|
<Compile Include="IDiscordApi.cs" />
|
||||||
<Compile Include="IHeadphonesApi.cs" />
|
<Compile Include="IHeadphonesApi.cs" />
|
||||||
<Compile Include="IMusicBrainzApi.cs" />
|
<Compile Include="IMusicBrainzApi.cs" />
|
||||||
<Compile Include="INetflixApi.cs" />
|
<Compile Include="INetflixApi.cs" />
|
||||||
<Compile Include="IPlexApi.cs" />
|
<Compile Include="IPlexApi.cs" />
|
||||||
<Compile Include="IPushbulletApi.cs" />
|
<Compile Include="IPushbulletApi.cs" />
|
||||||
|
<Compile Include="IRadarrApi.cs" />
|
||||||
<Compile Include="ISlackApi.cs" />
|
<Compile Include="ISlackApi.cs" />
|
||||||
<Compile Include="IPushoverApi.cs" />
|
<Compile Include="IPushoverApi.cs" />
|
||||||
<Compile Include="ISickRageApi.cs" />
|
<Compile Include="ISickRageApi.cs" />
|
||||||
<Compile Include="ISonarrApi.cs" />
|
<Compile Include="ISonarrApi.cs" />
|
||||||
|
<Compile Include="ITraktApi.cs" />
|
||||||
<Compile Include="IWatcherApi.cs" />
|
<Compile Include="IWatcherApi.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
|
||||||
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
||||||
|
<package id="TraktApiSharp" version="0.8.0" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
104
Ombi.Api.Models/Movie/TmdbMovieDetails.cs
Normal file
104
Ombi.Api.Models/Movie/TmdbMovieDetails.cs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: TmdbMovieDetails.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.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Models.Movie
|
||||||
|
{
|
||||||
|
|
||||||
|
public class Genre
|
||||||
|
{
|
||||||
|
public int id { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProductionCompany
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProductionCountry
|
||||||
|
{
|
||||||
|
public string iso_3166_1 { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpokenLanguage
|
||||||
|
{
|
||||||
|
public string iso_639_1 { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Result
|
||||||
|
{
|
||||||
|
public string id { get; set; }
|
||||||
|
public string iso_639_1 { get; set; }
|
||||||
|
public string iso_3166_1 { get; set; }
|
||||||
|
public string key { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public string site { get; set; }
|
||||||
|
public int size { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Videos
|
||||||
|
{
|
||||||
|
public List<Result> results { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TmdbMovieDetails
|
||||||
|
{
|
||||||
|
public bool adult { get; set; }
|
||||||
|
public string backdrop_path { get; set; }
|
||||||
|
public object belongs_to_collection { get; set; }
|
||||||
|
public int budget { get; set; }
|
||||||
|
public List<Genre> genres { get; set; }
|
||||||
|
public string homepage { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
public string imdb_id { get; set; }
|
||||||
|
public string original_language { get; set; }
|
||||||
|
public string original_title { get; set; }
|
||||||
|
public string overview { get; set; }
|
||||||
|
public double popularity { get; set; }
|
||||||
|
public string poster_path { get; set; }
|
||||||
|
public List<ProductionCompany> production_companies { get; set; }
|
||||||
|
public List<ProductionCountry> production_countries { get; set; }
|
||||||
|
public string release_date { get; set; }
|
||||||
|
public int revenue { get; set; }
|
||||||
|
public int runtime { get; set; }
|
||||||
|
public List<SpokenLanguage> spoken_languages { get; set; }
|
||||||
|
public string status { get; set; }
|
||||||
|
public string tagline { get; set; }
|
||||||
|
public string title { get; set; }
|
||||||
|
public bool video { get; set; }
|
||||||
|
public double vote_average { get; set; }
|
||||||
|
public int vote_count { get; set; }
|
||||||
|
public Videos videos { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -58,5 +58,12 @@ namespace Ombi.Api.Models.Netflix
|
||||||
public string Mediatype { get; set; }
|
public string Mediatype { get; set; }
|
||||||
[JsonProperty(PropertyName = "runtime")]
|
[JsonProperty(PropertyName = "runtime")]
|
||||||
public string Runtime { get; set; }
|
public string Runtime { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
// For errors
|
||||||
|
[JsonProperty(PropertyName = "errorcode")]
|
||||||
|
public int ErrorCode { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "message")]
|
||||||
|
public string Message { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
34
Ombi.Api.Models/Notifications/DiscordWebhookRequest.cs
Normal file
34
Ombi.Api.Models/Notifications/DiscordWebhookRequest.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: DiscordWebhookRequest.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
|
||||||
|
namespace Ombi.Api.Models.Notifications
|
||||||
|
{
|
||||||
|
public class DiscordWebhookRequest
|
||||||
|
{
|
||||||
|
public string content { get; set; }
|
||||||
|
public string username { get; set; }
|
||||||
|
}
|
||||||
|
}
|
47
Ombi.Api.Models/Notifications/DiscordWebhookResponse.cs
Normal file
47
Ombi.Api.Models/Notifications/DiscordWebhookResponse.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: DiscordWebhookResponse.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 Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Models.Notifications
|
||||||
|
{
|
||||||
|
public class DiscordWebhookResponse
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "channel_id")]
|
||||||
|
public string channelid { get; set; }
|
||||||
|
|
||||||
|
public string token { get; set; }
|
||||||
|
public string avatar { get; set; }
|
||||||
|
[JsonProperty(PropertyName = "guild_id")]
|
||||||
|
public string guildid { get; set; }
|
||||||
|
|
||||||
|
public string id { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,6 +54,7 @@
|
||||||
<Compile Include="Movie\CouchPotatoProfiles.cs" />
|
<Compile Include="Movie\CouchPotatoProfiles.cs" />
|
||||||
<Compile Include="Movie\CouchPotatoStatus.cs" />
|
<Compile Include="Movie\CouchPotatoStatus.cs" />
|
||||||
<Compile Include="Movie\CouchPotatoApiKey.cs" />
|
<Compile Include="Movie\CouchPotatoApiKey.cs" />
|
||||||
|
<Compile Include="Movie\TmdbMovieDetails.cs" />
|
||||||
<Compile Include="Music\HeadphonesAlbumSearchResult.cs" />
|
<Compile Include="Music\HeadphonesAlbumSearchResult.cs" />
|
||||||
<Compile Include="Music\HeadphonesArtistSearchResult.cs" />
|
<Compile Include="Music\HeadphonesArtistSearchResult.cs" />
|
||||||
<Compile Include="Music\HeadphonesGetIndex.cs" />
|
<Compile Include="Music\HeadphonesGetIndex.cs" />
|
||||||
|
@ -62,6 +63,8 @@
|
||||||
<Compile Include="Music\MusicBrainzReleaseInfo.cs" />
|
<Compile Include="Music\MusicBrainzReleaseInfo.cs" />
|
||||||
<Compile Include="Music\MusicBrainzSearchResults.cs" />
|
<Compile Include="Music\MusicBrainzSearchResults.cs" />
|
||||||
<Compile Include="Netflix\NetflixMovieResult.cs" />
|
<Compile Include="Netflix\NetflixMovieResult.cs" />
|
||||||
|
<Compile Include="Notifications\DiscordWebhookRequest.cs" />
|
||||||
|
<Compile Include="Notifications\DiscordWebhookResponse.cs" />
|
||||||
<Compile Include="Notifications\PushbulletPush.cs" />
|
<Compile Include="Notifications\PushbulletPush.cs" />
|
||||||
<Compile Include="Notifications\PushbulletResponse.cs" />
|
<Compile Include="Notifications\PushbulletResponse.cs" />
|
||||||
<Compile Include="Notifications\PushoverResponse.cs" />
|
<Compile Include="Notifications\PushoverResponse.cs" />
|
||||||
|
@ -80,6 +83,10 @@
|
||||||
<Compile Include="Plex\PlexUserRequest.cs" />
|
<Compile Include="Plex\PlexUserRequest.cs" />
|
||||||
<Compile Include="Plex\RecentlyAddedModelOld.cs" />
|
<Compile Include="Plex\RecentlyAddedModelOld.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Radarr\RadarrAddMovie.cs" />
|
||||||
|
<Compile Include="Radarr\RadarrAddOptions.cs" />
|
||||||
|
<Compile Include="Radarr\RadarrError.cs" />
|
||||||
|
<Compile Include="Radarr\RadarrMovieResponse.cs" />
|
||||||
<Compile Include="SickRage\SickRageBase.cs" />
|
<Compile Include="SickRage\SickRageBase.cs" />
|
||||||
<Compile Include="SickRage\SickrageShows.cs" />
|
<Compile Include="SickRage\SickrageShows.cs" />
|
||||||
<Compile Include="SickRage\SickRagePing.cs" />
|
<Compile Include="SickRage\SickRagePing.cs" />
|
||||||
|
@ -95,6 +102,7 @@
|
||||||
<Compile Include="Sonarr\SonarrEpisodes.cs" />
|
<Compile Include="Sonarr\SonarrEpisodes.cs" />
|
||||||
<Compile Include="Sonarr\SonarrError.cs" />
|
<Compile Include="Sonarr\SonarrError.cs" />
|
||||||
<Compile Include="Sonarr\SonarrProfile.cs" />
|
<Compile Include="Sonarr\SonarrProfile.cs" />
|
||||||
|
<Compile Include="Sonarr\SonarrRootFolder.cs" />
|
||||||
<Compile Include="Sonarr\SonarrSearchCommand.cs" />
|
<Compile Include="Sonarr\SonarrSearchCommand.cs" />
|
||||||
<Compile Include="Sonarr\SonarrSeasonSearchResult.cs" />
|
<Compile Include="Sonarr\SonarrSeasonSearchResult.cs" />
|
||||||
<Compile Include="Sonarr\SonarrSeriesSearchResult.cs" />
|
<Compile Include="Sonarr\SonarrSeriesSearchResult.cs" />
|
||||||
|
|
56
Ombi.Api.Models/Radarr/RadarrAddMovie.cs
Normal file
56
Ombi.Api.Models/Radarr/RadarrAddMovie.cs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: RadarrAddMovie.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.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Ombi.Api.Models.Sonarr;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Models.Radarr
|
||||||
|
{
|
||||||
|
public class RadarrAddMovie
|
||||||
|
{
|
||||||
|
|
||||||
|
public RadarrAddMovie()
|
||||||
|
{
|
||||||
|
images = new List<string>();
|
||||||
|
}
|
||||||
|
public RadarrError Error { get; set; }
|
||||||
|
public RadarrAddOptions addOptions { get; set; }
|
||||||
|
public string title { get; set; }
|
||||||
|
public string rootFolderPath { get; set; }
|
||||||
|
public int qualityProfileId { get; set; }
|
||||||
|
public bool monitored { get; set; }
|
||||||
|
public int tmdbId { get; set; }
|
||||||
|
public List<string> images { get; set; }
|
||||||
|
public string cleanTitle { get; set; }
|
||||||
|
public string imdbId { get; set; }
|
||||||
|
public string titleSlug { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
public int year { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
35
Ombi.Api.Models/Radarr/RadarrAddOptions.cs
Normal file
35
Ombi.Api.Models/Radarr/RadarrAddOptions.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: RadarrAddOptions.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
|
||||||
|
namespace Ombi.Api.Models.Radarr
|
||||||
|
{
|
||||||
|
public class RadarrAddOptions
|
||||||
|
{
|
||||||
|
public bool ignoreEpisodesWithFiles { get; set; }
|
||||||
|
public bool ignoreEpisodesWithoutFiles { get; set; }
|
||||||
|
public bool searchForMovie { get; set; }
|
||||||
|
}
|
||||||
|
}
|
34
Ombi.Api.Models/Radarr/RadarrError.cs
Normal file
34
Ombi.Api.Models/Radarr/RadarrError.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: RadarrError.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
|
||||||
|
namespace Ombi.Api.Models.Radarr
|
||||||
|
{
|
||||||
|
public class RadarrError
|
||||||
|
{
|
||||||
|
public string message { get; set; }
|
||||||
|
public string description { get; set; }
|
||||||
|
}
|
||||||
|
}
|
80
Ombi.Api.Models/Radarr/RadarrMovieResponse.cs
Normal file
80
Ombi.Api.Models/Radarr/RadarrMovieResponse.cs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: RadarrMovieResponse.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.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Models.Radarr
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public class Image
|
||||||
|
{
|
||||||
|
public string coverType { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Ratings
|
||||||
|
{
|
||||||
|
public int votes { get; set; }
|
||||||
|
public double value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RadarrMovieResponse
|
||||||
|
{
|
||||||
|
public string title { get; set; }
|
||||||
|
public string sortTitle { get; set; }
|
||||||
|
public double sizeOnDisk { get; set; }
|
||||||
|
public string status { get; set; }
|
||||||
|
public string overview { get; set; }
|
||||||
|
public string inCinemas { get; set; }
|
||||||
|
public string physicalRelease { get; set; }
|
||||||
|
public List<Image> images { get; set; }
|
||||||
|
public string website { get; set; }
|
||||||
|
public bool downloaded { get; set; }
|
||||||
|
public int year { get; set; }
|
||||||
|
public bool hasFile { get; set; }
|
||||||
|
public string youTubeTrailerId { get; set; }
|
||||||
|
public string studio { get; set; }
|
||||||
|
public string path { get; set; }
|
||||||
|
public int profileId { get; set; }
|
||||||
|
public bool monitored { get; set; }
|
||||||
|
public int runtime { get; set; }
|
||||||
|
public string lastInfoSync { get; set; }
|
||||||
|
public string cleanTitle { get; set; }
|
||||||
|
public string imdbId { get; set; }
|
||||||
|
public int tmdbId { get; set; }
|
||||||
|
public string titleSlug { get; set; }
|
||||||
|
public List<string> genres { get; set; }
|
||||||
|
public List<object> tags { get; set; }
|
||||||
|
public string added { get; set; }
|
||||||
|
public Ratings ratings { get; set; }
|
||||||
|
public List<string> alternativeTitles { get; set; }
|
||||||
|
public int qualityProfileId { get; set; }
|
||||||
|
public int id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
Ombi.Api.Models/Sonarr/SonarrRootFolder.cs
Normal file
35
Ombi.Api.Models/Sonarr/SonarrRootFolder.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: SonarrRootFolder.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
|
||||||
|
namespace Ombi.Api.Models.Sonarr
|
||||||
|
{
|
||||||
|
public class SonarrRootFolder
|
||||||
|
{
|
||||||
|
public int id { get; set; }
|
||||||
|
public string path { get; set; }
|
||||||
|
public long freespace { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -70,7 +70,7 @@ namespace Ombi.Api
|
||||||
|
|
||||||
return response.Data;
|
return response.Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRestResponse Execute(IRestRequest request, Uri baseUri)
|
public IRestResponse Execute(IRestRequest request, Uri baseUri)
|
||||||
{
|
{
|
||||||
var client = new RestClient { BaseUrl = baseUri };
|
var client = new RestClient { BaseUrl = baseUri };
|
||||||
|
|
115
Ombi.Api/DiscordApi.cs
Normal file
115
Ombi.Api/DiscordApi.cs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: NetflixRouletteApi.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.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Ombi.Api.Interfaces;
|
||||||
|
using Ombi.Api.Models.Netflix;
|
||||||
|
using Ombi.Api.Models.Notifications;
|
||||||
|
using RestSharp;
|
||||||
|
|
||||||
|
namespace Ombi.Api
|
||||||
|
{
|
||||||
|
public class DiscordApi : IDiscordApi
|
||||||
|
{
|
||||||
|
public DiscordApi(IApiRequest req)
|
||||||
|
{
|
||||||
|
Api = req;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IApiRequest Api { get; }
|
||||||
|
private Uri Endpoint => new Uri("https://discordapp.com/api/"); //webhooks/270828242636636161/lLysOMhJ96AFO1kvev0bSqP-WCZxKUh1UwfubhIcLkpS0DtM3cg4Pgeraw3waoTXbZii
|
||||||
|
|
||||||
|
|
||||||
|
public void SendMessage(string message, string webhookId, string webhookToken, string username = null)
|
||||||
|
{
|
||||||
|
var request = new RestRequest
|
||||||
|
{
|
||||||
|
Resource = "webhooks/{webhookId}/{webhookToken}",
|
||||||
|
Method = Method.POST
|
||||||
|
};
|
||||||
|
|
||||||
|
request.AddUrlSegment("webhookId", webhookId);
|
||||||
|
request.AddUrlSegment("webhookToken", webhookToken);
|
||||||
|
|
||||||
|
var body = new DiscordWebhookRequest
|
||||||
|
{
|
||||||
|
content = message,
|
||||||
|
username = username
|
||||||
|
};
|
||||||
|
request.AddJsonBody(body);
|
||||||
|
|
||||||
|
request.AddHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
Api.Execute(request, Endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendMessageAsync(string message, string webhookId, string webhookToken, string username = null)
|
||||||
|
{
|
||||||
|
var request = new RestRequest
|
||||||
|
{
|
||||||
|
Resource = "webhooks/{webhookId}/{webhookToken}",
|
||||||
|
Method = Method.POST
|
||||||
|
};
|
||||||
|
|
||||||
|
request.AddUrlSegment("webhookId", webhookId);
|
||||||
|
request.AddUrlSegment("webhookToken", webhookToken);
|
||||||
|
|
||||||
|
var body = new DiscordWebhookRequest
|
||||||
|
{
|
||||||
|
content = message,
|
||||||
|
username = username
|
||||||
|
};
|
||||||
|
request.AddJsonBody(body);
|
||||||
|
|
||||||
|
request.AddHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
await Task.Run(
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
Api.Execute(request, Endpoint);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public NetflixMovieResult CheckNetflix(string title, string year = null)
|
||||||
|
{
|
||||||
|
var request = new RestRequest();
|
||||||
|
request.AddQueryParameter("title", title);
|
||||||
|
if (!string.IsNullOrEmpty(year))
|
||||||
|
{
|
||||||
|
request.AddQueryParameter("year", year);
|
||||||
|
}
|
||||||
|
var result = Api.Execute(request, Endpoint);
|
||||||
|
|
||||||
|
return JsonConvert.DeserializeObject<NetflixMovieResult>(result.Content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,8 @@ namespace Ombi.Api
|
||||||
public abstract class MovieBase
|
public abstract class MovieBase
|
||||||
{
|
{
|
||||||
private static readonly string Encrypted = "0T3QNSseexLO7n7UPiJvl70Y+KKnvbeTlsusl7Kwq0hPH0BHOuFNGwksNCjkwqWedyDdI/MJeUR4wtL4bIl0Z+//uHXEaYM/4H2pjeLbH5EWdUe5TTj1AhaIR5PQweamvcienRyFD/3YPCC/+qL5mHkKXBkPumMod3Zb/4yN0Ik=";
|
private static readonly string Encrypted = "0T3QNSseexLO7n7UPiJvl70Y+KKnvbeTlsusl7Kwq0hPH0BHOuFNGwksNCjkwqWedyDdI/MJeUR4wtL4bIl0Z+//uHXEaYM/4H2pjeLbH5EWdUe5TTj1AhaIR5PQweamvcienRyFD/3YPCC/+qL5mHkKXBkPumMod3Zb/4yN0Ik=";
|
||||||
protected string ApiKey = StringCipher.Decrypt(Encrypted, "ApiKey");
|
private string _apiKey;
|
||||||
|
|
||||||
|
protected string ApiKey => _apiKey ?? (_apiKey = StringCipher.Decrypt(Encrypted, "ApiKey"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Ombi.Api.Interfaces;
|
using Ombi.Api.Interfaces;
|
||||||
using Ombi.Api.Models.Netflix;
|
using Ombi.Api.Models.Netflix;
|
||||||
|
@ -43,10 +44,10 @@ namespace Ombi.Api
|
||||||
private IApiRequest Api { get; }
|
private IApiRequest Api { get; }
|
||||||
private Uri Endpoint => new Uri("http://netflixroulette.net/api/api.php");
|
private Uri Endpoint => new Uri("http://netflixroulette.net/api/api.php");
|
||||||
|
|
||||||
public NetflixMovieResult GetMovies(string movieName, string year = null)
|
public NetflixMovieResult CheckNetflix(string title, string year = null)
|
||||||
{
|
{
|
||||||
var request = new RestRequest();
|
var request = new RestRequest();
|
||||||
request.AddQueryParameter("title", movieName);
|
request.AddQueryParameter("title", title);
|
||||||
if (!string.IsNullOrEmpty(year))
|
if (!string.IsNullOrEmpty(year))
|
||||||
{
|
{
|
||||||
request.AddQueryParameter("year", year);
|
request.AddQueryParameter("year", year);
|
||||||
|
|
|
@ -66,10 +66,17 @@
|
||||||
<HintPath>..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll</HintPath>
|
<HintPath>..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="TraktApiSharp, Version=0.8.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\TraktApiSharp.0.8.0\lib\portable-net45+netcore45+wpa81\TraktApiSharp.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ApiRequest.cs" />
|
<Compile Include="ApiRequest.cs" />
|
||||||
|
<Compile Include="DiscordApi.cs" />
|
||||||
<Compile Include="NetflixRouletteApi.cs" />
|
<Compile Include="NetflixRouletteApi.cs" />
|
||||||
|
<Compile Include="RadarrApi.cs" />
|
||||||
|
<Compile Include="TraktApi.cs" />
|
||||||
<Compile Include="WatcherApi.cs" />
|
<Compile Include="WatcherApi.cs" />
|
||||||
<Compile Include="MusicBrainzApi.cs" />
|
<Compile Include="MusicBrainzApi.cs" />
|
||||||
<Compile Include="SlackApi.cs" />
|
<Compile Include="SlackApi.cs" />
|
||||||
|
|
158
Ombi.Api/RadarrApi.cs
Normal file
158
Ombi.Api/RadarrApi.cs
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: CouchPotatoApi.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.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NLog;
|
||||||
|
using Ombi.Api.Interfaces;
|
||||||
|
using Ombi.Api.Models.Radarr;
|
||||||
|
using Ombi.Api.Models.Sonarr;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using RestSharp;
|
||||||
|
|
||||||
|
namespace Ombi.Api
|
||||||
|
{
|
||||||
|
public class RadarrApi : IRadarrApi
|
||||||
|
{
|
||||||
|
public RadarrApi()
|
||||||
|
{
|
||||||
|
Api = new ApiRequest();
|
||||||
|
}
|
||||||
|
private ApiRequest Api { get; set; }
|
||||||
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public List<SonarrProfile> GetProfiles(string apiKey, Uri baseUrl)
|
||||||
|
{
|
||||||
|
var request = new RestRequest { Resource = "/api/profile", Method = Method.GET };
|
||||||
|
|
||||||
|
request.AddHeader("X-Api-Key", apiKey);
|
||||||
|
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetProfiles for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
||||||
|
TimeSpan.FromSeconds (2),
|
||||||
|
TimeSpan.FromSeconds(5),
|
||||||
|
TimeSpan.FromSeconds(10)
|
||||||
|
});
|
||||||
|
|
||||||
|
var obj = policy.Execute(() => Api.ExecuteJson<List<SonarrProfile>>(request, baseUrl));
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RadarrAddMovie AddMovie(int tmdbId, string title, int year, int qualityId, string rootPath, string apiKey, Uri baseUrl, bool searchNow = false)
|
||||||
|
{
|
||||||
|
var request = new RestRequest
|
||||||
|
{
|
||||||
|
Resource = "/api/movie",
|
||||||
|
Method = Method.POST
|
||||||
|
};
|
||||||
|
|
||||||
|
var options = new RadarrAddMovie
|
||||||
|
{
|
||||||
|
title = title,
|
||||||
|
tmdbId = tmdbId,
|
||||||
|
qualityProfileId = qualityId,
|
||||||
|
rootFolderPath = rootPath,
|
||||||
|
titleSlug = title,
|
||||||
|
monitored = true,
|
||||||
|
year = year
|
||||||
|
};
|
||||||
|
|
||||||
|
if (searchNow)
|
||||||
|
{
|
||||||
|
options.addOptions = new RadarrAddOptions
|
||||||
|
{
|
||||||
|
searchForMovie = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
request.AddHeader("X-Api-Key", apiKey);
|
||||||
|
request.AddJsonBody(options);
|
||||||
|
|
||||||
|
RadarrAddMovie result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling AddSeries for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
||||||
|
TimeSpan.FromSeconds (2)
|
||||||
|
});
|
||||||
|
|
||||||
|
var response = policy.Execute(() => Api.Execute(request, baseUrl));
|
||||||
|
if (response.Content.Contains("\"message\":"))
|
||||||
|
{
|
||||||
|
var error = JsonConvert.DeserializeObject < RadarrError>(response.Content);
|
||||||
|
return new RadarrAddMovie {Error = error};
|
||||||
|
}
|
||||||
|
if (response.Content.Contains("\"errorMessage\":"))
|
||||||
|
{
|
||||||
|
var error = JsonConvert.DeserializeObject<List<SonarrError>>(response.Content).FirstOrDefault();
|
||||||
|
return new RadarrAddMovie {Error = new RadarrError {message = error?.errorMessage}};
|
||||||
|
}
|
||||||
|
return JsonConvert.DeserializeObject < RadarrAddMovie>(response.Content);
|
||||||
|
}
|
||||||
|
catch (JsonSerializationException jse)
|
||||||
|
{
|
||||||
|
Log.Error(jse);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public SystemStatus SystemStatus(string apiKey, Uri baseUrl)
|
||||||
|
{
|
||||||
|
var request = new RestRequest { Resource = "/api/system/status", Method = Method.GET };
|
||||||
|
request.AddHeader("X-Api-Key", apiKey);
|
||||||
|
|
||||||
|
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling SystemStatus for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
||||||
|
TimeSpan.FromSeconds (2),
|
||||||
|
TimeSpan.FromSeconds(5),
|
||||||
|
TimeSpan.FromSeconds(10)
|
||||||
|
});
|
||||||
|
|
||||||
|
var obj = policy.Execute(() => Api.ExecuteJson<SystemStatus>(request, baseUrl));
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<RadarrMovieResponse> GetMovies(string apiKey, Uri baseUrl)
|
||||||
|
{
|
||||||
|
var request = new RestRequest { Resource = "/api/movie", Method = Method.GET };
|
||||||
|
request.AddHeader("X-Api-Key", apiKey);
|
||||||
|
|
||||||
|
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling SystemStatus for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
||||||
|
TimeSpan.FromSeconds (2),
|
||||||
|
TimeSpan.FromSeconds(5),
|
||||||
|
TimeSpan.FromSeconds(10)
|
||||||
|
});
|
||||||
|
|
||||||
|
var obj = policy.Execute(() => Api.Execute(request, baseUrl));
|
||||||
|
|
||||||
|
return JsonConvert.DeserializeObject<List<RadarrMovieResponse>>(obj.Content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,6 +62,22 @@ namespace Ombi.Api
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<SonarrRootFolder> GetRootFolders(string apiKey, Uri baseUrl)
|
||||||
|
{
|
||||||
|
var request = new RestRequest { Resource = "/api/rootfolder", Method = Method.GET };
|
||||||
|
|
||||||
|
request.AddHeader("X-Api-Key", apiKey);
|
||||||
|
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetRootFolders for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
||||||
|
TimeSpan.FromSeconds (2),
|
||||||
|
TimeSpan.FromSeconds(5),
|
||||||
|
TimeSpan.FromSeconds(10)
|
||||||
|
});
|
||||||
|
|
||||||
|
var obj = policy.Execute(() => Api.ExecuteJson<List<SonarrRootFolder>>(request, baseUrl));
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
public SonarrAddSeries AddSeries(int tvdbId, string title, int qualityId, bool seasonFolders, string rootPath, int seasonCount, int[] seasons, string apiKey, Uri baseUrl, bool monitor = true, bool searchForMissingEpisodes = false)
|
public SonarrAddSeries AddSeries(int tvdbId, string title, int qualityId, bool seasonFolders, string rootPath, int seasonCount, int[] seasons, string apiKey, Uri baseUrl, bool monitor = true, bool searchForMissingEpisodes = false)
|
||||||
{
|
{
|
||||||
Log.Debug("Adding series {0}", title);
|
Log.Debug("Adding series {0}", title);
|
||||||
|
|
|
@ -25,12 +25,18 @@
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NLog;
|
||||||
|
using NLog.Fluent;
|
||||||
|
using Ombi.Api.Models.Movie;
|
||||||
|
using RestSharp;
|
||||||
using TMDbLib.Client;
|
using TMDbLib.Client;
|
||||||
using TMDbLib.Objects.General;
|
using TMDbLib.Objects.General;
|
||||||
using TMDbLib.Objects.Movies;
|
using TMDbLib.Objects.Movies;
|
||||||
using TMDbLib.Objects.Search;
|
using TMDbLib.Objects.Search;
|
||||||
|
using Movie = TMDbLib.Objects.Movies.Movie;
|
||||||
|
|
||||||
namespace Ombi.Api
|
namespace Ombi.Api
|
||||||
{
|
{
|
||||||
|
@ -39,9 +45,13 @@ namespace Ombi.Api
|
||||||
public TheMovieDbApi()
|
public TheMovieDbApi()
|
||||||
{
|
{
|
||||||
Client = new TMDbClient(ApiKey);
|
Client = new TMDbClient(ApiKey);
|
||||||
|
Api = new ApiRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ApiRequest Api { get; }
|
||||||
public TMDbClient Client { get; set; }
|
public TMDbClient Client { get; set; }
|
||||||
|
private const string BaseUrl = "https://api.themoviedb.org/3/";
|
||||||
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
public async Task<List<SearchMovie>> SearchMovie(string searchTerm)
|
public async Task<List<SearchMovie>> SearchMovie(string searchTerm)
|
||||||
{
|
{
|
||||||
var results = await Client.SearchMovie(searchTerm);
|
var results = await Client.SearchMovie(searchTerm);
|
||||||
|
@ -56,7 +66,27 @@ namespace Ombi.Api
|
||||||
public async Task<List<MovieResult>> GetUpcomingMovies()
|
public async Task<List<MovieResult>> GetUpcomingMovies()
|
||||||
{
|
{
|
||||||
var movies = await Client.GetMovieList(MovieListType.Upcoming);
|
var movies = await Client.GetMovieList(MovieListType.Upcoming);
|
||||||
return movies?.Results ?? new List<MovieResult>();
|
return movies?.Results ?? new List<MovieResult>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TmdbMovieDetails GetMovieInformationWithVideos(int tmdbId)
|
||||||
|
{
|
||||||
|
var request = new RestRequest { Resource = "movie/{movieId}", Method = Method.GET };
|
||||||
|
request.AddUrlSegment("movieId", tmdbId.ToString());
|
||||||
|
request.AddQueryParameter("api_key", ApiKey);
|
||||||
|
request.AddQueryParameter("append_to_response", "videos"); // Get the videos
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
var obj = Api.ExecuteJson<TmdbMovieDetails>(request, new Uri(BaseUrl));
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Movie> GetMovieInformation(int tmdbId)
|
public async Task<Movie> GetMovieInformation(int tmdbId)
|
||||||
|
|
51
Ombi.Api/TraktApi.cs
Normal file
51
Ombi.Api/TraktApi.cs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Api.Interfaces;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using TraktApiSharp;
|
||||||
|
using TraktApiSharp.Enums;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows.Common;
|
||||||
|
using TraktApiSharp.Requests.Params;
|
||||||
|
|
||||||
|
namespace Ombi.Api
|
||||||
|
{
|
||||||
|
public class TraktApi : ITraktApi
|
||||||
|
{
|
||||||
|
private TraktClient Client { get; }
|
||||||
|
|
||||||
|
private static readonly string Encrypted = "z/56wM/oEkkCWEvSIZCrzQyUvvqmafQ3njqf0UNK5xuKbNYh5Wz8ocoG2QDa5y1DBkozLaKsGxORmAB1XUvwbnom8DVNo9gE++9GTuwxmGlLDD318PXpRmYmpKqNwFSKRZgF6ewiY9qR4t3iG0pGQwPA08FK3+H7kpOKAGJNR9RMDP9wwB6Vl4DuOiZb9/DETjzZ+/zId0ZqimrbN+PLrg==";
|
||||||
|
private readonly string _apiKey = StringCipher.Decrypt(Encrypted, "ApiKey");
|
||||||
|
public TraktApi()
|
||||||
|
{
|
||||||
|
Client = new TraktClient(_apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TraktShow>> GetPopularShows(int? page = null, int? limitPerPage = null)
|
||||||
|
{
|
||||||
|
var popular = await Client.Shows.GetPopularShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||||
|
return popular.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TraktTrendingShow>> GetTrendingShows(int? page = null, int? limitPerPage = null)
|
||||||
|
{
|
||||||
|
var trendingShowsTop10 = await Client.Shows.GetTrendingShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||||
|
return trendingShowsTop10.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TraktMostAnticipatedShow>> GetAnticipatedShows(int? page = null, int? limitPerPage = null)
|
||||||
|
{
|
||||||
|
var anticipatedShows = await Client.Shows.GetMostAnticipatedShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||||
|
return anticipatedShows.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TraktMostWatchedShow>> GetMostWatchesShows(TraktTimePeriod period = null, int? page = null, int? limitPerPage = null)
|
||||||
|
{
|
||||||
|
var anticipatedShows = await Client.Shows.GetMostWatchedShowsAsync(period ?? TraktTimePeriod.Monthly, new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
|
||||||
|
return anticipatedShows.Items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,4 +8,5 @@
|
||||||
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
||||||
<package id="System.Net.Http" version="4.0.0" targetFramework="net45" />
|
<package id="System.Net.Http" version="4.0.0" targetFramework="net45" />
|
||||||
<package id="TMDbLib" version="0.9.0.0-alpha" targetFramework="net45" />
|
<package id="TMDbLib" version="0.9.0.0-alpha" targetFramework="net45" />
|
||||||
|
<package id="TraktApiSharp" version="0.8.0" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
64
Ombi.Core.Migration/Migrations/Version2200.cs
Normal file
64
Ombi.Core.Migration/Migrations/Version2200.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#region Copyright
|
||||||
|
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: Version1100.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.Data;
|
||||||
|
using NLog;
|
||||||
|
using Ombi.Core.SettingModels;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Migration.Migrations
|
||||||
|
{
|
||||||
|
[Migration(22000, "v2.20.0.0")]
|
||||||
|
public class Version2200 : BaseMigration, IMigration
|
||||||
|
{
|
||||||
|
public Version2200(ISettingsService<CustomizationSettings> custom)
|
||||||
|
{
|
||||||
|
Customization = custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Version => 22000;
|
||||||
|
private ISettingsService<CustomizationSettings> Customization { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
private static Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public void Start(IDbConnection con)
|
||||||
|
{
|
||||||
|
//UpdateCustomSettings(); Turned off the migration for now until the search has been improved on.
|
||||||
|
//UpdateSchema(con, Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCustomSettings()
|
||||||
|
{
|
||||||
|
var settings = Customization.GetSettings();
|
||||||
|
settings.NewSearch = true; // Use the new search
|
||||||
|
|
||||||
|
Customization.SaveSettings(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,6 +69,7 @@
|
||||||
<Compile Include="MigrationAttribute.cs" />
|
<Compile Include="MigrationAttribute.cs" />
|
||||||
<Compile Include="MigrationRunner.cs" />
|
<Compile Include="MigrationRunner.cs" />
|
||||||
<Compile Include="Migrations\BaseMigration.cs" />
|
<Compile Include="Migrations\BaseMigration.cs" />
|
||||||
|
<Compile Include="Migrations\Version2200.cs" />
|
||||||
<Compile Include="Migrations\Version1100.cs" />
|
<Compile Include="Migrations\Version1100.cs" />
|
||||||
<Compile Include="Migrations\Version195.cs" />
|
<Compile Include="Migrations\Version195.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|
|
@ -37,7 +37,9 @@ namespace Ombi.Core
|
||||||
public const string PlexEpisodes = nameof(PlexEpisodes);
|
public const string PlexEpisodes = nameof(PlexEpisodes);
|
||||||
public const string TvDbToken = nameof(TvDbToken);
|
public const string TvDbToken = nameof(TvDbToken);
|
||||||
public const string SonarrQualityProfiles = nameof(SonarrQualityProfiles);
|
public const string SonarrQualityProfiles = nameof(SonarrQualityProfiles);
|
||||||
|
public const string RadarrQualityProfiles = nameof(RadarrQualityProfiles);
|
||||||
public const string SonarrQueued = nameof(SonarrQueued);
|
public const string SonarrQueued = nameof(SonarrQueued);
|
||||||
|
public const string RadarrMovies = nameof(RadarrMovies);
|
||||||
public const string SickRageQualityProfiles = nameof(SickRageQualityProfiles);
|
public const string SickRageQualityProfiles = nameof(SickRageQualityProfiles);
|
||||||
public const string SickRageQueued = nameof(SickRageQueued);
|
public const string SickRageQueued = nameof(SickRageQueued);
|
||||||
public const string CouchPotatoQualityProfiles = nameof(CouchPotatoQualityProfiles);
|
public const string CouchPotatoQualityProfiles = nameof(CouchPotatoQualityProfiles);
|
||||||
|
@ -45,5 +47,6 @@ namespace Ombi.Core
|
||||||
public const string WatcherQueued = nameof(WatcherQueued);
|
public const string WatcherQueued = nameof(WatcherQueued);
|
||||||
public const string GetPlexRequestSettings = nameof(GetPlexRequestSettings);
|
public const string GetPlexRequestSettings = nameof(GetPlexRequestSettings);
|
||||||
public const string LastestProductVersion = nameof(LastestProductVersion);
|
public const string LastestProductVersion = nameof(LastestProductVersion);
|
||||||
|
public const string SonarrRootFolders = nameof(SonarrRootFolders);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,7 +29,10 @@ namespace Ombi.Core
|
||||||
/// Gets the username this could be the alias! We should always use this method when getting the username
|
/// Gets the username this could be the alias! We should always use this method when getting the username
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="username">The username.</param>
|
/// <param name="username">The username.</param>
|
||||||
/// <returns><c>null</c> if we cannot find a user</returns>
|
/// <param name="session">The session.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>null</c> if we cannot find a user
|
||||||
|
/// </returns>
|
||||||
string GetUsername(string username, ISession session);
|
string GetUsername(string username, ISession session);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,16 +37,20 @@ namespace Ombi.Core
|
||||||
public class MovieSender : IMovieSender
|
public class MovieSender : IMovieSender
|
||||||
{
|
{
|
||||||
public MovieSender(ISettingsService<CouchPotatoSettings> cp, ISettingsService<WatcherSettings> watcher,
|
public MovieSender(ISettingsService<CouchPotatoSettings> cp, ISettingsService<WatcherSettings> watcher,
|
||||||
ICouchPotatoApi cpApi, IWatcherApi watcherApi)
|
ICouchPotatoApi cpApi, IWatcherApi watcherApi, IRadarrApi radarrApi, ISettingsService<RadarrSettings> radarrSettings)
|
||||||
{
|
{
|
||||||
CouchPotatoSettings = cp;
|
CouchPotatoSettings = cp;
|
||||||
WatcherSettings = watcher;
|
WatcherSettings = watcher;
|
||||||
CpApi = cpApi;
|
CpApi = cpApi;
|
||||||
WatcherApi = watcherApi;
|
WatcherApi = watcherApi;
|
||||||
|
RadarrSettings = radarrSettings;
|
||||||
|
RadarrApi = radarrApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISettingsService<CouchPotatoSettings> CouchPotatoSettings { get; }
|
private ISettingsService<CouchPotatoSettings> CouchPotatoSettings { get; }
|
||||||
private ISettingsService<WatcherSettings> WatcherSettings { get; }
|
private ISettingsService<WatcherSettings> WatcherSettings { get; }
|
||||||
|
private ISettingsService<RadarrSettings> RadarrSettings { get; }
|
||||||
|
private IRadarrApi RadarrApi { get; }
|
||||||
private ICouchPotatoApi CpApi { get; }
|
private ICouchPotatoApi CpApi { get; }
|
||||||
private IWatcherApi WatcherApi { get; }
|
private IWatcherApi WatcherApi { get; }
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
@ -55,6 +59,7 @@ namespace Ombi.Core
|
||||||
{
|
{
|
||||||
var cpSettings = await CouchPotatoSettings.GetSettingsAsync();
|
var cpSettings = await CouchPotatoSettings.GetSettingsAsync();
|
||||||
var watcherSettings = await WatcherSettings.GetSettingsAsync();
|
var watcherSettings = await WatcherSettings.GetSettingsAsync();
|
||||||
|
var radarrSettings = await RadarrSettings.GetSettingsAsync();
|
||||||
|
|
||||||
if (cpSettings.Enabled)
|
if (cpSettings.Enabled)
|
||||||
{
|
{
|
||||||
|
@ -66,6 +71,11 @@ namespace Ombi.Core
|
||||||
return SendToWatcher(model, watcherSettings);
|
return SendToWatcher(model, watcherSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (radarrSettings.Enabled)
|
||||||
|
{
|
||||||
|
return SendToRadarr(model, radarrSettings);
|
||||||
|
}
|
||||||
|
|
||||||
return new MovieSenderResult { Result = false, MovieSendingEnabled = false };
|
return new MovieSenderResult { Result = false, MovieSendingEnabled = false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,5 +101,23 @@ namespace Ombi.Core
|
||||||
var result = CpApi.AddMovie(model.ImdbId, settings.ApiKey, model.Title, settings.FullUri, qualityId);
|
var result = CpApi.AddMovie(model.ImdbId, settings.ApiKey, model.Title, settings.FullUri, qualityId);
|
||||||
return new MovieSenderResult { Result = result, MovieSendingEnabled = true };
|
return new MovieSenderResult { Result = result, MovieSendingEnabled = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MovieSenderResult SendToRadarr(RequestedModel model, RadarrSettings settings)
|
||||||
|
{
|
||||||
|
var qualityProfile = 0;
|
||||||
|
int.TryParse(settings.QualityProfile, out qualityProfile);
|
||||||
|
var result = RadarrApi.AddMovie(model.ProviderId, model.Title, model.ReleaseDate.Year, qualityProfile, settings.RootPath, settings.ApiKey, settings.FullUri, true);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(result.Error?.message))
|
||||||
|
{
|
||||||
|
Log.Error(result.Error.message);
|
||||||
|
return new MovieSenderResult { Result = false, Error = true};
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(result.title))
|
||||||
|
{
|
||||||
|
return new MovieSenderResult { Result = true, MovieSendingEnabled = true };
|
||||||
|
}
|
||||||
|
return new MovieSenderResult { Result = false, MovieSendingEnabled = true };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,5 +36,7 @@ namespace Ombi.Core
|
||||||
/// <c>true</c> if [movie sending enabled]; otherwise, <c>false</c>.
|
/// <c>true</c> if [movie sending enabled]; otherwise, <c>false</c>.
|
||||||
/// </value>
|
/// </value>
|
||||||
public bool MovieSendingEnabled { get; set; }
|
public bool MovieSendingEnabled { get; set; }
|
||||||
|
|
||||||
|
public bool Error { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -122,6 +122,8 @@
|
||||||
<Compile Include="Queue\TransientFaultQueue.cs" />
|
<Compile Include="Queue\TransientFaultQueue.cs" />
|
||||||
<Compile Include="SecurityExtensions.cs" />
|
<Compile Include="SecurityExtensions.cs" />
|
||||||
<Compile Include="SettingModels\AuthenticationSettings.cs" />
|
<Compile Include="SettingModels\AuthenticationSettings.cs" />
|
||||||
|
<Compile Include="SettingModels\DiscordNotificationSettings.cs" />
|
||||||
|
<Compile Include="SettingModels\RadarrSettings.cs" />
|
||||||
<Compile Include="SettingModels\WatcherSettings.cs" />
|
<Compile Include="SettingModels\WatcherSettings.cs" />
|
||||||
<Compile Include="SettingModels\ExternalSettings.cs" />
|
<Compile Include="SettingModels\ExternalSettings.cs" />
|
||||||
<Compile Include="SettingModels\HeadphonesSettings.cs" />
|
<Compile Include="SettingModels\HeadphonesSettings.cs" />
|
||||||
|
|
|
@ -97,7 +97,7 @@ namespace Ombi.Core.Queue
|
||||||
Content = ByteConverterHelper.ReturnBytes(request),
|
Content = ByteConverterHelper.ReturnBytes(request),
|
||||||
PrimaryIdentifier = id,
|
PrimaryIdentifier = id,
|
||||||
FaultType = faultType,
|
FaultType = faultType,
|
||||||
Message = description ?? string.Empty
|
Description = description ?? string.Empty
|
||||||
};
|
};
|
||||||
await RequestQueue.InsertAsync(queue);
|
await RequestQueue.InsertAsync(queue);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,40 +94,33 @@ namespace Ombi.Core
|
||||||
/// Gets the username this could be the alias! We should always use this method when getting the username
|
/// Gets the username this could be the alias! We should always use this method when getting the username
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="username">The username.</param>
|
/// <param name="username">The username.</param>
|
||||||
/// <returns><c>null</c> if we cannot find a user</returns>
|
/// <param name="session"></param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>null</c> if we cannot find a user
|
||||||
|
/// </returns>
|
||||||
public string GetUsername(string username, ISession session)
|
public string GetUsername(string username, ISession session)
|
||||||
{
|
{
|
||||||
var plexUser = PlexUsers.GetUserByUsername(username);
|
var plexUser = PlexUsers.GetUserByUsername(username);
|
||||||
if (plexUser != null)
|
if (plexUser != null)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(plexUser.UserAlias))
|
return !string.IsNullOrEmpty(plexUser.UserAlias) ? plexUser.UserAlias : plexUser.Username;
|
||||||
{
|
|
||||||
return plexUser.UserAlias;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return plexUser.Username;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var dbUser = UserRepository.GetUserByUsername(username);
|
var dbUser = UserRepository.GetUserByUsername(username);
|
||||||
if (dbUser != null)
|
if (dbUser != null)
|
||||||
{
|
{
|
||||||
var userProps = ByteConverterHelper.ReturnObject<UserProperties>(dbUser.UserProperties);
|
var userProps = ByteConverterHelper.ReturnObject<UserProperties>(dbUser.UserProperties);
|
||||||
if (!string.IsNullOrEmpty(userProps.UserAlias))
|
return !string.IsNullOrEmpty(userProps.UserAlias) ? userProps.UserAlias : dbUser.UserName;
|
||||||
{
|
|
||||||
return userProps.UserAlias;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return dbUser.UserName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// could be a local user
|
// could be a local user
|
||||||
var localName = session[SessionKeys.UsernameKey];
|
var hasSessionKey = session[SessionKeys.UsernameKey] != null;
|
||||||
|
if (hasSessionKey)
|
||||||
|
{
|
||||||
|
return (string)session[SessionKeys.UsernameKey];
|
||||||
|
}
|
||||||
|
|
||||||
return localName as string;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -53,5 +53,7 @@ namespace Ombi.Core.SettingModels
|
||||||
|
|
||||||
public int DefaultLang { get; set; }
|
public int DefaultLang { get; set; }
|
||||||
|
|
||||||
|
public bool NewSearch { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
31
Ombi.Core/SettingModels/DiscordNotificationSettings.cs
Normal file
31
Ombi.Core/SettingModels/DiscordNotificationSettings.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Ombi.Core.SettingModels
|
||||||
|
{
|
||||||
|
public sealed class DiscordNotificationSettings : NotificationSettings
|
||||||
|
{
|
||||||
|
public string WebhookUrl { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public string WebookId => SplitWebUrl(4);
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public string Token => SplitWebUrl(5);
|
||||||
|
|
||||||
|
private string SplitWebUrl(int index)
|
||||||
|
{
|
||||||
|
if (!WebhookUrl.StartsWith("http", StringComparison.InvariantCulture))
|
||||||
|
{
|
||||||
|
WebhookUrl = "https://" + WebhookUrl;
|
||||||
|
}
|
||||||
|
var split = WebhookUrl.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
return split.Length < index
|
||||||
|
? string.Empty
|
||||||
|
: split[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,7 +34,6 @@ namespace Ombi.Core.SettingModels
|
||||||
public string EmailSender { get; set; }
|
public string EmailSender { get; set; }
|
||||||
public string EmailUsername { get; set; }
|
public string EmailUsername { get; set; }
|
||||||
public bool Authentication { get; set; }
|
public bool Authentication { get; set; }
|
||||||
public bool EnableUserEmailNotifications { get; set; }
|
|
||||||
public string RecipientEmail { get; set; }
|
public string RecipientEmail { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
37
Ombi.Core/SettingModels/RadarrSettings.cs
Normal file
37
Ombi.Core/SettingModels/RadarrSettings.cs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: SonarrSettings.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
|
||||||
|
namespace Ombi.Core.SettingModels
|
||||||
|
{
|
||||||
|
public sealed class RadarrSettings : ExternalSettings
|
||||||
|
{
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
public string QualityProfile { get; set; }
|
||||||
|
public string RootPath { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,5 +46,6 @@ namespace Ombi.Core.SettingModels
|
||||||
public int FaultQueueHandler { get; set; }
|
public int FaultQueueHandler { get; set; }
|
||||||
public int PlexContentCacher { get; set; }
|
public int PlexContentCacher { get; set; }
|
||||||
public int PlexUserChecker { get; set; }
|
public int PlexUserChecker { get; set; }
|
||||||
|
public int RadarrCacher { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,7 +32,13 @@ namespace Ombi.Core.SettingModels
|
||||||
public string ApiKey { get; set; }
|
public string ApiKey { get; set; }
|
||||||
public string QualityProfile { get; set; }
|
public string QualityProfile { get; set; }
|
||||||
public bool SeasonFolders { get; set; }
|
public bool SeasonFolders { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// This is the root path ID
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The root path.
|
||||||
|
/// </value>
|
||||||
public string RootPath { get; set; }
|
public string RootPath { get; set; }
|
||||||
|
public string FullRootPath { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -34,19 +34,22 @@ using Ombi.Api.Interfaces;
|
||||||
using Ombi.Api.Models.SickRage;
|
using Ombi.Api.Models.SickRage;
|
||||||
using Ombi.Api.Models.Sonarr;
|
using Ombi.Api.Models.Sonarr;
|
||||||
using Ombi.Core.SettingModels;
|
using Ombi.Core.SettingModels;
|
||||||
|
using Ombi.Helpers;
|
||||||
using Ombi.Store;
|
using Ombi.Store;
|
||||||
|
|
||||||
namespace Ombi.Core
|
namespace Ombi.Core
|
||||||
{
|
{
|
||||||
public class TvSender
|
public class TvSender
|
||||||
{
|
{
|
||||||
public TvSender(ISonarrApi sonarrApi, ISickRageApi srApi)
|
public TvSender(ISonarrApi sonarrApi, ISickRageApi srApi, ICacheProvider cache)
|
||||||
{
|
{
|
||||||
SonarrApi = sonarrApi;
|
SonarrApi = sonarrApi;
|
||||||
SickrageApi = srApi;
|
SickrageApi = srApi;
|
||||||
|
Cache = cache;
|
||||||
}
|
}
|
||||||
private ISonarrApi SonarrApi { get; }
|
private ISonarrApi SonarrApi { get; }
|
||||||
private ISickRageApi SickrageApi { get; }
|
private ISickRageApi SickrageApi { get; }
|
||||||
|
private ICacheProvider Cache { get; }
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
public async Task<SonarrAddSeries> SendToSonarr(SonarrSettings sonarrSettings, RequestedModel model)
|
public async Task<SonarrAddSeries> SendToSonarr(SonarrSettings sonarrSettings, RequestedModel model)
|
||||||
|
@ -82,6 +85,8 @@ namespace Ombi.Core
|
||||||
var latest = model.SeasonsRequested?.Equals("Latest", StringComparison.CurrentCultureIgnoreCase);
|
var latest = model.SeasonsRequested?.Equals("Latest", StringComparison.CurrentCultureIgnoreCase);
|
||||||
var specificSeasonRequest = model.SeasonList?.Any();
|
var specificSeasonRequest = model.SeasonList?.Any();
|
||||||
|
|
||||||
|
var rootFolderPath = model.RootFolderSelected <= 0 ? sonarrSettings.FullRootPath : await GetRootPath(model.RootFolderSelected, sonarrSettings);
|
||||||
|
|
||||||
if (episodeRequest)
|
if (episodeRequest)
|
||||||
{
|
{
|
||||||
// Does series exist?
|
// Does series exist?
|
||||||
|
@ -96,7 +101,7 @@ namespace Ombi.Core
|
||||||
|
|
||||||
// Series doesn't exist, need to add it as unmonitored.
|
// Series doesn't exist, need to add it as unmonitored.
|
||||||
var addResult = await Task.Run(() => SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile,
|
var addResult = await Task.Run(() => SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile,
|
||||||
sonarrSettings.SeasonFolders, sonarrSettings.RootPath, 0, new int[0], sonarrSettings.ApiKey,
|
sonarrSettings.SeasonFolders, rootFolderPath, 0, new int[0], sonarrSettings.ApiKey,
|
||||||
sonarrSettings.FullUri, false));
|
sonarrSettings.FullUri, false));
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,7 +130,7 @@ namespace Ombi.Core
|
||||||
{
|
{
|
||||||
// Set the series as monitored with a season count as 0 so it doesn't search for anything
|
// Set the series as monitored with a season count as 0 so it doesn't search for anything
|
||||||
SonarrApi.AddSeriesNew(model.ProviderId, model.Title, qualityProfile,
|
SonarrApi.AddSeriesNew(model.ProviderId, model.Title, qualityProfile,
|
||||||
sonarrSettings.SeasonFolders, sonarrSettings.RootPath, new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13}, sonarrSettings.ApiKey,
|
sonarrSettings.SeasonFolders, rootFolderPath, new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13}, sonarrSettings.ApiKey,
|
||||||
sonarrSettings.FullUri);
|
sonarrSettings.FullUri);
|
||||||
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||||
|
@ -372,5 +377,20 @@ namespace Ombi.Core
|
||||||
|
|
||||||
return selectedSeries;
|
return selectedSeries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string> GetRootPath(int pathId, SonarrSettings sonarrSettings)
|
||||||
|
{
|
||||||
|
var rootFoldersResult = await Cache.GetOrSetAsync(CacheKeys.SonarrRootFolders, async () =>
|
||||||
|
{
|
||||||
|
return await Task.Run(() => SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri));
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var r in rootFoldersResult.Where(r => r.id == pathId))
|
||||||
|
{
|
||||||
|
return r.path;
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -34,19 +34,22 @@ using Ombi.Api.Interfaces;
|
||||||
using Ombi.Api.Models.SickRage;
|
using Ombi.Api.Models.SickRage;
|
||||||
using Ombi.Api.Models.Sonarr;
|
using Ombi.Api.Models.Sonarr;
|
||||||
using Ombi.Core.SettingModels;
|
using Ombi.Core.SettingModels;
|
||||||
|
using Ombi.Helpers;
|
||||||
using Ombi.Store;
|
using Ombi.Store;
|
||||||
|
|
||||||
namespace Ombi.Core
|
namespace Ombi.Core
|
||||||
{
|
{
|
||||||
public class TvSenderOld
|
public class TvSenderOld
|
||||||
{
|
{
|
||||||
public TvSenderOld(ISonarrApi sonarrApi, ISickRageApi srApi)
|
public TvSenderOld(ISonarrApi sonarrApi, ISickRageApi srApi, ICacheProvider cache)
|
||||||
{
|
{
|
||||||
SonarrApi = sonarrApi;
|
SonarrApi = sonarrApi;
|
||||||
SickrageApi = srApi;
|
SickrageApi = srApi;
|
||||||
|
Cache = cache;
|
||||||
}
|
}
|
||||||
private ISonarrApi SonarrApi { get; }
|
private ISonarrApi SonarrApi { get; }
|
||||||
private ISickRageApi SickrageApi { get; }
|
private ISickRageApi SickrageApi { get; }
|
||||||
|
private ICacheProvider Cache { get; }
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
public async Task<SonarrAddSeries> SendToSonarr(SonarrSettings sonarrSettings, RequestedModel model)
|
public async Task<SonarrAddSeries> SendToSonarr(SonarrSettings sonarrSettings, RequestedModel model)
|
||||||
|
@ -67,6 +70,8 @@ namespace Ombi.Core
|
||||||
{
|
{
|
||||||
int.TryParse(sonarrSettings.QualityProfile, out qualityProfile);
|
int.TryParse(sonarrSettings.QualityProfile, out qualityProfile);
|
||||||
}
|
}
|
||||||
|
var rootFolderPath = model.RootFolderSelected <= 0 ? sonarrSettings.FullRootPath : await GetRootPath(model.RootFolderSelected, sonarrSettings);
|
||||||
|
|
||||||
|
|
||||||
var series = await GetSonarrSeries(sonarrSettings, model.ProviderId);
|
var series = await GetSonarrSeries(sonarrSettings, model.ProviderId);
|
||||||
|
|
||||||
|
@ -84,7 +89,7 @@ namespace Ombi.Core
|
||||||
|
|
||||||
// Series doesn't exist, need to add it as unmonitored.
|
// Series doesn't exist, need to add it as unmonitored.
|
||||||
var addResult = await Task.Run(() => SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile,
|
var addResult = await Task.Run(() => SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile,
|
||||||
sonarrSettings.SeasonFolders, sonarrSettings.RootPath, 0, new int[0], sonarrSettings.ApiKey,
|
sonarrSettings.SeasonFolders, rootFolderPath, 0, new int[0], sonarrSettings.ApiKey,
|
||||||
sonarrSettings.FullUri, false));
|
sonarrSettings.FullUri, false));
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,7 +161,7 @@ namespace Ombi.Core
|
||||||
|
|
||||||
|
|
||||||
var result = SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile,
|
var result = SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile,
|
||||||
sonarrSettings.SeasonFolders, sonarrSettings.RootPath, model.SeasonCount, model.SeasonList, sonarrSettings.ApiKey,
|
sonarrSettings.SeasonFolders, rootFolderPath, model.SeasonCount, model.SeasonList, sonarrSettings.ApiKey,
|
||||||
sonarrSettings.FullUri, true, true);
|
sonarrSettings.FullUri, true, true);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -298,5 +303,20 @@ namespace Ombi.Core
|
||||||
|
|
||||||
return selectedSeries;
|
return selectedSeries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<string> GetRootPath(int pathId, SonarrSettings sonarrSettings)
|
||||||
|
{
|
||||||
|
var rootFoldersResult = await Cache.GetOrSetAsync(CacheKeys.SonarrRootFolders, async () =>
|
||||||
|
{
|
||||||
|
return await Task.Run(() => SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri));
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var r in rootFoldersResult.Where(r => r.id == pathId))
|
||||||
|
{
|
||||||
|
return r.path;
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,6 +25,7 @@
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Helpers.Permissions;
|
using Ombi.Helpers.Permissions;
|
||||||
|
|
||||||
|
@ -38,5 +39,8 @@ namespace Ombi.Core.Users
|
||||||
public Features Features { get; set; }
|
public Features Features { get; set; }
|
||||||
public string EmailAddress { get; set; }
|
public string EmailAddress { get; set; }
|
||||||
public UserType Type { get; set; }
|
public UserType Type { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public string UsernameOrAlias => string.IsNullOrEmpty(UserAlias) ? Username : UserAlias;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -46,5 +46,12 @@ namespace Ombi.Helpers
|
||||||
dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime();
|
dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime();
|
||||||
return dtDateTime;
|
return dtDateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long ToJavascriptTimestamp(this DateTime input)
|
||||||
|
{
|
||||||
|
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
var time = input.Subtract(new TimeSpan(epoch.Ticks));
|
||||||
|
return (long)(time.Ticks / 10000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ namespace Ombi.Services.Interfaces
|
||||||
{
|
{
|
||||||
public interface IAvailabilityChecker
|
public interface IAvailabilityChecker
|
||||||
{
|
{
|
||||||
|
void Start();
|
||||||
void CheckAndUpdateAll();
|
void CheckAndUpdateAll();
|
||||||
IEnumerable<PlexContent> GetPlexMovies(IEnumerable<PlexContent> content);
|
IEnumerable<PlexContent> GetPlexMovies(IEnumerable<PlexContent> content);
|
||||||
bool IsMovieAvailable(PlexContent[] plexMovies, string title, string year, string providerId = null);
|
bool IsMovieAvailable(PlexContent[] plexMovies, string title, string year, string providerId = null);
|
||||||
|
|
11
Ombi.Services/Interfaces/IRadarrCacher.cs
Normal file
11
Ombi.Services/Interfaces/IRadarrCacher.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Services.Models;
|
||||||
|
|
||||||
|
namespace Ombi.Services.Interfaces
|
||||||
|
{
|
||||||
|
public interface IRadarrCacher
|
||||||
|
{
|
||||||
|
void Queued();
|
||||||
|
int[] QueuedIds();
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,5 +6,6 @@ namespace Ombi.Services.Jobs
|
||||||
{
|
{
|
||||||
void Execute(IJobExecutionContext context);
|
void Execute(IJobExecutionContext context);
|
||||||
void Test();
|
void Test();
|
||||||
|
void Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
10
Ombi.Services/Interfaces/IStoreBackup.cs
Normal file
10
Ombi.Services/Interfaces/IStoreBackup.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace Ombi.Services.Jobs
|
||||||
|
{
|
||||||
|
public interface IStoreBackup
|
||||||
|
{
|
||||||
|
void Start();
|
||||||
|
void Execute(IJobExecutionContext context);
|
||||||
|
}
|
||||||
|
}
|
10
Ombi.Services/Interfaces/IStoreCleanup.cs
Normal file
10
Ombi.Services/Interfaces/IStoreCleanup.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace Ombi.Services.Jobs
|
||||||
|
{
|
||||||
|
public interface IStoreCleanup
|
||||||
|
{
|
||||||
|
void Execute(IJobExecutionContext context);
|
||||||
|
void Start();
|
||||||
|
}
|
||||||
|
}
|
16
Ombi.Services/Interfaces/IUserRequestLimitResetter.cs
Normal file
16
Ombi.Services/Interfaces/IUserRequestLimitResetter.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Core.SettingModels;
|
||||||
|
using Ombi.Store.Models;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace Ombi.Services.Jobs
|
||||||
|
{
|
||||||
|
public interface IUserRequestLimitResetter
|
||||||
|
{
|
||||||
|
void AlbumLimit(PlexRequestSettings s, IEnumerable<RequestLimit> allUsers);
|
||||||
|
void Execute(IJobExecutionContext context);
|
||||||
|
void MovieLimit(PlexRequestSettings s, IEnumerable<RequestLimit> allUsers);
|
||||||
|
void Start();
|
||||||
|
void TvLimit(PlexRequestSettings s, IEnumerable<RequestLimit> allUsers);
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ using Quartz;
|
||||||
|
|
||||||
namespace Ombi.Services.Jobs
|
namespace Ombi.Services.Jobs
|
||||||
{
|
{
|
||||||
public class FaultQueueHandler : IJob
|
public class FaultQueueHandler : IJob, IFaultQueueHandler
|
||||||
{
|
{
|
||||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ namespace Ombi.Services.Jobs
|
||||||
ISickRageApi srApi, ISettingsService<SonarrSettings> sonarrSettings, ISettingsService<SickRageSettings> srSettings,
|
ISickRageApi srApi, ISettingsService<SonarrSettings> sonarrSettings, ISettingsService<SickRageSettings> srSettings,
|
||||||
ICouchPotatoApi cpApi, ISettingsService<CouchPotatoSettings> cpsettings, IRequestService requestService,
|
ICouchPotatoApi cpApi, ISettingsService<CouchPotatoSettings> cpsettings, IRequestService requestService,
|
||||||
ISettingsService<HeadphonesSettings> hpSettings, IHeadphonesApi headphonesApi, ISettingsService<PlexRequestSettings> prSettings,
|
ISettingsService<HeadphonesSettings> hpSettings, IHeadphonesApi headphonesApi, ISettingsService<PlexRequestSettings> prSettings,
|
||||||
ISecurityExtensions security, IMovieSender movieSender)
|
ISecurityExtensions security, IMovieSender movieSender, ICacheProvider cache)
|
||||||
{
|
{
|
||||||
Record = record;
|
Record = record;
|
||||||
Repo = repo;
|
Repo = repo;
|
||||||
|
@ -71,6 +71,8 @@ namespace Ombi.Services.Jobs
|
||||||
Security = security;
|
Security = security;
|
||||||
PrSettings = prSettings.GetSettings();
|
PrSettings = prSettings.GetSettings();
|
||||||
MovieSender = movieSender;
|
MovieSender = movieSender;
|
||||||
|
|
||||||
|
Cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMovieSender MovieSender { get; }
|
private IMovieSender MovieSender { get; }
|
||||||
|
@ -78,6 +80,7 @@ namespace Ombi.Services.Jobs
|
||||||
private IJobRecord Record { get; }
|
private IJobRecord Record { get; }
|
||||||
private ISonarrApi SonarrApi { get; }
|
private ISonarrApi SonarrApi { get; }
|
||||||
private ISickRageApi SrApi { get; }
|
private ISickRageApi SrApi { get; }
|
||||||
|
private ICacheProvider Cache { get; }
|
||||||
private ICouchPotatoApi CpApi { get; }
|
private ICouchPotatoApi CpApi { get; }
|
||||||
private IHeadphonesApi HpApi { get; }
|
private IHeadphonesApi HpApi { get; }
|
||||||
private IRequestService RequestService { get; }
|
private IRequestService RequestService { get; }
|
||||||
|
@ -88,9 +91,8 @@ namespace Ombi.Services.Jobs
|
||||||
private ISettingsService<HeadphonesSettings> HeadphoneSettings { get; }
|
private ISettingsService<HeadphonesSettings> HeadphoneSettings { get; }
|
||||||
private ISecurityExtensions Security { get; }
|
private ISecurityExtensions Security { get; }
|
||||||
|
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Start()
|
||||||
{
|
{
|
||||||
|
|
||||||
Record.SetRunning(true, JobNames.CpCacher);
|
Record.SetRunning(true, JobNames.CpCacher);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -113,6 +115,11 @@ namespace Ombi.Services.Jobs
|
||||||
Record.SetRunning(false, JobNames.CpCacher);
|
Record.SetRunning(false, JobNames.CpCacher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ProcessMissingInformation(List<RequestQueue> requests)
|
private void ProcessMissingInformation(List<RequestQueue> requests)
|
||||||
|
@ -163,7 +170,7 @@ namespace Ombi.Services.Jobs
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
var sender = new TvSenderOld(SonarrApi, SrApi);
|
var sender = new TvSenderOld(SonarrApi, SrApi, Cache);
|
||||||
if (sonarr.Enabled)
|
if (sonarr.Enabled)
|
||||||
{
|
{
|
||||||
var task = sender.SendToSonarr(sonarr, tvModel, sonarr.QualityProfile);
|
var task = sender.SendToSonarr(sonarr, tvModel, sonarr.QualityProfile);
|
||||||
|
|
14
Ombi.Services/Jobs/IFaultQueueHandler.cs
Normal file
14
Ombi.Services/Jobs/IFaultQueueHandler.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Core.SettingModels;
|
||||||
|
using Ombi.Store;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace Ombi.Services.Jobs
|
||||||
|
{
|
||||||
|
public interface IFaultQueueHandler
|
||||||
|
{
|
||||||
|
void Execute(IJobExecutionContext context);
|
||||||
|
bool ShouldAutoApprove(RequestType requestType, PlexRequestSettings prSettings, List<string> username);
|
||||||
|
void Start();
|
||||||
|
}
|
||||||
|
}
|
12
Ombi.Services/Jobs/IPlexEpisodeCacher.cs
Normal file
12
Ombi.Services/Jobs/IPlexEpisodeCacher.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using Ombi.Core.SettingModels;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace Ombi.Services.Jobs
|
||||||
|
{
|
||||||
|
public interface IPlexEpisodeCacher
|
||||||
|
{
|
||||||
|
void CacheEpisodes(PlexSettings settings);
|
||||||
|
void Execute(IJobExecutionContext context);
|
||||||
|
void Start();
|
||||||
|
}
|
||||||
|
}
|
10
Ombi.Services/Jobs/IPlexUserChecker.cs
Normal file
10
Ombi.Services/Jobs/IPlexUserChecker.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace Ombi.Services.Jobs
|
||||||
|
{
|
||||||
|
public interface IPlexUserChecker
|
||||||
|
{
|
||||||
|
void Execute(IJobExecutionContext context);
|
||||||
|
void Start();
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ namespace Ombi.Services.Jobs
|
||||||
public const string CpCacher = "CouchPotato Cacher";
|
public const string CpCacher = "CouchPotato Cacher";
|
||||||
public const string WatcherCacher = "Watcher Cacher";
|
public const string WatcherCacher = "Watcher Cacher";
|
||||||
public const string SonarrCacher = "Sonarr Cacher";
|
public const string SonarrCacher = "Sonarr Cacher";
|
||||||
|
public const string RadarrCacher = "Radarr Cacher";
|
||||||
public const string SrCacher = "SickRage Cacher";
|
public const string SrCacher = "SickRage Cacher";
|
||||||
public const string PlexChecker = "Plex Availability Cacher";
|
public const string PlexChecker = "Plex Availability Cacher";
|
||||||
public const string PlexCacher = "Plex Cacher";
|
public const string PlexCacher = "Plex Cacher";
|
||||||
|
|
|
@ -79,6 +79,7 @@ namespace Ombi.Services.Jobs
|
||||||
|
|
||||||
public void CheckAndUpdateAll()
|
public void CheckAndUpdateAll()
|
||||||
{
|
{
|
||||||
|
|
||||||
var plexSettings = Plex.GetSettings();
|
var plexSettings = Plex.GetSettings();
|
||||||
|
|
||||||
if (!ValidateSettings(plexSettings))
|
if (!ValidateSettings(plexSettings))
|
||||||
|
@ -472,5 +473,23 @@ namespace Ombi.Services.Jobs
|
||||||
Job.SetRunning(false, JobNames.PlexChecker);
|
Job.SetRunning(false, JobNames.PlexChecker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
Job.SetRunning(true, JobNames.PlexChecker);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CheckAndUpdateAll();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Job.Record(JobNames.PlexChecker);
|
||||||
|
Job.SetRunning(false, JobNames.PlexChecker);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,7 +43,7 @@ using Quartz;
|
||||||
|
|
||||||
namespace Ombi.Services.Jobs
|
namespace Ombi.Services.Jobs
|
||||||
{
|
{
|
||||||
public class PlexEpisodeCacher : IJob
|
public class PlexEpisodeCacher : IJob, IPlexEpisodeCacher
|
||||||
{
|
{
|
||||||
public PlexEpisodeCacher(ISettingsService<PlexSettings> plexSettings, IPlexApi plex, ICacheProvider cache,
|
public PlexEpisodeCacher(ISettingsService<PlexSettings> plexSettings, IPlexApi plex, ICacheProvider cache,
|
||||||
IJobRecord rec, IRepository<PlexEpisodes> repo, ISettingsService<ScheduledJobsSettings> jobs)
|
IJobRecord rec, IRepository<PlexEpisodes> repo, ISettingsService<ScheduledJobsSettings> jobs)
|
||||||
|
@ -140,6 +140,38 @@ namespace Ombi.Services.Jobs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var s = Plex.GetSettings();
|
||||||
|
if (!s.EnableTvEpisodeSearching)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var jobs = Job.GetJobs();
|
||||||
|
var job = jobs.FirstOrDefault(x => x.Name.Equals(JobNames.EpisodeCacher, StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (job != null)
|
||||||
|
{
|
||||||
|
if (job.LastRun > DateTime.Now.AddHours(-11)) // If it's been run in the last 11 hours
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Job.SetRunning(true, JobNames.EpisodeCacher);
|
||||||
|
CacheEpisodes(s);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Job.Record(JobNames.EpisodeCacher);
|
||||||
|
Job.SetRunning(false, JobNames.EpisodeCacher);
|
||||||
|
}
|
||||||
|
}
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ using Quartz;
|
||||||
|
|
||||||
namespace Ombi.Services.Jobs
|
namespace Ombi.Services.Jobs
|
||||||
{
|
{
|
||||||
public class PlexUserChecker : IJob
|
public class PlexUserChecker : IJob, IPlexUserChecker
|
||||||
{
|
{
|
||||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ namespace Ombi.Services.Jobs
|
||||||
private IRequestService RequestService { get; }
|
private IRequestService RequestService { get; }
|
||||||
private IUserRepository LocalUserRepository { get; }
|
private IUserRepository LocalUserRepository { get; }
|
||||||
|
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Start()
|
||||||
{
|
{
|
||||||
JobRecord.SetRunning(true, JobNames.PlexUserChecker);
|
JobRecord.SetRunning(true, JobNames.PlexUserChecker);
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ namespace Ombi.Services.Jobs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Looks like it's a new user!
|
// Looks like it's a new user!
|
||||||
var m = new PlexUsers
|
var m = new PlexUsers
|
||||||
{
|
{
|
||||||
PlexUserId = user.Id,
|
PlexUserId = user.Id,
|
||||||
Permissions = UserManagementHelper.GetPermissions(userManagementSettings),
|
Permissions = UserManagementHelper.GetPermissions(userManagementSettings),
|
||||||
|
@ -170,7 +170,7 @@ namespace Ombi.Services.Jobs
|
||||||
// Main Plex user
|
// Main Plex user
|
||||||
var dbMainAcc = dbUsers.FirstOrDefault(x => x.Username.Equals(mainPlexAccount.Username, StringComparison.CurrentCulture));
|
var dbMainAcc = dbUsers.FirstOrDefault(x => x.Username.Equals(mainPlexAccount.Username, StringComparison.CurrentCulture));
|
||||||
var localMainAcc = localUsers.FirstOrDefault(x => x.UserName.Equals(mainPlexAccount.Username, StringComparison.CurrentCulture));
|
var localMainAcc = localUsers.FirstOrDefault(x => x.UserName.Equals(mainPlexAccount.Username, StringComparison.CurrentCulture));
|
||||||
|
|
||||||
// TODO if admin acc does exist, check if we need to update it
|
// TODO if admin acc does exist, check if we need to update it
|
||||||
|
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ namespace Ombi.Services.Jobs
|
||||||
LoginId = Guid.NewGuid().ToString()
|
LoginId = Guid.NewGuid().ToString()
|
||||||
};
|
};
|
||||||
|
|
||||||
a.Permissions += (int) Permissions.Administrator; // Make admin
|
a.Permissions += (int)Permissions.Administrator; // Make admin
|
||||||
|
|
||||||
Repo.Insert(a);
|
Repo.Insert(a);
|
||||||
}
|
}
|
||||||
|
@ -205,5 +205,9 @@ namespace Ombi.Services.Jobs
|
||||||
JobRecord.Record(JobNames.PlexUserChecker);
|
JobRecord.Record(JobNames.PlexUserChecker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
110
Ombi.Services/Jobs/RadarrCacher.cs
Normal file
110
Ombi.Services/Jobs/RadarrCacher.cs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: PlexAvailabilityChecker.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.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using Ombi.Api.Interfaces;
|
||||||
|
using Ombi.Api.Models.Radarr;
|
||||||
|
using Ombi.Core;
|
||||||
|
using Ombi.Core.SettingModels;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Services.Interfaces;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace Ombi.Services.Jobs
|
||||||
|
{
|
||||||
|
public class RadarrCacher : IJob, IRadarrCacher
|
||||||
|
{
|
||||||
|
public RadarrCacher(ISettingsService<RadarrSettings> radarrService, IRadarrApi radarrApi, ICacheProvider cache, IJobRecord rec)
|
||||||
|
{
|
||||||
|
RadarrSettings = radarrService;
|
||||||
|
RadarrApi = radarrApi;
|
||||||
|
Job = rec;
|
||||||
|
Cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ISettingsService<RadarrSettings> RadarrSettings { get; }
|
||||||
|
private ICacheProvider Cache { get; }
|
||||||
|
private IRadarrApi RadarrApi { get; }
|
||||||
|
private IJobRecord Job { get; }
|
||||||
|
|
||||||
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public void Queued()
|
||||||
|
{
|
||||||
|
var settings = RadarrSettings.GetSettings();
|
||||||
|
if (settings.Enabled)
|
||||||
|
{
|
||||||
|
Job.SetRunning(true, JobNames.RadarrCacher);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var movies = RadarrApi.GetMovies(settings.ApiKey, settings.FullUri);
|
||||||
|
if (movies != null)
|
||||||
|
{
|
||||||
|
var movieIds = new List<int>();
|
||||||
|
foreach (var m in movies)
|
||||||
|
{
|
||||||
|
if (m.tmdbId > 0)
|
||||||
|
{
|
||||||
|
movieIds.Add(m.tmdbId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//var movieIds = movies.Select(x => x.tmdbId).ToList();
|
||||||
|
Cache.Set(CacheKeys.RadarrMovies, movieIds, CacheKeys.TimeFrameMinutes.SchedulerCaching);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failed caching queued items from Radarr");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Job.Record(JobNames.RadarrCacher);
|
||||||
|
Job.SetRunning(false, JobNames.RadarrCacher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we do not want to set here...
|
||||||
|
public int[] QueuedIds()
|
||||||
|
{
|
||||||
|
var retVal = new List<int>();
|
||||||
|
var movies = Cache.Get<List<int>>(CacheKeys.RadarrMovies);
|
||||||
|
if (movies != null)
|
||||||
|
{
|
||||||
|
retVal.AddRange(movies);
|
||||||
|
}
|
||||||
|
return retVal.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
Queued();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -78,7 +78,7 @@ namespace Ombi.Services.Jobs
|
||||||
|
|
||||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Start()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -100,6 +100,10 @@ namespace Ombi.Services.Jobs
|
||||||
JobRecord.SetRunning(false, JobNames.RecentlyAddedEmail);
|
JobRecord.SetRunning(false, JobNames.RecentlyAddedEmail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
public void Test()
|
public void Test()
|
||||||
{
|
{
|
||||||
|
@ -455,7 +459,7 @@ namespace Ombi.Services.Jobs
|
||||||
|
|
||||||
if (!testEmail)
|
if (!testEmail)
|
||||||
{
|
{
|
||||||
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification);
|
var users = UserHelper.GetUsersWithFeature(Features.Newsletter);
|
||||||
if (users != null)
|
if (users != null)
|
||||||
{
|
{
|
||||||
foreach (var user in users)
|
foreach (var user in users)
|
||||||
|
|
|
@ -35,7 +35,7 @@ using Quartz;
|
||||||
|
|
||||||
namespace Ombi.Services.Jobs
|
namespace Ombi.Services.Jobs
|
||||||
{
|
{
|
||||||
public class StoreBackup : IJob
|
public class StoreBackup : IJob, IStoreBackup
|
||||||
{
|
{
|
||||||
public StoreBackup(ISqliteConfiguration sql, IJobRecord rec)
|
public StoreBackup(ISqliteConfiguration sql, IJobRecord rec)
|
||||||
{
|
{
|
||||||
|
@ -48,6 +48,13 @@ namespace Ombi.Services.Jobs
|
||||||
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||||
|
TakeBackup();
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
JobRecord.SetRunning(true, JobNames.CpCacher);
|
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||||
|
|
|
@ -36,7 +36,7 @@ using Quartz;
|
||||||
|
|
||||||
namespace Ombi.Services.Jobs
|
namespace Ombi.Services.Jobs
|
||||||
{
|
{
|
||||||
public class StoreCleanup : IJob
|
public class StoreCleanup : IJob, IStoreCleanup
|
||||||
{
|
{
|
||||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
@ -81,6 +81,11 @@ namespace Ombi.Services.Jobs
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
JobRecord.SetRunning(true, JobNames.CpCacher);
|
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||||
|
|
|
@ -39,7 +39,7 @@ using Quartz;
|
||||||
|
|
||||||
namespace Ombi.Services.Jobs
|
namespace Ombi.Services.Jobs
|
||||||
{
|
{
|
||||||
public class UserRequestLimitResetter : IJob
|
public class UserRequestLimitResetter : IJob, IUserRequestLimitResetter
|
||||||
{
|
{
|
||||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
@ -94,6 +94,31 @@ namespace Ombi.Services.Jobs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
Record.SetRunning(true, JobNames.CpCacher);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = Settings.GetSettings();
|
||||||
|
var users = Repo.GetAll();
|
||||||
|
var requestLimits = users as RequestLimit[] ?? users.ToArray();
|
||||||
|
|
||||||
|
MovieLimit(settings, requestLimits);
|
||||||
|
TvLimit(settings, requestLimits);
|
||||||
|
AlbumLimit(settings, requestLimits);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Record.Record(JobNames.RequestLimitReset);
|
||||||
|
Record.SetRunning(false, JobNames.CpCacher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
Record.SetRunning(true, JobNames.CpCacher);
|
Record.SetRunning(true, JobNames.CpCacher);
|
||||||
|
|
165
Ombi.Services/Notification/DiscordNotification.cs
Normal file
165
Ombi.Services/Notification/DiscordNotification.cs
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: SlackNotification.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.Threading.Tasks;
|
||||||
|
using NLog;
|
||||||
|
using Ombi.Api.Interfaces;
|
||||||
|
using Ombi.Api.Models.Notifications;
|
||||||
|
using Ombi.Core;
|
||||||
|
using Ombi.Core.Models;
|
||||||
|
using Ombi.Core.SettingModels;
|
||||||
|
using Ombi.Services.Interfaces;
|
||||||
|
|
||||||
|
namespace Ombi.Services.Notification
|
||||||
|
{
|
||||||
|
public class DiscordNotification : INotification
|
||||||
|
{
|
||||||
|
public DiscordNotification(IDiscordApi api, ISettingsService<DiscordNotificationSettings> sn)
|
||||||
|
{
|
||||||
|
Api = api;
|
||||||
|
Settings = sn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string NotificationName => "DiscordNotification";
|
||||||
|
|
||||||
|
private IDiscordApi Api { get; }
|
||||||
|
private ISettingsService<DiscordNotificationSettings> Settings { get; }
|
||||||
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
|
||||||
|
public async Task NotifyAsync(NotificationModel model)
|
||||||
|
{
|
||||||
|
var settings = Settings.GetSettings();
|
||||||
|
|
||||||
|
await NotifyAsync(model, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyAsync(NotificationModel model, Settings settings)
|
||||||
|
{
|
||||||
|
if (settings == null) await NotifyAsync(model);
|
||||||
|
|
||||||
|
var pushSettings = (DiscordNotificationSettings)settings;
|
||||||
|
if (!ValidateConfiguration(pushSettings))
|
||||||
|
{
|
||||||
|
Log.Error("Settings for Slack was not correct, we cannot push a notification");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (model.NotificationType)
|
||||||
|
{
|
||||||
|
case NotificationType.NewRequest:
|
||||||
|
await PushNewRequestAsync(model, pushSettings);
|
||||||
|
break;
|
||||||
|
case NotificationType.Issue:
|
||||||
|
await PushIssueAsync(model, pushSettings);
|
||||||
|
break;
|
||||||
|
case NotificationType.RequestAvailable:
|
||||||
|
break;
|
||||||
|
case NotificationType.RequestApproved:
|
||||||
|
break;
|
||||||
|
case NotificationType.AdminNote:
|
||||||
|
break;
|
||||||
|
case NotificationType.Test:
|
||||||
|
await PushTest(pushSettings);
|
||||||
|
break;
|
||||||
|
case NotificationType.RequestDeclined:
|
||||||
|
await PushRequestDeclinedAsync(model, pushSettings);
|
||||||
|
break;
|
||||||
|
case NotificationType.ItemAddedToFaultQueue:
|
||||||
|
await PushFaultQueue(model, pushSettings);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PushNewRequestAsync(NotificationModel model, DiscordNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var message = $"{model.Title} has been requested by user: {model.User}";
|
||||||
|
await Push(settings, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PushRequestDeclinedAsync(NotificationModel model, DiscordNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var message = $"Hello! Your request for {model.Title} has been declined, Sorry!";
|
||||||
|
await Push(settings, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PushIssueAsync(NotificationModel model, DiscordNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}";
|
||||||
|
await Push(settings, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PushTest(DiscordNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!";
|
||||||
|
await Push(settings, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PushFaultQueue(NotificationModel model, DiscordNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var message = $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||||
|
await Push(settings, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Push(DiscordNotificationSettings config, string message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Api.SendMessageAsync(message, config.WebookId, config.Token, config.Username);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ValidateConfiguration(DiscordNotificationSettings settings)
|
||||||
|
{
|
||||||
|
if (!settings.Enabled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(settings.WebhookUrl))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var a = settings.Token;
|
||||||
|
var b = settings.WebookId;
|
||||||
|
}
|
||||||
|
catch (IndexOutOfRangeException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -119,14 +119,6 @@ namespace Ombi.Services.Notification
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!settings.EnableUserEmailNotifications)
|
|
||||||
{
|
|
||||||
if (!settings.Enabled)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,16 +229,12 @@ namespace Ombi.Services.Notification
|
||||||
|
|
||||||
private async Task EmailAvailableRequest(NotificationModel model, EmailNotificationSettings settings)
|
private async Task EmailAvailableRequest(NotificationModel model, EmailNotificationSettings settings)
|
||||||
{
|
{
|
||||||
if (!settings.EnableUserEmailNotifications)
|
|
||||||
{
|
|
||||||
await Task.FromResult(false);
|
|
||||||
}
|
|
||||||
var email = new EmailBasicTemplate();
|
var email = new EmailBasicTemplate();
|
||||||
var html = email.LoadTemplate(
|
var html = email.LoadTemplate(
|
||||||
$"Ombi: {model.Title} is now available!",
|
$"Ombi: {model.Title} is now available!",
|
||||||
$"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)",
|
$"Hello! You requested {model.Title} on Ombi! This is now available on Plex! :)",
|
||||||
model.ImgSrc);
|
model.ImgSrc);
|
||||||
var body = new BodyBuilder { HtmlBody = html, TextBody = $"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)" };
|
var body = new BodyBuilder { HtmlBody = html, TextBody = $"Hello! You requested {model.Title} on Ombi! This is now available on Plex! :)" };
|
||||||
|
|
||||||
var message = new MimeMessage
|
var message = new MimeMessage
|
||||||
{
|
{
|
||||||
|
|
|
@ -98,10 +98,31 @@ namespace Ombi.Services.Notification
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var localUser =
|
UserHelperModel localUser = null;
|
||||||
users.FirstOrDefault( x =>
|
//users.FirstOrDefault( x =>
|
||||||
x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase) ||
|
// x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase) ||
|
||||||
x.UserAlias.Equals(user, StringComparison.CurrentCultureIgnoreCase));
|
// x.UserAlias.Equals(user, StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
|
||||||
|
foreach (var userHelperModel in users)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(userHelperModel.Username))
|
||||||
|
{
|
||||||
|
if (userHelperModel.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
localUser = userHelperModel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(userHelperModel.UserAlias))
|
||||||
|
{
|
||||||
|
if (userHelperModel.UserAlias.Equals(user, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
localUser = userHelperModel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// So if the request was from an alias, then we need to use the local user (since that contains the alias).
|
// So if the request was from an alias, then we need to use the local user (since that contains the alias).
|
||||||
// If we do not have a local user, then we should be using the Plex user if that user exists.
|
// If we do not have a local user, then we should be using the Plex user if that user exists.
|
||||||
|
@ -152,8 +173,36 @@ namespace Ombi.Services.Notification
|
||||||
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification).ToList();
|
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification).ToList();
|
||||||
Log.Debug("Notifying Users Count {0}", users.Count);
|
Log.Debug("Notifying Users Count {0}", users.Count);
|
||||||
|
|
||||||
var selectedUsers = users.Select(x => x.Username).Intersect(model.RequestedUsers, StringComparer.CurrentCultureIgnoreCase);
|
// Get the usernames or alias depending if they have an alias
|
||||||
foreach (var user in selectedUsers)
|
var userNamesWithFeature = users.Select(x => x.UsernameOrAlias).ToList();
|
||||||
|
Log.Debug("Users with the feature count {0}", userNamesWithFeature.Count);
|
||||||
|
Log.Debug("Usernames: ");
|
||||||
|
foreach (var u in userNamesWithFeature)
|
||||||
|
{
|
||||||
|
Log.Debug(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Debug("Users in the requested model count: {0}", model.AllUsers.Count);
|
||||||
|
Log.Debug("usernames from model: ");
|
||||||
|
foreach (var modelAllUser in model.AllUsers)
|
||||||
|
{
|
||||||
|
Log.Debug(modelAllUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model.AllUsers == null || !model.AllUsers.Any())
|
||||||
|
{
|
||||||
|
Log.Debug("There are no users in the model.AllUsers, no users to notify");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var usersToNotify = userNamesWithFeature.Intersect(model.AllUsers, StringComparer.CurrentCultureIgnoreCase).ToList();
|
||||||
|
|
||||||
|
if (!usersToNotify.Any())
|
||||||
|
{
|
||||||
|
Log.Debug("Could not find any users after the .Intersect()");
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Debug("Users being notified for this request count {0}", users.Count);
|
||||||
|
foreach (var user in usersToNotify)
|
||||||
{
|
{
|
||||||
Log.Info("Notifying user {0}", user);
|
Log.Info("Notifying user {0}", user);
|
||||||
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
|
|
@ -86,13 +86,21 @@
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Interfaces\IRadarrCacher.cs" />
|
||||||
<Compile Include="Interfaces\IWatcherCacher.cs" />
|
<Compile Include="Interfaces\IWatcherCacher.cs" />
|
||||||
<Compile Include="Interfaces\IJobRecord.cs" />
|
<Compile Include="Interfaces\IJobRecord.cs" />
|
||||||
<Compile Include="Interfaces\INotificationEngine.cs" />
|
<Compile Include="Interfaces\INotificationEngine.cs" />
|
||||||
|
<Compile Include="Interfaces\IStoreBackup.cs" />
|
||||||
|
<Compile Include="Interfaces\IStoreCleanup.cs" />
|
||||||
|
<Compile Include="Interfaces\IUserRequestLimitResetter.cs" />
|
||||||
|
<Compile Include="Jobs\IFaultQueueHandler.cs" />
|
||||||
|
<Compile Include="Jobs\IPlexEpisodeCacher.cs" />
|
||||||
|
<Compile Include="Jobs\IPlexUserChecker.cs" />
|
||||||
|
<Compile Include="Jobs\RadarrCacher.cs" />
|
||||||
<Compile Include="Jobs\WatcherCacher.cs" />
|
<Compile Include="Jobs\WatcherCacher.cs" />
|
||||||
<Compile Include="Jobs\HtmlTemplateGenerator.cs" />
|
<Compile Include="Jobs\HtmlTemplateGenerator.cs" />
|
||||||
<Compile Include="Jobs\IPlexContentCacher.cs" />
|
<Compile Include="Interfaces\IPlexContentCacher.cs" />
|
||||||
<Compile Include="Jobs\IRecentlyAdded.cs" />
|
<Compile Include="Interfaces\IRecentlyAdded.cs" />
|
||||||
<Compile Include="Jobs\JobRecord.cs" />
|
<Compile Include="Jobs\JobRecord.cs" />
|
||||||
<Compile Include="Jobs\JobNames.cs" />
|
<Compile Include="Jobs\JobNames.cs" />
|
||||||
<Compile Include="Jobs\PlexContentCacher.cs" />
|
<Compile Include="Jobs\PlexContentCacher.cs" />
|
||||||
|
@ -126,6 +134,7 @@
|
||||||
<Compile Include="Notification\NotificationService.cs" />
|
<Compile Include="Notification\NotificationService.cs" />
|
||||||
<Compile Include="Notification\PushoverNotification.cs" />
|
<Compile Include="Notification\PushoverNotification.cs" />
|
||||||
<Compile Include="Notification\PushbulletNotification.cs" />
|
<Compile Include="Notification\PushbulletNotification.cs" />
|
||||||
|
<Compile Include="Notification\DiscordNotification.cs" />
|
||||||
<Compile Include="Notification\SlackNotification.cs" />
|
<Compile Include="Notification\SlackNotification.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using Dapper.Contrib.Extensions;
|
using Dapper.Contrib.Extensions;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Ombi.Store.Models
|
namespace Ombi.Store.Models
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace Ombi.Store.Models
|
||||||
|
|
||||||
public FaultType FaultType { get; set; }
|
public FaultType FaultType { get; set; }
|
||||||
public DateTime? LastRetry { get; set; }
|
public DateTime? LastRetry { get; set; }
|
||||||
public string Message { get; set; }
|
public string Description { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum FaultType
|
public enum FaultType
|
||||||
|
|
|
@ -27,9 +27,6 @@ namespace Ombi.Store
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public bool Approved { get; set; }
|
public bool Approved { get; set; }
|
||||||
|
|
||||||
[Obsolete("Use RequestedUsers")] //TODO remove this obsolete property
|
|
||||||
public string RequestedBy { get; set; }
|
|
||||||
|
|
||||||
public DateTime RequestedDate { get; set; }
|
public DateTime RequestedDate { get; set; }
|
||||||
public bool Available { get; set; }
|
public bool Available { get; set; }
|
||||||
public IssueState Issues { get; set; }
|
public IssueState Issues { get; set; }
|
||||||
|
@ -46,6 +43,13 @@ namespace Ombi.Store
|
||||||
public List<EpisodesModel> Episodes { get; set; }
|
public List<EpisodesModel> Episodes { get; set; }
|
||||||
public bool Denied { get; set; }
|
public bool Denied { get; set; }
|
||||||
public string DeniedReason { get; set; }
|
public string DeniedReason { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// For TV Shows with a custom root folder
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The root folder selected.
|
||||||
|
/// </value>
|
||||||
|
public int RootFolderSelected { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public List<string> AllUsers
|
public List<string> AllUsers
|
||||||
|
@ -53,14 +57,9 @@ namespace Ombi.Store
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var u = new List<string>();
|
var u = new List<string>();
|
||||||
if (!string.IsNullOrEmpty(RequestedBy))
|
if (RequestedUsers != null && RequestedUsers.Any())
|
||||||
{
|
{
|
||||||
u.Add(RequestedBy);
|
u.AddRange(RequestedUsers);
|
||||||
}
|
|
||||||
|
|
||||||
if (RequestedUsers.Any())
|
|
||||||
{
|
|
||||||
u.AddRange(RequestedUsers.Where(requestedUser => requestedUser != RequestedBy));
|
|
||||||
}
|
}
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ using Ombi.Api.Interfaces;
|
||||||
using Ombi.Api.Models.Sonarr;
|
using Ombi.Api.Models.Sonarr;
|
||||||
using Ombi.Core;
|
using Ombi.Core;
|
||||||
using Ombi.Core.SettingModels;
|
using Ombi.Core.SettingModels;
|
||||||
|
using Ombi.Helpers;
|
||||||
using Ombi.Store;
|
using Ombi.Store;
|
||||||
using Ploeh.AutoFixture;
|
using Ploeh.AutoFixture;
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@ namespace Ombi.UI.Tests
|
||||||
|
|
||||||
private TvSender Sender { get; set; }
|
private TvSender Sender { get; set; }
|
||||||
private Fixture F { get; set; }
|
private Fixture F { get; set; }
|
||||||
|
private Mock<ICacheProvider> Cache { get; set; }
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
|
@ -56,7 +58,8 @@ namespace Ombi.UI.Tests
|
||||||
F = new Fixture();
|
F = new Fixture();
|
||||||
SonarrMock = new Mock<ISonarrApi>();
|
SonarrMock = new Mock<ISonarrApi>();
|
||||||
SickrageMock = new Mock<ISickRageApi>();
|
SickrageMock = new Mock<ISickRageApi>();
|
||||||
Sender = new TvSender(SonarrMock.Object, SickrageMock.Object);
|
Cache = new Mock<ICacheProvider>();
|
||||||
|
Sender = new TvSender(SonarrMock.Object, SickrageMock.Object, Cache.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -66,7 +69,7 @@ namespace Ombi.UI.Tests
|
||||||
var seriesResult = new SonarrAddSeries() { title = "ABC"};
|
var seriesResult = new SonarrAddSeries() { title = "ABC"};
|
||||||
SonarrMock.Setup(x => x.GetSeries(It.IsAny<string>(), It.IsAny<Uri>())).Returns(F.Build<Series>().With(x => x.tvdbId, 1).With(x => x.title, "ABC").CreateMany().ToList());
|
SonarrMock.Setup(x => x.GetSeries(It.IsAny<string>(), It.IsAny<Uri>())).Returns(F.Build<Series>().With(x => x.tvdbId, 1).With(x => x.title, "ABC").CreateMany().ToList());
|
||||||
|
|
||||||
Sender = new TvSender(SonarrMock.Object, SickrageMock.Object);
|
Sender = new TvSender(SonarrMock.Object, SickrageMock.Object, Cache.Object);
|
||||||
|
|
||||||
var request = new RequestedModel {SeasonsRequested = "All", ProviderId = 1, Title = "ABC"};
|
var request = new RequestedModel {SeasonsRequested = "All", ProviderId = 1, Title = "ABC"};
|
||||||
|
|
||||||
|
@ -116,7 +119,7 @@ namespace Ombi.UI.Tests
|
||||||
SonarrMock.Setup(x => x.GetEpisodes(It.IsAny<string>(), It.IsAny<string>(),
|
SonarrMock.Setup(x => x.GetEpisodes(It.IsAny<string>(), It.IsAny<string>(),
|
||||||
It.IsAny<Uri>())).Returns(F.CreateMany<SonarrEpisodes>());
|
It.IsAny<Uri>())).Returns(F.CreateMany<SonarrEpisodes>());
|
||||||
|
|
||||||
Sender = new TvSender(SonarrMock.Object, SickrageMock.Object);
|
Sender = new TvSender(SonarrMock.Object, SickrageMock.Object, Cache.Object);
|
||||||
var episodes = new List<EpisodesModel>
|
var episodes = new List<EpisodesModel>
|
||||||
{
|
{
|
||||||
new EpisodesModel
|
new EpisodesModel
|
||||||
|
|
8
Ombi.UI/Content/base.css
vendored
8
Ombi.UI/Content/base.css
vendored
|
@ -509,3 +509,11 @@ label {
|
||||||
background-position: center;
|
background-position: center;
|
||||||
position: absolute; }
|
position: absolute; }
|
||||||
|
|
||||||
|
.list-group-item-dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
padding: 10px 15px;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
background-color: #3e3e3e;
|
||||||
|
border: 1px solid transparent; }
|
||||||
|
|
||||||
|
|
2
Ombi.UI/Content/base.min.css
vendored
2
Ombi.UI/Content/base.min.css
vendored
File diff suppressed because one or more lines are too long
|
@ -632,3 +632,13 @@ $border-radius: 10px;
|
||||||
background-position:center;
|
background-position:center;
|
||||||
position:absolute;
|
position:absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.list-group-item-dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
padding: 10px 15px;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
background-color: #3e3e3e;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
1
Ombi.UI/Content/bootstrap.css
vendored
1
Ombi.UI/Content/bootstrap.css
vendored
|
@ -5259,6 +5259,7 @@ a.thumbnail.active {
|
||||||
background-color: #4e5d6c;
|
background-color: #4e5d6c;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-group-item:first-child {
|
.list-group-item:first-child {
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
|
|
53
Ombi.UI/Content/requests.js
vendored
53
Ombi.UI/Content/requests.js
vendored
|
@ -559,6 +559,25 @@ $(document).on("click", ".approve-with-quality", function (e) {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Change root folder
|
||||||
|
$(document).on("click", ".change-root-folder", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var $this = $(this);
|
||||||
|
var $button = $this.parents('.btn-split').children('.change').first();
|
||||||
|
var rootFolderId = e.target.id
|
||||||
|
var $form = $this.parents('form').first();
|
||||||
|
|
||||||
|
if ($button.text() === " Loading...") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingButton($button.attr('id'), "success");
|
||||||
|
|
||||||
|
changeRootFolder($form, rootFolderId, function () {
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Change Availability
|
// Change Availability
|
||||||
$(document).on("click", ".change", function (e) {
|
$(document).on("click", ".change", function (e) {
|
||||||
|
@ -638,6 +657,37 @@ function approveRequest($form, qualityId, successCallback) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeRootFolder($form, rootFolderId, successCallback) {
|
||||||
|
|
||||||
|
var formData = $form.serialize();
|
||||||
|
if (rootFolderId) formData += ("&rootFolderId=" + rootFolderId);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: $form.prop('method'),
|
||||||
|
url: $form.prop('action'),
|
||||||
|
data: formData,
|
||||||
|
dataType: "json",
|
||||||
|
success: function (response) {
|
||||||
|
|
||||||
|
if (checkJsonResponse(response)) {
|
||||||
|
if (response.message) {
|
||||||
|
generateNotify(response.message, "success");
|
||||||
|
} else {
|
||||||
|
generateNotify("Success! Changed Root Path.", "success");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (successCallback) {
|
||||||
|
successCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
console.log(e);
|
||||||
|
generateNotify("Something went wrong!", "danger");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function denyRequest($form, successCallback) {
|
function denyRequest($form, successCallback) {
|
||||||
|
|
||||||
var formData = $form.serialize();
|
var formData = $form.serialize();
|
||||||
|
@ -808,6 +858,9 @@ function buildRequestContext(result, type) {
|
||||||
musicBrainzId: result.musicBrainzId,
|
musicBrainzId: result.musicBrainzId,
|
||||||
denied: result.denied,
|
denied: result.denied,
|
||||||
deniedReason: result.deniedReason,
|
deniedReason: result.deniedReason,
|
||||||
|
hasRootFolders: result.hasRootFolders,
|
||||||
|
rootFolders: result.rootFolders,
|
||||||
|
currentRootPath : result.currentRootPath
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
87
Ombi.UI/Content/search.js
vendored
87
Ombi.UI/Content/search.js
vendored
|
@ -24,7 +24,8 @@ Function.prototype.bind = function (parent) {
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
||||||
var searchSource = $("#search-template").html();
|
var useNewSearch = $('#useNewSearch').text() == 'True';
|
||||||
|
var searchSource = useNewSearch ? $("#search-templateNew").html() : $("#search-template").html();
|
||||||
var seasonsSource = $("#seasons-template").html();
|
var seasonsSource = $("#seasons-template").html();
|
||||||
var musicSource = $("#music-template").html();
|
var musicSource = $("#music-template").html();
|
||||||
var seasonsNumberSource = $("#seasonNumber-template").html();
|
var seasonsNumberSource = $("#seasonNumber-template").html();
|
||||||
|
@ -72,6 +73,25 @@ $(function () {
|
||||||
moviesInTheaters();
|
moviesInTheaters();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TV DropDown
|
||||||
|
$('#popularShows').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
popularShows();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#trendingShows').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
trendingTv();
|
||||||
|
});
|
||||||
|
$('#mostWatchedShows').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
mostwatchedTv();
|
||||||
|
});
|
||||||
|
$('#anticipatedShows').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
anticipatedTv();
|
||||||
|
});
|
||||||
|
|
||||||
// Type in TV search
|
// Type in TV search
|
||||||
$("#tvSearchContent").on("input", function () {
|
$("#tvSearchContent").on("input", function () {
|
||||||
if (searchTimer) {
|
if (searchTimer) {
|
||||||
|
@ -293,6 +313,23 @@ $(function () {
|
||||||
getMovies(url);
|
getMovies(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function popularShows() {
|
||||||
|
var url = createBaseUrl(base, '/search/tv/popular');
|
||||||
|
getTvShows(url, true);
|
||||||
|
}
|
||||||
|
function anticipatedTv() {
|
||||||
|
var url = createBaseUrl(base, '/search/tv/anticipated');
|
||||||
|
getTvShows(url, true);
|
||||||
|
}
|
||||||
|
function trendingTv() {
|
||||||
|
var url = createBaseUrl(base, '/search/tv/trending');
|
||||||
|
getTvShows(url, true);
|
||||||
|
}
|
||||||
|
function mostwatchedTv() {
|
||||||
|
var url = createBaseUrl(base, '/search/tv/mostwatched');
|
||||||
|
getTvShows(url, true);
|
||||||
|
}
|
||||||
|
|
||||||
function getMovies(url) {
|
function getMovies(url) {
|
||||||
resetMovies();
|
resetMovies();
|
||||||
|
|
||||||
|
@ -304,6 +341,8 @@ $(function () {
|
||||||
|
|
||||||
var html = searchTemplate(context);
|
var html = searchTemplate(context);
|
||||||
$("#movieList").append(html);
|
$("#movieList").append(html);
|
||||||
|
|
||||||
|
checkNetflix(context.title, context.id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -321,10 +360,10 @@ $(function () {
|
||||||
var query = $("#tvSearchContent").val();
|
var query = $("#tvSearchContent").val();
|
||||||
|
|
||||||
var url = createBaseUrl(base, '/search/tv/');
|
var url = createBaseUrl(base, '/search/tv/');
|
||||||
query ? getTvShows(url + query) : resetTvShows();
|
query ? getTvShows(url + query, false) : resetTvShows();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTvShows(url) {
|
function getTvShows(url, loadImage) {
|
||||||
resetTvShows();
|
resetTvShows();
|
||||||
|
|
||||||
$('#tvSearchButton').attr("class", "fa fa-spinner fa-spin");
|
$('#tvSearchButton').attr("class", "fa fa-spinner fa-spin");
|
||||||
|
@ -334,6 +373,11 @@ $(function () {
|
||||||
var context = buildTvShowContext(result);
|
var context = buildTvShowContext(result);
|
||||||
var html = searchTemplate(context);
|
var html = searchTemplate(context);
|
||||||
$("#tvList").append(html);
|
$("#tvList").append(html);
|
||||||
|
|
||||||
|
checkNetflix(context.title, context.id);
|
||||||
|
if (loadImage) {
|
||||||
|
getTvPoster(result.id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -343,6 +387,19 @@ $(function () {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function checkNetflix(title, id) {
|
||||||
|
var url = createBaseUrl(base, '/searchextension/netflix/' + title);
|
||||||
|
$.ajax(url).success(function (results) {
|
||||||
|
|
||||||
|
if (results.result) {
|
||||||
|
// It's on Netflix
|
||||||
|
$('#' + id + 'netflixTab')
|
||||||
|
.html("<a href='https://www.netflix.com/watch/"+results.netflixId+"' target='_blank'><span class='label label-success'>Avaialble on Netflix</span></a>");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function resetTvShows() {
|
function resetTvShows() {
|
||||||
$("#tvList").html("");
|
$("#tvList").html("");
|
||||||
}
|
}
|
||||||
|
@ -388,6 +445,16 @@ $(function () {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getTvPoster(theTvDbId) {
|
||||||
|
|
||||||
|
var url = createBaseUrl(base, '/search/tv/poster/');
|
||||||
|
$.ajax(url + theTvDbId).success(function (result) {
|
||||||
|
if (result) {
|
||||||
|
$('#' + theTvDbId + "imgDiv").html(" <img class='img-responsive' src='" + result + "' width='150' alt='poster'>");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
function buildMovieContext(result) {
|
function buildMovieContext(result) {
|
||||||
var date = new Date(result.releaseDate);
|
var date = new Date(result.releaseDate);
|
||||||
var year = date.getFullYear();
|
var year = date.getFullYear();
|
||||||
|
@ -404,7 +471,11 @@ $(function () {
|
||||||
requested: result.requested,
|
requested: result.requested,
|
||||||
approved: result.approved,
|
approved: result.approved,
|
||||||
available: result.available,
|
available: result.available,
|
||||||
url: result.plexUrl
|
url: result.plexUrl,
|
||||||
|
trailer: result.trailer,
|
||||||
|
homepage: result.homepage,
|
||||||
|
releaseDate: Humanize(result.releaseDate),
|
||||||
|
status: result.status
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
@ -414,6 +485,7 @@ $(function () {
|
||||||
var date = new Date(result.firstAired);
|
var date = new Date(result.firstAired);
|
||||||
var year = date.getFullYear();
|
var year = date.getFullYear();
|
||||||
var context = {
|
var context = {
|
||||||
|
status: result.status,
|
||||||
posterPath: result.banner,
|
posterPath: result.banner,
|
||||||
id: result.id,
|
id: result.id,
|
||||||
title: result.seriesName,
|
title: result.seriesName,
|
||||||
|
@ -430,8 +502,11 @@ $(function () {
|
||||||
tvPartialAvailable: result.tvPartialAvailable,
|
tvPartialAvailable: result.tvPartialAvailable,
|
||||||
disableTvRequestsByEpisode: result.disableTvRequestsByEpisode,
|
disableTvRequestsByEpisode: result.disableTvRequestsByEpisode,
|
||||||
disableTvRequestsBySeason: result.disableTvRequestsBySeason,
|
disableTvRequestsBySeason: result.disableTvRequestsBySeason,
|
||||||
enableTvRequestsForOnlySeries: result.enableTvRequestsForOnlySeries
|
enableTvRequestsForOnlySeries: result.enableTvRequestsForOnlySeries,
|
||||||
};
|
trailer: result.trailer,
|
||||||
|
homepage: result.homepage,
|
||||||
|
firstAired: Humanize(result.firstAired)
|
||||||
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
15
Ombi.UI/Content/site.js
vendored
15
Ombi.UI/Content/site.js
vendored
|
@ -8,7 +8,7 @@
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(function() {
|
$(function () {
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -93,6 +93,19 @@ function createBaseUrl(base, url) {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createLocalUrl(url) {
|
||||||
|
var base = $('#baseUrl').text();
|
||||||
|
if (base) {
|
||||||
|
if (url.charAt(0) === "/") {
|
||||||
|
url = "/" + base + url;
|
||||||
|
} else {
|
||||||
|
url = "/" + base + "/" + url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
var noResultsHtml = "<div class='no-search-results'>" +
|
var noResultsHtml = "<div class='no-search-results'>" +
|
||||||
"<i class='fa fa-film no-search-results-icon'></i><div class='no-search-results-text'>Sorry, we didn't find any results!</div></div>";
|
"<i class='fa fa-film no-search-results-icon'></i><div class='no-search-results-text'>Sorry, we didn't find any results!</div></div>";
|
||||||
var noResultsMusic = "<div class='no-search-results'>" +
|
var noResultsMusic = "<div class='no-search-results'>" +
|
||||||
|
|
41
Ombi.UI/Content/systemjs.config.js
vendored
Normal file
41
Ombi.UI/Content/systemjs.config.js
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* System configuration for Angular 2 samples
|
||||||
|
* Adjust as necessary for your application needs.
|
||||||
|
*/
|
||||||
|
(function (global) {
|
||||||
|
System.config({
|
||||||
|
paths: {
|
||||||
|
// paths serve as alias
|
||||||
|
'npm:': '../node_modules/',
|
||||||
|
'app' : '../app/'
|
||||||
|
},
|
||||||
|
// map tells the System loader where to look for things
|
||||||
|
map: {
|
||||||
|
// our app is within the app folder
|
||||||
|
app: 'app',
|
||||||
|
|
||||||
|
// angular bundles
|
||||||
|
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
|
||||||
|
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
|
||||||
|
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
|
||||||
|
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
|
||||||
|
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
|
||||||
|
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
|
||||||
|
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
|
||||||
|
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
|
||||||
|
|
||||||
|
// other libraries
|
||||||
|
'rxjs': 'npm:rxjs'
|
||||||
|
},
|
||||||
|
// packages tells the System loader how to load when no filename and/or no extension
|
||||||
|
packages: {
|
||||||
|
app: {
|
||||||
|
main: './main.js',
|
||||||
|
defaultExtension: 'js'
|
||||||
|
},
|
||||||
|
rxjs: {
|
||||||
|
defaultExtension: 'js'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})(this);
|
|
@ -199,7 +199,7 @@ namespace Ombi.UI.Helpers
|
||||||
var assetLocation = GetBaseUrl();
|
var assetLocation = GetBaseUrl();
|
||||||
|
|
||||||
var content = GetContentUrl(assetLocation);
|
var content = GetContentUrl(assetLocation);
|
||||||
|
|
||||||
sb.AppendLine($"<script src=\"{content}/Content/wizard.js?v={Assembly}\" type=\"text/javascript\"></script>");
|
sb.AppendLine($"<script src=\"{content}/Content/wizard.js?v={Assembly}\" type=\"text/javascript\"></script>");
|
||||||
|
|
||||||
return helper.Raw(sb.ToString());
|
return helper.Raw(sb.ToString());
|
||||||
|
@ -226,9 +226,9 @@ namespace Ombi.UI.Helpers
|
||||||
sb.Append($"<script src=\"{content}/Content/app/userManagement/userManagementService.js?v={Assembly}\" type=\"text/javascript\"></script>");
|
sb.Append($"<script src=\"{content}/Content/app/userManagement/userManagementService.js?v={Assembly}\" type=\"text/javascript\"></script>");
|
||||||
sb.Append($"<script src=\"{content}/Content/app/userManagement/Directives/userManagementDirective.js?v={Assembly}\" type=\"text/javascript\"></script>");
|
sb.Append($"<script src=\"{content}/Content/app/userManagement/Directives/userManagementDirective.js?v={Assembly}\" type=\"text/javascript\"></script>");
|
||||||
sb.Append($"<script src=\"{content}/Content/moment.min.js\"></script>");
|
sb.Append($"<script src=\"{content}/Content/moment.min.js\"></script>");
|
||||||
sb.Append($"<script src=\"{content}/Content/spin.min.js\"></script>");
|
sb.Append($"<script src=\"{content}/Content/spin.min.js\"></script>");
|
||||||
sb.Append($"<script src=\"{content}/Content/Angular/angular-spinner.min.js\"></script>");
|
sb.Append($"<script src=\"{content}/Content/Angular/angular-spinner.min.js\"></script>");
|
||||||
sb.Append($"<script src=\"{content}/Content/Angular/angular-loading-spinner.js\"></script>");
|
sb.Append($"<script src=\"{content}/Content/Angular/angular-loading-spinner.js\"></script>");
|
||||||
|
|
||||||
return helper.Raw(sb.ToString());
|
return helper.Raw(sb.ToString());
|
||||||
}
|
}
|
||||||
|
@ -290,16 +290,19 @@ namespace Ombi.UI.Helpers
|
||||||
return helper.Raw(asset);
|
return helper.Raw(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IHtmlString GetSidebarUrl(this HtmlHelpers helper, NancyContext context, string url, string title)
|
public static IHtmlString GetSidebarUrl(this HtmlHelpers helper, NancyContext context, string url, string title, string icon = null)
|
||||||
{
|
{
|
||||||
var content = GetLinkUrl(GetBaseUrl());
|
var content = GetLinkUrl(GetBaseUrl());
|
||||||
if (!string.IsNullOrEmpty(content))
|
if (!string.IsNullOrEmpty(content))
|
||||||
{
|
{
|
||||||
url = $"/{content}{url}";
|
url = $"/{content}{url}";
|
||||||
}
|
}
|
||||||
var returnString = context.Request.Path == url
|
|
||||||
? $"<a class=\"list-group-item active\" href=\"{url}\">{title}</a>"
|
|
||||||
: $"<a class=\"list-group-item\" href=\"{url}\">{title}</a>";
|
var iconHtml = string.IsNullOrEmpty(icon) ? "" : $"<span style=\"font-size:16px; \" class=\"pull-right hidden-xs showopacity {icon}\"></span>";
|
||||||
|
var returnString = context.Request.Path == url
|
||||||
|
? $"<a class=\"list-group-item active\" href=\"{url}\">{title} {iconHtml}</a>"
|
||||||
|
: $"<a class=\"list-group-item\" href=\"{url}\">{title} {iconHtml}</a>";
|
||||||
|
|
||||||
return helper.Raw(returnString);
|
return helper.Raw(returnString);
|
||||||
}
|
}
|
||||||
|
@ -311,8 +314,8 @@ namespace Ombi.UI.Helpers
|
||||||
{
|
{
|
||||||
url = $"/{content}{url}";
|
url = $"/{content}{url}";
|
||||||
}
|
}
|
||||||
var returnString = context.Request.Path == url ?
|
var returnString = context.Request.Path == url ?
|
||||||
$"<li class=\"active\"><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title}</a></li>"
|
$"<li class=\"active\"><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title}</a></li>"
|
||||||
: $"<li><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title}</a></li>";
|
: $"<li><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title}</a></li>";
|
||||||
|
|
||||||
return helper.Raw(returnString);
|
return helper.Raw(returnString);
|
||||||
|
@ -326,8 +329,8 @@ namespace Ombi.UI.Helpers
|
||||||
url = $"/{content}{url}";
|
url = $"/{content}{url}";
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnString = context.Request.Path == url
|
var returnString = context.Request.Path == url
|
||||||
? $"<li class=\"active\"><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title} {extraHtml}</a></li>"
|
? $"<li class=\"active\"><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title} {extraHtml}</a></li>"
|
||||||
: $"<li><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title} {extraHtml}</a></li>";
|
: $"<li><a href=\"{url}\"><i class=\"fa fa-{fontIcon}\"></i> {title} {extraHtml}</a></li>";
|
||||||
|
|
||||||
return helper.Raw(returnString);
|
return helper.Raw(returnString);
|
||||||
|
|
|
@ -75,6 +75,7 @@ namespace Ombi.UI.Jobs
|
||||||
JobBuilder.Create<UserRequestLimitResetter>().WithIdentity("UserRequestLimiter", "Request").Build(),
|
JobBuilder.Create<UserRequestLimitResetter>().WithIdentity("UserRequestLimiter", "Request").Build(),
|
||||||
JobBuilder.Create<RecentlyAdded>().WithIdentity("RecentlyAddedModel", "Email").Build(),
|
JobBuilder.Create<RecentlyAdded>().WithIdentity("RecentlyAddedModel", "Email").Build(),
|
||||||
JobBuilder.Create<FaultQueueHandler>().WithIdentity("FaultQueueHandler", "Fault").Build(),
|
JobBuilder.Create<FaultQueueHandler>().WithIdentity("FaultQueueHandler", "Fault").Build(),
|
||||||
|
JobBuilder.Create<RadarrCacher>().WithIdentity("RadarrCacher", "Cache").Build(),
|
||||||
};
|
};
|
||||||
|
|
||||||
jobs.AddRange(jobList);
|
jobs.AddRange(jobList);
|
||||||
|
@ -170,6 +171,10 @@ namespace Ombi.UI.Jobs
|
||||||
{
|
{
|
||||||
s.PlexUserChecker = 24;
|
s.PlexUserChecker = 24;
|
||||||
}
|
}
|
||||||
|
if (s.RadarrCacher == 0)
|
||||||
|
{
|
||||||
|
s.RadarrCacher = 60;
|
||||||
|
}
|
||||||
|
|
||||||
var triggers = new List<ITrigger>();
|
var triggers = new List<ITrigger>();
|
||||||
|
|
||||||
|
@ -222,6 +227,14 @@ namespace Ombi.UI.Jobs
|
||||||
.WithSimpleSchedule(x => x.WithIntervalInMinutes(s.WatcherCacher).RepeatForever())
|
.WithSimpleSchedule(x => x.WithIntervalInMinutes(s.WatcherCacher).RepeatForever())
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
var radarrCacher =
|
||||||
|
TriggerBuilder.Create()
|
||||||
|
.WithIdentity("RadarrCacher", "Cache")
|
||||||
|
.StartNow()
|
||||||
|
//.StartAt(DateBuilder.FutureDate(2, IntervalUnit.Minute))
|
||||||
|
.WithSimpleSchedule(x => x.WithIntervalInMinutes(s.RadarrCacher).RepeatForever())
|
||||||
|
.Build();
|
||||||
|
|
||||||
var storeBackup =
|
var storeBackup =
|
||||||
TriggerBuilder.Create()
|
TriggerBuilder.Create()
|
||||||
.WithIdentity("StoreBackup", "Database")
|
.WithIdentity("StoreBackup", "Database")
|
||||||
|
@ -280,6 +293,7 @@ namespace Ombi.UI.Jobs
|
||||||
triggers.Add(fault);
|
triggers.Add(fault);
|
||||||
triggers.Add(plexCacher);
|
triggers.Add(plexCacher);
|
||||||
triggers.Add(plexUserChecker);
|
triggers.Add(plexUserChecker);
|
||||||
|
triggers.Add(radarrCacher);
|
||||||
|
|
||||||
return triggers;
|
return triggers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace Ombi.UI.ModelDataProviders
|
||||||
with.Property(x => x.QualityProfile).Description("Sonarr's quality profile").Required(true);
|
with.Property(x => x.QualityProfile).Description("Sonarr's quality profile").Required(true);
|
||||||
|
|
||||||
with.Property(x => x.SeasonFolders).Description("Sonarr's season folders").Required(false);
|
with.Property(x => x.SeasonFolders).Description("Sonarr's season folders").Required(false);
|
||||||
|
|
||||||
with.Property(x => x.RootPath).Description("Sonarr's root path").Required(false);
|
with.Property(x => x.RootPath).Description("Sonarr's root path").Required(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,5 +58,8 @@ namespace Ombi.UI.Models
|
||||||
public Store.EpisodesModel[] Episodes { get; set; }
|
public Store.EpisodesModel[] Episodes { get; set; }
|
||||||
public bool Denied { get; set; }
|
public bool Denied { get; set; }
|
||||||
public string DeniedReason { get; set; }
|
public string DeniedReason { get; set; }
|
||||||
|
public RootFolderModel[] RootFolders { get; set; }
|
||||||
|
public bool HasRootFolders { get; set; }
|
||||||
|
public string CurrentRootPath { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
36
Ombi.UI/Models/RootFolderModel.cs
Normal file
36
Ombi.UI/Models/RootFolderModel.cs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: RootFolderModel.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
|
||||||
|
namespace Ombi.UI.Models
|
||||||
|
{
|
||||||
|
|
||||||
|
public class RootFolderModel
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Path { get; set; }
|
||||||
|
public long FreeSpace { get; set; }
|
||||||
|
}
|
||||||
|
}
|
37
Ombi.UI/Models/SearchLoadViewModel.cs
Normal file
37
Ombi.UI/Models/SearchLoadViewModel.cs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: SearchLoadViewModel.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 Ombi.Core.SettingModels;
|
||||||
|
|
||||||
|
namespace Ombi.UI.Models
|
||||||
|
{
|
||||||
|
public class SearchLoadViewModel
|
||||||
|
{
|
||||||
|
public PlexRequestSettings Settings { get; set; }
|
||||||
|
public CustomizationSettings CustomizationSettings { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,5 +47,8 @@ namespace Ombi.UI.Models
|
||||||
public double VoteAverage { get; set; }
|
public double VoteAverage { get; set; }
|
||||||
public int VoteCount { get; set; }
|
public int VoteCount { get; set; }
|
||||||
public bool AlreadyInCp { get; set; }
|
public bool AlreadyInCp { get; set; }
|
||||||
|
public string Trailer { get; set; }
|
||||||
|
public string Homepage { get; set; }
|
||||||
|
public string ImdbId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -58,5 +58,20 @@ namespace Ombi.UI.Models
|
||||||
public bool DisableTvRequestsByEpisode { get; set; }
|
public bool DisableTvRequestsByEpisode { get; set; }
|
||||||
public bool DisableTvRequestsBySeason { get; set; }
|
public bool DisableTvRequestsBySeason { get; set; }
|
||||||
public bool EnableTvRequestsForOnlySeries { get; set; }
|
public bool EnableTvRequestsForOnlySeries { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used from the Trakt API
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The trailer.
|
||||||
|
/// </value>
|
||||||
|
public string Trailer { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// This is used from the Trakt API
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The trailer.
|
||||||
|
/// </value>
|
||||||
|
public string Homepage { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -93,6 +93,10 @@ namespace Ombi.UI.Modules.Admin
|
||||||
private IAnalytics Analytics { get; }
|
private IAnalytics Analytics { get; }
|
||||||
private IRecentlyAdded RecentlyAdded { get; }
|
private IRecentlyAdded RecentlyAdded { get; }
|
||||||
private ISettingsService<NotificationSettingsV2> NotifySettings { get; }
|
private ISettingsService<NotificationSettingsV2> NotifySettings { get; }
|
||||||
|
private ISettingsService<DiscordNotificationSettings> DiscordSettings { get; }
|
||||||
|
private IDiscordApi DiscordApi { get; }
|
||||||
|
private ISettingsService<RadarrSettings> RadarrSettings { get; }
|
||||||
|
private IRadarrApi RadarrApi { get; }
|
||||||
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
public AdminModule(ISettingsService<PlexRequestSettings> prService,
|
public AdminModule(ISettingsService<PlexRequestSettings> prService,
|
||||||
|
@ -118,7 +122,9 @@ namespace Ombi.UI.Modules.Admin
|
||||||
ISlackApi slackApi, ISettingsService<LandingPageSettings> lp,
|
ISlackApi slackApi, ISettingsService<LandingPageSettings> lp,
|
||||||
ISettingsService<ScheduledJobsSettings> scheduler, IJobRecord rec, IAnalytics analytics,
|
ISettingsService<ScheduledJobsSettings> scheduler, IJobRecord rec, IAnalytics analytics,
|
||||||
ISettingsService<NotificationSettingsV2> notifyService, IRecentlyAdded recentlyAdded,
|
ISettingsService<NotificationSettingsV2> notifyService, IRecentlyAdded recentlyAdded,
|
||||||
ISettingsService<WatcherSettings> watcherSettings
|
ISettingsService<WatcherSettings> watcherSettings ,
|
||||||
|
ISettingsService<DiscordNotificationSettings> discord,
|
||||||
|
IDiscordApi discordapi, ISettingsService<RadarrSettings> settings, IRadarrApi radarrApi
|
||||||
, ISecurityExtensions security) : base("admin", prService, security)
|
, ISecurityExtensions security) : base("admin", prService, security)
|
||||||
{
|
{
|
||||||
PrService = prService;
|
PrService = prService;
|
||||||
|
@ -150,6 +156,10 @@ namespace Ombi.UI.Modules.Admin
|
||||||
NotifySettings = notifyService;
|
NotifySettings = notifyService;
|
||||||
RecentlyAdded = recentlyAdded;
|
RecentlyAdded = recentlyAdded;
|
||||||
WatcherSettings = watcherSettings;
|
WatcherSettings = watcherSettings;
|
||||||
|
DiscordSettings = discord;
|
||||||
|
DiscordApi = discordapi;
|
||||||
|
RadarrSettings = settings;
|
||||||
|
RadarrApi = radarrApi;
|
||||||
|
|
||||||
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
|
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
|
||||||
|
|
||||||
|
@ -165,18 +175,19 @@ namespace Ombi.UI.Modules.Admin
|
||||||
Get["/getusers"] = _ => GetUsers();
|
Get["/getusers"] = _ => GetUsers();
|
||||||
|
|
||||||
Get["/couchpotato"] = _ => CouchPotato();
|
Get["/couchpotato"] = _ => CouchPotato();
|
||||||
Post["/couchpotato"] = _ => SaveCouchPotato();
|
Post["/couchpotato", true] = async (x, ct) => await SaveCouchPotato();
|
||||||
|
|
||||||
Get["/plex"] = _ => Plex();
|
Get["/plex"] = _ => Plex();
|
||||||
Post["/plex", true] = async (x, ct) => await SavePlex();
|
Post["/plex", true] = async (x, ct) => await SavePlex();
|
||||||
|
|
||||||
Get["/sonarr"] = _ => Sonarr();
|
Get["/sonarr"] = _ => Sonarr();
|
||||||
Post["/sonarr"] = _ => SaveSonarr();
|
Post["/sonarr"] = _ => SaveSonarr();
|
||||||
|
Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles();
|
||||||
|
|
||||||
|
|
||||||
Get["/sickrage"] = _ => Sickrage();
|
Get["/sickrage"] = _ => Sickrage();
|
||||||
Post["/sickrage"] = _ => SaveSickrage();
|
Post["/sickrage"] = _ => SaveSickrage();
|
||||||
|
|
||||||
Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles();
|
|
||||||
Post["/cpprofiles", true] = async (x, ct) => await GetCpProfiles();
|
Post["/cpprofiles", true] = async (x, ct) => await GetCpProfiles();
|
||||||
Post["/cpapikey"] = x => GetCpApiKey();
|
Post["/cpapikey"] = x => GetCpApiKey();
|
||||||
|
|
||||||
|
@ -200,18 +211,21 @@ namespace Ombi.UI.Modules.Admin
|
||||||
Get["/headphones"] = _ => Headphones();
|
Get["/headphones"] = _ => Headphones();
|
||||||
Post["/headphones"] = _ => SaveHeadphones();
|
Post["/headphones"] = _ => SaveHeadphones();
|
||||||
|
|
||||||
Get["/newsletter"] = _ => Newsletter();
|
Get["/newsletter", true] = async (x, ct) => await Newsletter();
|
||||||
Post["/newsletter"] = _ => SaveNewsletter();
|
Post["/newsletter", true] = async (x, ct) => await SaveNewsletter();
|
||||||
|
|
||||||
Post["/createapikey"] = x => CreateApiKey();
|
Post["/createapikey"] = x => CreateApiKey();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Post["/testslacknotification", true] = async (x, ct) => await TestSlackNotification();
|
Post["/testslacknotification", true] = async (x, ct) => await TestSlackNotification();
|
||||||
|
|
||||||
Get["/slacknotification"] = _ => SlackNotifications();
|
Get["/slacknotification"] = _ => SlackNotifications();
|
||||||
Post["/slacknotification"] = _ => SaveSlackNotifications();
|
Post["/slacknotification"] = _ => SaveSlackNotifications();
|
||||||
|
|
||||||
|
Post["/testdiscordnotification", true] = async (x, ct) => await TestDiscordNotification();
|
||||||
|
Get["/discordnotification", true] = async (x, ct) => await DiscordNotification();
|
||||||
|
Post["/discordnotification", true] = async (x, ct) => await SaveDiscordNotifications();
|
||||||
|
|
||||||
Get["/landingpage", true] = async (x, ct) => await LandingPage();
|
Get["/landingpage", true] = async (x, ct) => await LandingPage();
|
||||||
Post["/landingpage", true] = async (x, ct) => await SaveLandingPage();
|
Post["/landingpage", true] = async (x, ct) => await SaveLandingPage();
|
||||||
|
|
||||||
|
@ -368,7 +382,7 @@ namespace Ombi.UI.Modules.Admin
|
||||||
return View["CouchPotato", settings];
|
return View["CouchPotato", settings];
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response SaveCouchPotato()
|
private async Task<Response> SaveCouchPotato()
|
||||||
{
|
{
|
||||||
var couchPotatoSettings = this.Bind<CouchPotatoSettings>();
|
var couchPotatoSettings = this.Bind<CouchPotatoSettings>();
|
||||||
var valid = this.Validate(couchPotatoSettings);
|
var valid = this.Validate(couchPotatoSettings);
|
||||||
|
@ -377,7 +391,7 @@ namespace Ombi.UI.Modules.Admin
|
||||||
return Response.AsJson(valid.SendJsonError());
|
return Response.AsJson(valid.SendJsonError());
|
||||||
}
|
}
|
||||||
|
|
||||||
var watcherSettings = WatcherSettings.GetSettings();
|
var watcherSettings = await WatcherSettings.GetSettingsAsync();
|
||||||
|
|
||||||
if (watcherSettings.Enabled)
|
if (watcherSettings.Enabled)
|
||||||
{
|
{
|
||||||
|
@ -389,8 +403,20 @@ namespace Ombi.UI.Modules.Admin
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var radarrSettings = await RadarrSettings.GetSettingsAsync();
|
||||||
|
|
||||||
|
if (radarrSettings.Enabled)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
Response.AsJson(new JsonResponseModel
|
||||||
|
{
|
||||||
|
Result = false,
|
||||||
|
Message = "Cannot have Radarr and CouchPotato both enabled."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
couchPotatoSettings.ApiKey = couchPotatoSettings.ApiKey.Trim();
|
couchPotatoSettings.ApiKey = couchPotatoSettings.ApiKey.Trim();
|
||||||
var result = CpService.SaveSettings(couchPotatoSettings);
|
var result = await CpService.SaveSettingsAsync(couchPotatoSettings);
|
||||||
return Response.AsJson(result
|
return Response.AsJson(result
|
||||||
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for CouchPotato!" }
|
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for CouchPotato!" }
|
||||||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||||
|
@ -448,6 +474,7 @@ namespace Ombi.UI.Modules.Admin
|
||||||
{
|
{
|
||||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "SickRage is enabled, we cannot enable Sonarr and SickRage" });
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "SickRage is enabled, we cannot enable Sonarr and SickRage" });
|
||||||
}
|
}
|
||||||
|
|
||||||
sonarrSettings.ApiKey = sonarrSettings.ApiKey.Trim();
|
sonarrSettings.ApiKey = sonarrSettings.ApiKey.Trim();
|
||||||
var result = SonarrService.SaveSettings(sonarrSettings);
|
var result = SonarrService.SaveSettings(sonarrSettings);
|
||||||
|
|
||||||
|
@ -456,6 +483,10 @@ namespace Ombi.UI.Modules.Admin
|
||||||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Negotiator Sickrage()
|
private Negotiator Sickrage()
|
||||||
{
|
{
|
||||||
var settings = SickRageService.GetSettings();
|
var settings = SickRageService.GetSettings();
|
||||||
|
@ -814,13 +845,13 @@ namespace Ombi.UI.Modules.Admin
|
||||||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||||
}
|
}
|
||||||
|
|
||||||
private Negotiator Newsletter()
|
private async Task<Negotiator> Newsletter()
|
||||||
{
|
{
|
||||||
var settings = NewsLetterService.GetSettings();
|
var settings = await NewsLetterService.GetSettingsAsync();
|
||||||
return View["NewsletterSettings", settings];
|
return View["NewsletterSettings", settings];
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response SaveNewsletter()
|
private async Task<Response> SaveNewsletter()
|
||||||
{
|
{
|
||||||
var settings = this.Bind<NewletterSettings>();
|
var settings = this.Bind<NewletterSettings>();
|
||||||
|
|
||||||
|
@ -828,9 +859,17 @@ namespace Ombi.UI.Modules.Admin
|
||||||
if (!valid.IsValid)
|
if (!valid.IsValid)
|
||||||
{
|
{
|
||||||
var error = valid.SendJsonError();
|
var error = valid.SendJsonError();
|
||||||
Log.Info("Error validating Headphones settings, message: {0}", error.Message);
|
Log.Info("Error validating Newsletter settings, message: {0}", error.Message);
|
||||||
return Response.AsJson(error);
|
return Response.AsJson(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure emails are setup
|
||||||
|
var emailSettings = await EmailService.GetSettingsAsync();
|
||||||
|
if (!emailSettings.Enabled)
|
||||||
|
{
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Please enable your email notifications" });
|
||||||
|
}
|
||||||
|
|
||||||
settings.SendRecentlyAddedEmail = settings.SendRecentlyAddedEmail;
|
settings.SendRecentlyAddedEmail = settings.SendRecentlyAddedEmail;
|
||||||
var result = NewsLetterService.SaveSettings(settings);
|
var result = NewsLetterService.SaveSettings(settings);
|
||||||
|
|
||||||
|
@ -918,6 +957,71 @@ namespace Ombi.UI.Modules.Admin
|
||||||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<Negotiator> DiscordNotification()
|
||||||
|
{
|
||||||
|
var settings = await DiscordSettings.GetSettingsAsync();
|
||||||
|
return View["DiscordNotification", settings];
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Response> TestDiscordNotification()
|
||||||
|
{
|
||||||
|
var settings = this.BindAndValidate<DiscordNotificationSettings>();
|
||||||
|
if (!ModelValidationResult.IsValid)
|
||||||
|
{
|
||||||
|
return Response.AsJson(ModelValidationResult.SendJsonError());
|
||||||
|
}
|
||||||
|
var notificationModel = new NotificationModel
|
||||||
|
{
|
||||||
|
NotificationType = NotificationType.Test,
|
||||||
|
DateTime = DateTime.Now
|
||||||
|
};
|
||||||
|
|
||||||
|
var currentDicordSettings = await DiscordSettings.GetSettingsAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NotificationService.Subscribe(new DiscordNotification(DiscordApi, DiscordSettings));
|
||||||
|
settings.Enabled = true;
|
||||||
|
await NotificationService.Publish(notificationModel, settings);
|
||||||
|
Log.Info("Sent Discord notification test");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, "Failed to subscribe and publish test Discord Notification");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!currentDicordSettings.Enabled)
|
||||||
|
{
|
||||||
|
NotificationService.UnSubscribe(new DiscordNotification(DiscordApi, DiscordSettings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = true, Message = "Successfully sent a test Discord Notification! If you do not receive it please check the logs." });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Response> SaveDiscordNotifications()
|
||||||
|
{
|
||||||
|
var settings = this.BindAndValidate<DiscordNotificationSettings>();
|
||||||
|
if (!ModelValidationResult.IsValid)
|
||||||
|
{
|
||||||
|
return Response.AsJson(ModelValidationResult.SendJsonError());
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await DiscordSettings.SaveSettingsAsync(settings);
|
||||||
|
if (settings.Enabled)
|
||||||
|
{
|
||||||
|
NotificationService.Subscribe(new DiscordNotification(DiscordApi, DiscordSettings));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NotificationService.UnSubscribe(new DiscordNotification(DiscordApi, DiscordSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Info("Saved discord settings, result: {0}", result);
|
||||||
|
return Response.AsJson(result
|
||||||
|
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Discord Notifications!" }
|
||||||
|
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<Negotiator> LandingPage()
|
private async Task<Negotiator> LandingPage()
|
||||||
{
|
{
|
||||||
var settings = await LandingSettings.GetSettingsAsync();
|
var settings = await LandingSettings.GetSettingsAsync();
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace Ombi.UI.Modules.Admin
|
||||||
Id = r.Id,
|
Id = r.Id,
|
||||||
PrimaryIdentifier = r.PrimaryIdentifier,
|
PrimaryIdentifier = r.PrimaryIdentifier,
|
||||||
LastRetry = r.LastRetry,
|
LastRetry = r.LastRetry,
|
||||||
Message = r.Message
|
Message = r.Description
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
return View["RequestFaultQueue", model];
|
return View["RequestFaultQueue", model];
|
||||||
|
|
|
@ -36,6 +36,7 @@ using Nancy;
|
||||||
using Nancy.ModelBinding;
|
using Nancy.ModelBinding;
|
||||||
using Nancy.Responses.Negotiation;
|
using Nancy.Responses.Negotiation;
|
||||||
using Nancy.Validation;
|
using Nancy.Validation;
|
||||||
|
using Ombi.Api.Interfaces;
|
||||||
using Ombi.Core;
|
using Ombi.Core;
|
||||||
using Ombi.Core.SettingModels;
|
using Ombi.Core.SettingModels;
|
||||||
using Ombi.Core.StatusChecker;
|
using Ombi.Core.StatusChecker;
|
||||||
|
@ -52,22 +53,40 @@ namespace Ombi.UI.Modules.Admin
|
||||||
public class IntegrationModule : BaseModule
|
public class IntegrationModule : BaseModule
|
||||||
{
|
{
|
||||||
public IntegrationModule(ISettingsService<PlexRequestSettings> settingsService, ISettingsService<WatcherSettings> watcher,
|
public IntegrationModule(ISettingsService<PlexRequestSettings> settingsService, ISettingsService<WatcherSettings> watcher,
|
||||||
ISettingsService<CouchPotatoSettings> cp,ISecurityExtensions security, IAnalytics a) : base("admin", settingsService, security)
|
ISettingsService<CouchPotatoSettings> cp,ISecurityExtensions security, IAnalytics a, ISettingsService<RadarrSettings> radarrSettings,
|
||||||
|
ICacheProvider cache, IRadarrApi radarrApi, ISonarrApi sonarrApi) : base("admin", settingsService, security)
|
||||||
{
|
{
|
||||||
|
|
||||||
WatcherSettings = watcher;
|
WatcherSettings = watcher;
|
||||||
Analytics = a;
|
Analytics = a;
|
||||||
CpSettings = cp;
|
CpSettings = cp;
|
||||||
|
Cache = cache;
|
||||||
|
RadarrApi = radarrApi;
|
||||||
|
RadarrSettings = radarrSettings;
|
||||||
|
SonarrApi = sonarrApi;
|
||||||
|
|
||||||
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
|
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
|
||||||
|
|
||||||
|
|
||||||
|
Post["/sonarrrootfolders"] = _ => GetSonarrRootFolders();
|
||||||
|
|
||||||
Get["/watcher", true] = async (x, ct) => await Watcher();
|
Get["/watcher", true] = async (x, ct) => await Watcher();
|
||||||
Post["/watcher", true] = async (x, ct) => await SaveWatcher();
|
Post["/watcher", true] = async (x, ct) => await SaveWatcher();
|
||||||
|
|
||||||
|
Get["/radarr", true] = async (x, ct) => await Radarr();
|
||||||
|
Post["/radarr", true] = async (x, ct) => await SaveRadarr();
|
||||||
|
|
||||||
|
|
||||||
|
Post["/radarrprofiles"] = _ => GetRadarrQualityProfiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISettingsService<WatcherSettings> WatcherSettings { get; }
|
private ISettingsService<WatcherSettings> WatcherSettings { get; }
|
||||||
private ISettingsService<CouchPotatoSettings> CpSettings { get; }
|
private ISettingsService<CouchPotatoSettings> CpSettings { get; }
|
||||||
|
private ISettingsService<RadarrSettings> RadarrSettings { get; }
|
||||||
|
private IRadarrApi RadarrApi { get; }
|
||||||
|
private ICacheProvider Cache { get; }
|
||||||
private IAnalytics Analytics { get; }
|
private IAnalytics Analytics { get; }
|
||||||
|
private ISonarrApi SonarrApi { get; }
|
||||||
|
|
||||||
private async Task<Negotiator> Watcher()
|
private async Task<Negotiator> Watcher()
|
||||||
{
|
{
|
||||||
|
@ -97,6 +116,18 @@ namespace Ombi.UI.Modules.Admin
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var radarrSettings = await RadarrSettings.GetSettingsAsync();
|
||||||
|
|
||||||
|
if (radarrSettings.Enabled)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
Response.AsJson(new JsonResponseModel
|
||||||
|
{
|
||||||
|
Result = false,
|
||||||
|
Message = "Cannot have Radarr and CouchPotato both enabled."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
settings.ApiKey = settings.ApiKey.Trim();
|
settings.ApiKey = settings.ApiKey.Trim();
|
||||||
var result = await WatcherSettings.SaveSettingsAsync(settings);
|
var result = await WatcherSettings.SaveSettingsAsync(settings);
|
||||||
return Response.AsJson(result
|
return Response.AsJson(result
|
||||||
|
@ -104,5 +135,72 @@ namespace Ombi.UI.Modules.Admin
|
||||||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<Negotiator> Radarr()
|
||||||
|
{
|
||||||
|
var settings = await RadarrSettings.GetSettingsAsync();
|
||||||
|
|
||||||
|
return View["Radarr", settings];
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Response> SaveRadarr()
|
||||||
|
{
|
||||||
|
var radarrSettings = this.Bind<RadarrSettings>();
|
||||||
|
|
||||||
|
//Check Watcher and CP make sure they are not enabled
|
||||||
|
var watcher = await WatcherSettings.GetSettingsAsync();
|
||||||
|
if (watcher.Enabled)
|
||||||
|
{
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Watcher is enabled, we cannot enable Watcher and Radarr" });
|
||||||
|
}
|
||||||
|
|
||||||
|
var cp = await CpSettings.GetSettingsAsync();
|
||||||
|
if (cp.Enabled)
|
||||||
|
{
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "CouchPotato is enabled, we cannot enable Watcher and CouchPotato" });
|
||||||
|
}
|
||||||
|
|
||||||
|
var valid = this.Validate(radarrSettings);
|
||||||
|
if (!valid.IsValid)
|
||||||
|
{
|
||||||
|
return Response.AsJson(valid.SendJsonError());
|
||||||
|
}
|
||||||
|
|
||||||
|
radarrSettings.ApiKey = radarrSettings.ApiKey.Trim();
|
||||||
|
var result = await RadarrSettings.SaveSettingsAsync(radarrSettings);
|
||||||
|
|
||||||
|
return Response.AsJson(result
|
||||||
|
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Radarr!" }
|
||||||
|
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response GetRadarrQualityProfiles()
|
||||||
|
{
|
||||||
|
var settings = this.Bind<RadarrSettings>();
|
||||||
|
var profiles = RadarrApi.GetProfiles(settings.ApiKey, settings.FullUri);
|
||||||
|
|
||||||
|
// set the cache
|
||||||
|
if (profiles != null)
|
||||||
|
{
|
||||||
|
Cache.Set(CacheKeys.RadarrQualityProfiles, profiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.AsJson(profiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response GetSonarrRootFolders()
|
||||||
|
{
|
||||||
|
var settings = this.Bind<SonarrSettings>();
|
||||||
|
|
||||||
|
var rootFolders = SonarrApi.GetRootFolders(settings.ApiKey, settings.FullUri);
|
||||||
|
|
||||||
|
// set the cache
|
||||||
|
if (rootFolders != null)
|
||||||
|
{
|
||||||
|
Cache.Set(CacheKeys.SonarrRootFolders, rootFolders);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.AsJson(rootFolders);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
150
Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs
Normal file
150
Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: AboutModule.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.Threading.Tasks;
|
||||||
|
using Nancy;
|
||||||
|
using Ombi.Core;
|
||||||
|
using Ombi.Core.SettingModels;
|
||||||
|
using Ombi.Helpers.Permissions;
|
||||||
|
using Ombi.Services.Interfaces;
|
||||||
|
using Ombi.Services.Jobs;
|
||||||
|
using Ombi.UI.Models;
|
||||||
|
using ISecurityExtensions = Ombi.Core.ISecurityExtensions;
|
||||||
|
|
||||||
|
namespace Ombi.UI.Modules.Admin
|
||||||
|
{
|
||||||
|
public class ScheduledJobsRunnerModule : BaseModule
|
||||||
|
{
|
||||||
|
public ScheduledJobsRunnerModule(ISettingsService<PlexRequestSettings> settingsService,
|
||||||
|
ISecurityExtensions security, IPlexContentCacher contentCacher, ISonarrCacher sonarrCacher, IWatcherCacher watcherCacher,
|
||||||
|
IRadarrCacher radarrCacher, ICouchPotatoCacher cpCacher, IStoreBackup store, ISickRageCacher srCacher, IAvailabilityChecker plexChceker,
|
||||||
|
IStoreCleanup cleanup, IUserRequestLimitResetter requestLimit, IPlexEpisodeCacher episodeCacher, IRecentlyAdded recentlyAdded,
|
||||||
|
IFaultQueueHandler faultQueueHandler, IPlexUserChecker plexUserChecker) : base("admin", settingsService, security)
|
||||||
|
{
|
||||||
|
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
|
||||||
|
|
||||||
|
PlexContentCacher = contentCacher;
|
||||||
|
SonarrCacher = sonarrCacher;
|
||||||
|
RadarrCacher = radarrCacher;
|
||||||
|
WatcherCacher = watcherCacher;
|
||||||
|
CpCacher = cpCacher;
|
||||||
|
StoreBackup = store;
|
||||||
|
SrCacher = srCacher;
|
||||||
|
AvailabilityChecker = plexChceker;
|
||||||
|
StoreCleanup = cleanup;
|
||||||
|
RequestLimit = requestLimit;
|
||||||
|
EpisodeCacher = episodeCacher;
|
||||||
|
RecentlyAdded = recentlyAdded;
|
||||||
|
FaultQueueHandler = faultQueueHandler;
|
||||||
|
PlexUserChecker = plexUserChecker;
|
||||||
|
|
||||||
|
Post["/schedulerun", true] = async (x, ct) => await ScheduleRun((string)Request.Form.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IPlexContentCacher PlexContentCacher { get; }
|
||||||
|
private IRadarrCacher RadarrCacher { get; }
|
||||||
|
private ISonarrCacher SonarrCacher { get; }
|
||||||
|
private IWatcherCacher WatcherCacher { get; }
|
||||||
|
private ICouchPotatoCacher CpCacher { get; }
|
||||||
|
private IStoreBackup StoreBackup { get; }
|
||||||
|
private ISickRageCacher SrCacher { get; }
|
||||||
|
private IAvailabilityChecker AvailabilityChecker { get; }
|
||||||
|
private IStoreCleanup StoreCleanup { get; }
|
||||||
|
private IUserRequestLimitResetter RequestLimit { get; }
|
||||||
|
private IPlexEpisodeCacher EpisodeCacher { get; }
|
||||||
|
private IRecentlyAdded RecentlyAdded { get; }
|
||||||
|
private IFaultQueueHandler FaultQueueHandler { get; }
|
||||||
|
private IPlexUserChecker PlexUserChecker { get; }
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<Response> ScheduleRun(string key)
|
||||||
|
{
|
||||||
|
if (key.Equals(JobNames.PlexCacher, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
PlexContentCacher.CacheContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.Equals(JobNames.WatcherCacher, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
WatcherCacher.Queued();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.Equals(JobNames.SonarrCacher, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
SonarrCacher.Queued();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.RadarrCacher, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
RadarrCacher.Queued();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.CpCacher, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
CpCacher.Queued();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.StoreBackup, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
StoreBackup.Start();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.SrCacher, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
SrCacher.Queued();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.PlexChecker, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
AvailabilityChecker.Start();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.StoreCleanup, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
StoreCleanup.Start();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.RequestLimitReset, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
RequestLimit.Start();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.EpisodeCacher, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
EpisodeCacher.Start();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.RecentlyAddedEmail, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
RecentlyAdded.Start();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.FaultQueueHandler, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
FaultQueueHandler.Start();
|
||||||
|
}
|
||||||
|
if (key.Equals(JobNames.PlexUserChecker, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
RequestLimit.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,7 +46,7 @@ namespace Ombi.UI.Modules
|
||||||
|
|
||||||
public ApplicationTesterModule(ICouchPotatoApi cpApi, ISonarrApi sonarrApi, IPlexApi plexApi,
|
public ApplicationTesterModule(ICouchPotatoApi cpApi, ISonarrApi sonarrApi, IPlexApi plexApi,
|
||||||
ISickRageApi srApi, IHeadphonesApi hpApi, ISettingsService<PlexRequestSettings> pr, ISecurityExtensions security,
|
ISickRageApi srApi, IHeadphonesApi hpApi, ISettingsService<PlexRequestSettings> pr, ISecurityExtensions security,
|
||||||
IWatcherApi watcherApi) : base("test", pr, security)
|
IWatcherApi watcherApi, IRadarrApi radarrApi) : base("test", pr, security)
|
||||||
{
|
{
|
||||||
this.RequiresAuthentication();
|
this.RequiresAuthentication();
|
||||||
|
|
||||||
|
@ -56,9 +56,11 @@ namespace Ombi.UI.Modules
|
||||||
SickRageApi = srApi;
|
SickRageApi = srApi;
|
||||||
HeadphonesApi = hpApi;
|
HeadphonesApi = hpApi;
|
||||||
WatcherApi = watcherApi;
|
WatcherApi = watcherApi;
|
||||||
|
RadarrApi = radarrApi;
|
||||||
|
|
||||||
Post["/cp"] = _ => CouchPotatoTest();
|
Post["/cp"] = _ => CouchPotatoTest();
|
||||||
Post["/sonarr"] = _ => SonarrTest();
|
Post["/sonarr"] = _ => SonarrTest();
|
||||||
|
Post["/radarr"] = _ => RadarrTest();
|
||||||
Post["/plex"] = _ => PlexTest();
|
Post["/plex"] = _ => PlexTest();
|
||||||
Post["/sickrage"] = _ => SickRageTest();
|
Post["/sickrage"] = _ => SickRageTest();
|
||||||
Post["/headphones"] = _ => HeadphonesTest();
|
Post["/headphones"] = _ => HeadphonesTest();
|
||||||
|
@ -73,6 +75,7 @@ namespace Ombi.UI.Modules
|
||||||
private ISickRageApi SickRageApi { get; }
|
private ISickRageApi SickRageApi { get; }
|
||||||
private IHeadphonesApi HeadphonesApi { get; }
|
private IHeadphonesApi HeadphonesApi { get; }
|
||||||
private IWatcherApi WatcherApi { get; }
|
private IWatcherApi WatcherApi { get; }
|
||||||
|
private IRadarrApi RadarrApi { get; }
|
||||||
|
|
||||||
private Response CouchPotatoTest()
|
private Response CouchPotatoTest()
|
||||||
{
|
{
|
||||||
|
@ -148,7 +151,7 @@ namespace Ombi.UI.Modules
|
||||||
: Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Sonarr, please check your settings." });
|
: Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Sonarr, please check your settings." });
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them.
|
catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them.
|
||||||
{
|
{
|
||||||
Log.Warn("Exception thrown when attempting to get Sonarr's status: ");
|
Log.Warn("Exception thrown when attempting to get Sonarr's status: ");
|
||||||
Log.Warn(e);
|
Log.Warn(e);
|
||||||
|
@ -161,6 +164,35 @@ namespace Ombi.UI.Modules
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Response RadarrTest()
|
||||||
|
{
|
||||||
|
var radarrSettings = this.Bind<RadarrSettings>();
|
||||||
|
var valid = this.Validate(radarrSettings);
|
||||||
|
if (!valid.IsValid)
|
||||||
|
{
|
||||||
|
return Response.AsJson(valid.SendJsonError());
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var status = RadarrApi.SystemStatus(radarrSettings.ApiKey, radarrSettings.FullUri);
|
||||||
|
return status?.version != null
|
||||||
|
? Response.AsJson(new JsonResponseModel { Result = true, Message = "Connected to Radarr successfully!" })
|
||||||
|
: Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Radarr, please check your settings." });
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them.
|
||||||
|
{
|
||||||
|
Log.Warn("Exception thrown when attempting to get Radarr's status: ");
|
||||||
|
Log.Warn(e);
|
||||||
|
var message = $"Could not connect to Radarr, please check your settings. <strong>Exception Message:</strong> {e.Message}";
|
||||||
|
if (e.InnerException != null)
|
||||||
|
{
|
||||||
|
message = $"Could not connect to Radarr, please check your settings. <strong>Exception Message:</strong> {e.InnerException.Message}";
|
||||||
|
}
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Response PlexTest()
|
private Response PlexTest()
|
||||||
{
|
{
|
||||||
var plexSettings = this.Bind<PlexSettings>();
|
var plexSettings = this.Bind<PlexSettings>();
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace Ombi.UI.Modules
|
||||||
public ApprovalModule(IRequestService service, ISonarrApi sonarrApi,
|
public ApprovalModule(IRequestService service, ISonarrApi sonarrApi,
|
||||||
ISettingsService<SonarrSettings> sonarrSettings, ISickRageApi srApi, ISettingsService<SickRageSettings> srSettings,
|
ISettingsService<SonarrSettings> sonarrSettings, ISickRageApi srApi, ISettingsService<SickRageSettings> srSettings,
|
||||||
ISettingsService<HeadphonesSettings> hpSettings, IHeadphonesApi hpApi, ISettingsService<PlexRequestSettings> pr, ITransientFaultQueue faultQueue
|
ISettingsService<HeadphonesSettings> hpSettings, IHeadphonesApi hpApi, ISettingsService<PlexRequestSettings> pr, ITransientFaultQueue faultQueue
|
||||||
, ISecurityExtensions security, IMovieSender movieSender) : base("approval", pr, security)
|
, ISecurityExtensions security, IMovieSender movieSender, ICacheProvider cache) : base("approval", pr, security)
|
||||||
{
|
{
|
||||||
|
|
||||||
Before += (ctx) => Security.AdminLoginRedirect(ctx, Permissions.Administrator,Permissions.ManageRequests);
|
Before += (ctx) => Security.AdminLoginRedirect(ctx, Permissions.Administrator,Permissions.ManageRequests);
|
||||||
|
@ -64,6 +64,7 @@ namespace Ombi.UI.Modules
|
||||||
HeadphoneApi = hpApi;
|
HeadphoneApi = hpApi;
|
||||||
FaultQueue = faultQueue;
|
FaultQueue = faultQueue;
|
||||||
MovieSender = movieSender;
|
MovieSender = movieSender;
|
||||||
|
Cache = cache;
|
||||||
|
|
||||||
Post["/approve", true] = async (x, ct) => await Approve((int)Request.Form.requestid, (string)Request.Form.qualityId);
|
Post["/approve", true] = async (x, ct) => await Approve((int)Request.Form.requestid, (string)Request.Form.qualityId);
|
||||||
Post["/deny", true] = async (x, ct) => await DenyRequest((int)Request.Form.requestid, (string)Request.Form.reason);
|
Post["/deny", true] = async (x, ct) => await DenyRequest((int)Request.Form.requestid, (string)Request.Form.reason);
|
||||||
|
@ -86,6 +87,7 @@ namespace Ombi.UI.Modules
|
||||||
private ISickRageApi SickRageApi { get; }
|
private ISickRageApi SickRageApi { get; }
|
||||||
private IHeadphonesApi HeadphoneApi { get; }
|
private IHeadphonesApi HeadphoneApi { get; }
|
||||||
private ITransientFaultQueue FaultQueue { get; }
|
private ITransientFaultQueue FaultQueue { get; }
|
||||||
|
private ICacheProvider Cache { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Approves the specified request identifier.
|
/// Approves the specified request identifier.
|
||||||
|
@ -120,7 +122,7 @@ namespace Ombi.UI.Modules
|
||||||
|
|
||||||
private async Task<Response> RequestTvAndUpdateStatus(RequestedModel request, string qualityId)
|
private async Task<Response> RequestTvAndUpdateStatus(RequestedModel request, string qualityId)
|
||||||
{
|
{
|
||||||
var sender = new TvSenderOld(SonarrApi, SickRageApi); // TODO put back
|
var sender = new TvSenderOld(SonarrApi, SickRageApi, Cache); // TODO put back
|
||||||
|
|
||||||
var sonarrSettings = await SonarrSettings.GetSettingsAsync();
|
var sonarrSettings = await SonarrSettings.GetSettingsAsync();
|
||||||
if (sonarrSettings.Enabled)
|
if (sonarrSettings.Enabled)
|
||||||
|
@ -435,7 +437,7 @@ namespace Ombi.UI.Modules
|
||||||
}
|
}
|
||||||
if (r.Type == RequestType.TvShow)
|
if (r.Type == RequestType.TvShow)
|
||||||
{
|
{
|
||||||
var sender = new TvSenderOld(SonarrApi, SickRageApi); // TODO put back
|
var sender = new TvSenderOld(SonarrApi, SickRageApi, Cache); // TODO put back
|
||||||
var sr = await SickRageSettings.GetSettingsAsync();
|
var sr = await SickRageSettings.GetSettingsAsync();
|
||||||
var sonarr = await SonarrSettings.GetSettingsAsync();
|
var sonarr = await SonarrSettings.GetSettingsAsync();
|
||||||
if (sr.Enabled)
|
if (sr.Enabled)
|
||||||
|
|
|
@ -31,6 +31,7 @@ using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Nancy;
|
using Nancy;
|
||||||
using Nancy.Security;
|
using Nancy.Security;
|
||||||
|
using NLog;
|
||||||
using Ombi.Core;
|
using Ombi.Core;
|
||||||
using Ombi.Core.SettingModels;
|
using Ombi.Core.SettingModels;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
@ -100,6 +101,7 @@ namespace Ombi.UI.Modules
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
private string _username;
|
private string _username;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the Username or UserAlias
|
/// Returns the Username or UserAlias
|
||||||
|
@ -112,15 +114,16 @@ namespace Ombi.UI.Modules
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var username = Security.GetUsername(User.UserName, Session);
|
var username = Security.GetUsername(User?.UserName, Session);
|
||||||
if (string.IsNullOrEmpty(username))
|
if (string.IsNullOrEmpty(username))
|
||||||
{
|
{
|
||||||
return Session[SessionKeys.UsernameKey].ToString();
|
return string.Empty;
|
||||||
}
|
}
|
||||||
_username = username;
|
_username = username;
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
Log.Info(e);
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,9 +152,10 @@ namespace Ombi.UI.Modules
|
||||||
|
|
||||||
protected bool LoggedIn => Context?.CurrentUser != null;
|
protected bool LoggedIn => Context?.CurrentUser != null;
|
||||||
|
|
||||||
protected string Culture { get; set; }
|
private string Culture { get; set; }
|
||||||
protected const string CultureCookieName = "_culture";
|
protected const string CultureCookieName = "_culture";
|
||||||
protected Response SetCookie()
|
|
||||||
|
private Response SetCookie()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -96,6 +96,8 @@ namespace Ombi.UI.Modules
|
||||||
|
|
||||||
Post["/changeavailability", true] = async (x, ct) => await ChangeRequestAvailability((int)Request.Form.Id, (bool)Request.Form.Available);
|
Post["/changeavailability", true] = async (x, ct) => await ChangeRequestAvailability((int)Request.Form.Id, (bool)Request.Form.Available);
|
||||||
|
|
||||||
|
Post["/changeRootFolder", true] = async (x, ct) => await ChangeRootFolder((int) Request.Form.requestId, (int) Request.Form.rootFolderId);
|
||||||
|
|
||||||
Get["/UpdateFilters", true] = async (x, ct) => await GetFilterAndSortSettings();
|
Get["/UpdateFilters", true] = async (x, ct) => await GetFilterAndSortSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +162,7 @@ namespace Ombi.UI.Modules
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var canManageRequest = Security.HasAnyPermissions(User, Permissions.Administrator, Permissions.ManageRequests);
|
var canManageRequest = Security.HasAnyPermissions(User, Permissions.Administrator, Permissions.ManageRequests);
|
||||||
var viewModel = dbMovies.Select(movie => new RequestViewModel
|
var viewModel = dbMovies.Select(movie => new RequestViewModel
|
||||||
{
|
{
|
||||||
|
@ -185,7 +187,7 @@ namespace Ombi.UI.Modules
|
||||||
IssueId = movie.IssueId,
|
IssueId = movie.IssueId,
|
||||||
Denied = movie.Denied,
|
Denied = movie.Denied,
|
||||||
DeniedReason = movie.DeniedReason,
|
DeniedReason = movie.DeniedReason,
|
||||||
Qualities = qualities.ToArray()
|
Qualities = qualities.ToArray(),
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
return Response.AsJson(viewModel);
|
return Response.AsJson(viewModel);
|
||||||
|
@ -193,32 +195,39 @@ namespace Ombi.UI.Modules
|
||||||
|
|
||||||
private async Task<Response> GetTvShows()
|
private async Task<Response> GetTvShows()
|
||||||
{
|
{
|
||||||
var settingsTask = PrSettings.GetSettingsAsync();
|
|
||||||
|
|
||||||
var requests = await Service.GetAllAsync();
|
var requests = await Service.GetAllAsync();
|
||||||
requests = requests.Where(x => x.Type == RequestType.TvShow);
|
requests = requests.Where(x => x.Type == RequestType.TvShow);
|
||||||
|
|
||||||
var dbTv = requests;
|
var dbTv = requests;
|
||||||
var settings = await settingsTask;
|
|
||||||
if (Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests) && !IsAdmin)
|
if (Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests) && !IsAdmin)
|
||||||
{
|
{
|
||||||
dbTv = dbTv.Where(x => x.UserHasRequested(Username)).ToList();
|
dbTv = dbTv.Where(x => x.UserHasRequested(Username)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<QualityModel> qualities = new List<QualityModel>();
|
IEnumerable<QualityModel> qualities = new List<QualityModel>();
|
||||||
|
IEnumerable<RootFolderModel> rootFolders = new List<RootFolderModel>();
|
||||||
|
|
||||||
|
var sonarrSettings = await SonarrSettings.GetSettingsAsync();
|
||||||
if (IsAdmin)
|
if (IsAdmin)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sonarrSettings = await SonarrSettings.GetSettingsAsync();
|
|
||||||
if (sonarrSettings.Enabled)
|
if (sonarrSettings.Enabled)
|
||||||
{
|
{
|
||||||
var result = Cache.GetOrSetAsync(CacheKeys.SonarrQualityProfiles, async () =>
|
var result = await Cache.GetOrSetAsync(CacheKeys.SonarrQualityProfiles, async () =>
|
||||||
{
|
{
|
||||||
return await Task.Run(() => SonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri));
|
return await Task.Run(() => SonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri));
|
||||||
});
|
});
|
||||||
qualities = result.Result.Select(x => new QualityModel { Id = x.id.ToString(), Name = x.name }).ToList();
|
qualities = result.Select(x => new QualityModel { Id = x.id.ToString(), Name = x.name }).ToList();
|
||||||
}
|
|
||||||
|
|
||||||
|
var rootFoldersResult =await Cache.GetOrSetAsync(CacheKeys.SonarrRootFolders, async () =>
|
||||||
|
{
|
||||||
|
return await Task.Run(() => SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri));
|
||||||
|
});
|
||||||
|
|
||||||
|
rootFolders = rootFoldersResult.Select(x => new RootFolderModel { Id = x.id.ToString(), Path = x.path, FreeSpace = x.freespace}).ToList();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var sickRageSettings = await SickRageSettings.GetSettingsAsync();
|
var sickRageSettings = await SickRageSettings.GetSettingsAsync();
|
||||||
|
@ -235,6 +244,8 @@ namespace Ombi.UI.Modules
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var canManageRequest = Security.HasAnyPermissions(User, Permissions.Administrator, Permissions.ManageRequests);
|
var canManageRequest = Security.HasAnyPermissions(User, Permissions.Administrator, Permissions.ManageRequests);
|
||||||
var viewModel = dbTv.Select(tv => new RequestViewModel
|
var viewModel = dbTv.Select(tv => new RequestViewModel
|
||||||
{
|
{
|
||||||
|
@ -243,7 +254,7 @@ namespace Ombi.UI.Modules
|
||||||
Status = tv.Status,
|
Status = tv.Status,
|
||||||
ImdbId = tv.ImdbId,
|
ImdbId = tv.ImdbId,
|
||||||
Id = tv.Id,
|
Id = tv.Id,
|
||||||
PosterPath = tv.PosterPath,
|
PosterPath = tv.PosterPath.Contains("http:") ? tv.PosterPath.Replace("http:", "https:") : tv.PosterPath, // We make the poster path https on request, but this is just incase
|
||||||
ReleaseDate = tv.ReleaseDate,
|
ReleaseDate = tv.ReleaseDate,
|
||||||
ReleaseDateTicks = tv.ReleaseDate.Ticks,
|
ReleaseDateTicks = tv.ReleaseDate.Ticks,
|
||||||
RequestedDate = tv.RequestedDate,
|
RequestedDate = tv.RequestedDate,
|
||||||
|
@ -262,11 +273,30 @@ namespace Ombi.UI.Modules
|
||||||
TvSeriesRequestType = tv.SeasonsRequested,
|
TvSeriesRequestType = tv.SeasonsRequested,
|
||||||
Qualities = qualities.ToArray(),
|
Qualities = qualities.ToArray(),
|
||||||
Episodes = tv.Episodes.ToArray(),
|
Episodes = tv.Episodes.ToArray(),
|
||||||
|
RootFolders = rootFolders.ToArray(),
|
||||||
|
HasRootFolders = rootFolders.Any(),
|
||||||
|
CurrentRootPath = sonarrSettings.Enabled ? GetRootPath(tv.RootFolderSelected, sonarrSettings).Result : null
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
return Response.AsJson(viewModel);
|
return Response.AsJson(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string> GetRootPath(int pathId, SonarrSettings sonarrSettings)
|
||||||
|
{
|
||||||
|
var rootFoldersResult = await Cache.GetOrSetAsync(CacheKeys.SonarrRootFolders, async () =>
|
||||||
|
{
|
||||||
|
return await Task.Run(() => SonarrApi.GetRootFolders(sonarrSettings.ApiKey, sonarrSettings.FullUri));
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var r in rootFoldersResult.Where(r => r.id == pathId))
|
||||||
|
{
|
||||||
|
return r.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return default path
|
||||||
|
return rootFoldersResult.FirstOrDefault(x => x.id.Equals(int.Parse(sonarrSettings.RootPath)))?.path ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<Response> GetAlbumRequests()
|
private async Task<Response> GetAlbumRequests()
|
||||||
{
|
{
|
||||||
var settings = PrSettings.GetSettings();
|
var settings = PrSettings.GetSettings();
|
||||||
|
@ -430,5 +460,34 @@ namespace Ombi.UI.Modules
|
||||||
|
|
||||||
return Response.AsJson(vm);
|
return Response.AsJson(vm);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private async Task<Response> ChangeRootFolder(int id, int rootFolderId)
|
||||||
|
{
|
||||||
|
// Get all root folders
|
||||||
|
var settings = await SonarrSettings.GetSettingsAsync();
|
||||||
|
var rootFolders = SonarrApi.GetRootFolders(settings.ApiKey, settings.FullUri);
|
||||||
|
|
||||||
|
// Get Request
|
||||||
|
var allRequests = await Service.GetAllAsync();
|
||||||
|
var request = allRequests.FirstOrDefault(x => x.Id == id);
|
||||||
|
|
||||||
|
if (request == null)
|
||||||
|
{
|
||||||
|
return Response.AsJson(new JsonResponseModel {Result = false});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var folder in rootFolders)
|
||||||
|
{
|
||||||
|
if (folder.id.Equals(rootFolderId))
|
||||||
|
{
|
||||||
|
request.RootFolderSelected = folder.id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Service.UpdateRequestAsync(request);
|
||||||
|
|
||||||
|
return Response.AsJson(new JsonResponseModel {Result = true});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
62
Ombi.UI/Modules/SearchExtensionModule.cs
Normal file
62
Ombi.UI/Modules/SearchExtensionModule.cs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: SearchExtensionModule.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.Threading.Tasks;
|
||||||
|
using Nancy;
|
||||||
|
using Ombi.Api.Interfaces;
|
||||||
|
using Ombi.Core;
|
||||||
|
using Ombi.Core.SettingModels;
|
||||||
|
|
||||||
|
namespace Ombi.UI.Modules
|
||||||
|
{
|
||||||
|
public class SearchExtensionModule : BaseAuthModule
|
||||||
|
{
|
||||||
|
public SearchExtensionModule(ISettingsService<PlexRequestSettings> pr, ISecurityExtensions security, INetflixApi netflix) : base("searchextension",pr, security)
|
||||||
|
{
|
||||||
|
NetflixApi = netflix;
|
||||||
|
|
||||||
|
Get["/netflix/{searchTerm}", true] = async (x, ctx) => await Netflix(x.searchTerm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private INetflixApi NetflixApi { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<Response> Netflix(string title)
|
||||||
|
{
|
||||||
|
var result = NetflixApi.CheckNetflix(title);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(result.Message))
|
||||||
|
{
|
||||||
|
return Response.AsJson(new { Result = false });
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.AsJson(new { Result = true, NetflixId = result.ShowId });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,6 +58,7 @@ using Ombi.Store.Repository;
|
||||||
using Ombi.UI.Helpers;
|
using Ombi.UI.Helpers;
|
||||||
using Ombi.UI.Models;
|
using Ombi.UI.Models;
|
||||||
using TMDbLib.Objects.General;
|
using TMDbLib.Objects.General;
|
||||||
|
using TraktApiSharp.Objects.Get.Shows;
|
||||||
using Action = Ombi.Helpers.Analytics.Action;
|
using Action = Ombi.Helpers.Analytics.Action;
|
||||||
using EpisodesModel = Ombi.Store.EpisodesModel;
|
using EpisodesModel = Ombi.Store.EpisodesModel;
|
||||||
using ISecurityExtensions = Ombi.Core.ISecurityExtensions;
|
using ISecurityExtensions = Ombi.Core.ISecurityExtensions;
|
||||||
|
@ -76,7 +77,7 @@ namespace Ombi.UI.Modules
|
||||||
ISettingsService<PlexSettings> plexService, ISettingsService<AuthenticationSettings> auth,
|
ISettingsService<PlexSettings> plexService, ISettingsService<AuthenticationSettings> auth,
|
||||||
IRepository<UsersToNotify> u, ISettingsService<EmailNotificationSettings> email,
|
IRepository<UsersToNotify> u, ISettingsService<EmailNotificationSettings> email,
|
||||||
IIssueService issue, IAnalytics a, IRepository<RequestLimit> rl, ITransientFaultQueue tfQueue, IRepository<PlexContent> content,
|
IIssueService issue, IAnalytics a, IRepository<RequestLimit> rl, ITransientFaultQueue tfQueue, IRepository<PlexContent> content,
|
||||||
ISecurityExtensions security, IMovieSender movieSender)
|
ISecurityExtensions security, IMovieSender movieSender, IRadarrCacher radarrCacher, ITraktApi traktApi, ISettingsService<CustomizationSettings> cus)
|
||||||
: base("search", prSettings, security)
|
: base("search", prSettings, security)
|
||||||
{
|
{
|
||||||
Auth = auth;
|
Auth = auth;
|
||||||
|
@ -108,6 +109,9 @@ namespace Ombi.UI.Modules
|
||||||
PlexContentRepository = content;
|
PlexContentRepository = content;
|
||||||
MovieSender = movieSender;
|
MovieSender = movieSender;
|
||||||
WatcherCacher = watcherCacher;
|
WatcherCacher = watcherCacher;
|
||||||
|
RadarrCacher = radarrCacher;
|
||||||
|
TraktApi = traktApi;
|
||||||
|
CustomizationSettings = cus;
|
||||||
|
|
||||||
Get["SearchIndex", "/", true] = async (x, ct) => await RequestLoad();
|
Get["SearchIndex", "/", true] = async (x, ct) => await RequestLoad();
|
||||||
|
|
||||||
|
@ -119,6 +123,13 @@ namespace Ombi.UI.Modules
|
||||||
Get["movie/upcoming", true] = async (x, ct) => await UpcomingMovies();
|
Get["movie/upcoming", true] = async (x, ct) => await UpcomingMovies();
|
||||||
Get["movie/playing", true] = async (x, ct) => await CurrentlyPlayingMovies();
|
Get["movie/playing", true] = async (x, ct) => await CurrentlyPlayingMovies();
|
||||||
|
|
||||||
|
Get["tv/popular", true] = async (x, ct) => await ProcessShows(ShowSearchType.Popular);
|
||||||
|
Get["tv/trending", true] = async (x, ct) => await ProcessShows(ShowSearchType.Trending);
|
||||||
|
Get["tv/mostwatched", true] = async (x, ct) => await ProcessShows(ShowSearchType.MostWatched);
|
||||||
|
Get["tv/anticipated", true] = async (x, ct) => await ProcessShows(ShowSearchType.Anticipated);
|
||||||
|
|
||||||
|
Get["tv/poster/{id}"] = p => GetTvPoster((int)p.id);
|
||||||
|
|
||||||
Post["request/movie", true] = async (x, ct) => await RequestMovie((int)Request.Form.movieId);
|
Post["request/movie", true] = async (x, ct) => await RequestMovie((int)Request.Form.movieId);
|
||||||
Post["request/tv", true] =
|
Post["request/tv", true] =
|
||||||
async (x, ct) => await RequestTvShow((int)Request.Form.tvId, (string)Request.Form.seasons);
|
async (x, ct) => await RequestTvShow((int)Request.Form.tvId, (string)Request.Form.seasons);
|
||||||
|
@ -128,6 +139,7 @@ namespace Ombi.UI.Modules
|
||||||
Get["/seasons"] = x => GetSeasons();
|
Get["/seasons"] = x => GetSeasons();
|
||||||
Get["/episodes", true] = async (x, ct) => await GetEpisodes();
|
Get["/episodes", true] = async (x, ct) => await GetEpisodes();
|
||||||
}
|
}
|
||||||
|
private ITraktApi TraktApi { get; }
|
||||||
private IWatcherCacher WatcherCacher { get; }
|
private IWatcherCacher WatcherCacher { get; }
|
||||||
private IMovieSender MovieSender { get; }
|
private IMovieSender MovieSender { get; }
|
||||||
private IRepository<PlexContent> PlexContentRepository { get; }
|
private IRepository<PlexContent> PlexContentRepository { get; }
|
||||||
|
@ -157,14 +169,23 @@ namespace Ombi.UI.Modules
|
||||||
private IAnalytics Analytics { get; }
|
private IAnalytics Analytics { get; }
|
||||||
private ITransientFaultQueue FaultQueue { get; }
|
private ITransientFaultQueue FaultQueue { get; }
|
||||||
private IRepository<RequestLimit> RequestLimitRepo { get; }
|
private IRepository<RequestLimit> RequestLimitRepo { get; }
|
||||||
|
private IRadarrCacher RadarrCacher { get; }
|
||||||
|
private ISettingsService<CustomizationSettings> CustomizationSettings { get; }
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
private async Task<Negotiator> RequestLoad()
|
private async Task<Negotiator> RequestLoad()
|
||||||
{
|
{
|
||||||
|
|
||||||
var settings = await PrService.GetSettingsAsync();
|
var settings = await PrService.GetSettingsAsync();
|
||||||
|
var custom = await CustomizationSettings.GetSettingsAsync();
|
||||||
|
var searchViewModel = new SearchLoadViewModel
|
||||||
|
{
|
||||||
|
Settings = settings,
|
||||||
|
CustomizationSettings = custom
|
||||||
|
};
|
||||||
|
|
||||||
return View["Search/Index", settings];
|
|
||||||
|
return View["Search/Index", searchViewModel];
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Response> UpcomingMovies()
|
private async Task<Response> UpcomingMovies()
|
||||||
|
@ -188,6 +209,17 @@ namespace Ombi.UI.Modules
|
||||||
return await ProcessMovies(MovieSearchType.Search, searchTerm);
|
return await ProcessMovies(MovieSearchType.Search, searchTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Response GetTvPoster(int theTvDbId)
|
||||||
|
{
|
||||||
|
var result = TvApi.ShowLookupByTheTvDbId(theTvDbId);
|
||||||
|
|
||||||
|
var banner = result.image?.medium;
|
||||||
|
if (!string.IsNullOrEmpty(banner))
|
||||||
|
{
|
||||||
|
banner = banner.Replace("http", "https"); // Always use the Https banners
|
||||||
|
}
|
||||||
|
return banner;
|
||||||
|
}
|
||||||
private async Task<Response> ProcessMovies(MovieSearchType searchType, string searchTerm)
|
private async Task<Response> ProcessMovies(MovieSearchType searchType, string searchTerm)
|
||||||
{
|
{
|
||||||
List<MovieResult> apiMovies;
|
List<MovieResult> apiMovies;
|
||||||
|
@ -236,22 +268,13 @@ namespace Ombi.UI.Modules
|
||||||
|
|
||||||
var cpCached = CpCacher.QueuedIds();
|
var cpCached = CpCacher.QueuedIds();
|
||||||
var watcherCached = WatcherCacher.QueuedIds();
|
var watcherCached = WatcherCacher.QueuedIds();
|
||||||
|
var radarrCached = RadarrCacher.QueuedIds();
|
||||||
var content = PlexContentRepository.GetAll();
|
var content = PlexContentRepository.GetAll();
|
||||||
var plexMovies = Checker.GetPlexMovies(content);
|
var plexMovies = Checker.GetPlexMovies(content);
|
||||||
var viewMovies = new List<SearchMovieViewModel>();
|
var viewMovies = new List<SearchMovieViewModel>();
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
foreach (var movie in apiMovies)
|
foreach (var movie in apiMovies)
|
||||||
{
|
{
|
||||||
var imdbId = string.Empty;
|
|
||||||
if (counter <= 5) // Let's only do it for the first 5 items
|
|
||||||
{
|
|
||||||
var movieInfoTask = await MovieApi.GetMovieInformation(movie.Id).ConfigureAwait(false);
|
|
||||||
// TODO needs to be careful about this, it's adding extra time to search...
|
|
||||||
// https://www.themoviedb.org/talk/5807f4cdc3a36812160041f2
|
|
||||||
imdbId = movieInfoTask?.ImdbId;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
var viewMovie = new SearchMovieViewModel
|
var viewMovie = new SearchMovieViewModel
|
||||||
{
|
{
|
||||||
Adult = movie.Adult,
|
Adult = movie.Adult,
|
||||||
|
@ -269,6 +292,28 @@ namespace Ombi.UI.Modules
|
||||||
VoteAverage = movie.VoteAverage,
|
VoteAverage = movie.VoteAverage,
|
||||||
VoteCount = movie.VoteCount
|
VoteCount = movie.VoteCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var imdbId = string.Empty;
|
||||||
|
if (counter <= 5) // Let's only do it for the first 5 items
|
||||||
|
{
|
||||||
|
var movieInfo = MovieApi.GetMovieInformationWithVideos(movie.Id);
|
||||||
|
|
||||||
|
// TODO needs to be careful about this, it's adding extra time to search...
|
||||||
|
// https://www.themoviedb.org/talk/5807f4cdc3a36812160041f2
|
||||||
|
viewMovie.ImdbId = movieInfo?.imdb_id;
|
||||||
|
viewMovie.Homepage = movieInfo?.homepage;
|
||||||
|
var videoId = movieInfo?.video ?? false
|
||||||
|
? movieInfo?.videos?.results?.FirstOrDefault()?.key
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
viewMovie.Trailer = string.IsNullOrEmpty(videoId)
|
||||||
|
? string.Empty
|
||||||
|
: $"https://www.youtube.com/watch?v={videoId}";
|
||||||
|
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var canSee = CanUserSeeThisRequest(viewMovie.Id, Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests), dbMovies);
|
var canSee = CanUserSeeThisRequest(viewMovie.Id, Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests), dbMovies);
|
||||||
var plexMovie = Checker.GetMovie(plexMovies.ToArray(), movie.Title, movie.ReleaseDate?.Year.ToString(),
|
var plexMovie = Checker.GetMovie(plexMovies.ToArray(), movie.Title, movie.ReleaseDate?.Year.ToString(),
|
||||||
imdbId);
|
imdbId);
|
||||||
|
@ -287,13 +332,19 @@ namespace Ombi.UI.Modules
|
||||||
}
|
}
|
||||||
else if (cpCached.Contains(movie.Id) && canSee) // compare to the couchpotato db
|
else if (cpCached.Contains(movie.Id) && canSee) // compare to the couchpotato db
|
||||||
{
|
{
|
||||||
|
viewMovie.Approved = true;
|
||||||
viewMovie.Requested = true;
|
viewMovie.Requested = true;
|
||||||
}
|
}
|
||||||
else if(watcherCached.Contains(imdbId) && canSee) // compare to the watcher db
|
else if(watcherCached.Contains(imdbId) && canSee) // compare to the watcher db
|
||||||
{
|
{
|
||||||
|
viewMovie.Approved = true;
|
||||||
|
viewMovie.Requested = true;
|
||||||
|
}
|
||||||
|
else if (radarrCached.Contains(movie.Id) && canSee)
|
||||||
|
{
|
||||||
|
viewMovie.Approved = true;
|
||||||
viewMovie.Requested = true;
|
viewMovie.Requested = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
viewMovies.Add(viewMovie);
|
viewMovies.Add(viewMovie);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,6 +363,186 @@ namespace Ombi.UI.Modules
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<Response> ProcessShows(ShowSearchType type)
|
||||||
|
{
|
||||||
|
var shows = new List<SearchTvShowViewModel>();
|
||||||
|
var prSettings = await PrService.GetSettingsAsync();
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ShowSearchType.Popular:
|
||||||
|
Analytics.TrackEventAsync(Category.Search, Action.TvShow, "Popular", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
|
var popularShows = await TraktApi.GetPopularShows();
|
||||||
|
|
||||||
|
foreach (var popularShow in popularShows)
|
||||||
|
{
|
||||||
|
var theTvDbId = int.Parse(popularShow.Ids.Tvdb.ToString());
|
||||||
|
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
FirstAired = popularShow.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"),
|
||||||
|
Id = theTvDbId,
|
||||||
|
ImdbId = popularShow.Ids.Imdb,
|
||||||
|
Network = popularShow.Network,
|
||||||
|
Overview = popularShow.Overview.RemoveHtml(),
|
||||||
|
Rating = popularShow.Rating.ToString(),
|
||||||
|
Runtime = popularShow.Runtime.ToString(),
|
||||||
|
SeriesName = popularShow.Title,
|
||||||
|
Status = popularShow.Status.DisplayName,
|
||||||
|
DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode,
|
||||||
|
DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason,
|
||||||
|
EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason),
|
||||||
|
Trailer = popularShow.Trailer,
|
||||||
|
Homepage = popularShow.Homepage
|
||||||
|
};
|
||||||
|
shows.Add(model);
|
||||||
|
}
|
||||||
|
shows = await MapToTvModel(shows, prSettings);
|
||||||
|
break;
|
||||||
|
case ShowSearchType.Anticipated:
|
||||||
|
Analytics.TrackEventAsync(Category.Search, Action.TvShow, "Anticipated", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
|
var anticipated = await TraktApi.GetAnticipatedShows();
|
||||||
|
foreach (var anticipatedShow in anticipated)
|
||||||
|
{
|
||||||
|
var show = anticipatedShow.Show;
|
||||||
|
var theTvDbId = int.Parse(show.Ids.Tvdb.ToString());
|
||||||
|
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
FirstAired = show.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"),
|
||||||
|
Id = theTvDbId,
|
||||||
|
ImdbId = show.Ids.Imdb,
|
||||||
|
Network = show.Network ?? string.Empty,
|
||||||
|
Overview = show.Overview?.RemoveHtml() ?? string.Empty,
|
||||||
|
Rating = show.Rating.ToString(),
|
||||||
|
Runtime = show.Runtime.ToString(),
|
||||||
|
SeriesName = show.Title,
|
||||||
|
Status = show.Status?.DisplayName ?? string.Empty,
|
||||||
|
DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode,
|
||||||
|
DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason,
|
||||||
|
EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason),
|
||||||
|
Trailer = show.Trailer,
|
||||||
|
Homepage = show.Homepage
|
||||||
|
};
|
||||||
|
shows.Add(model);
|
||||||
|
}
|
||||||
|
shows = await MapToTvModel(shows, prSettings);
|
||||||
|
break;
|
||||||
|
case ShowSearchType.MostWatched:
|
||||||
|
Analytics.TrackEventAsync(Category.Search, Action.TvShow, "MostWatched", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
|
var mostWatched = await TraktApi.GetMostWatchesShows();
|
||||||
|
foreach (var watched in mostWatched)
|
||||||
|
{
|
||||||
|
var show = watched.Show;
|
||||||
|
var theTvDbId = int.Parse(show.Ids.Tvdb.ToString());
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
FirstAired = show.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"),
|
||||||
|
Id = theTvDbId,
|
||||||
|
ImdbId = show.Ids.Imdb,
|
||||||
|
Network = show.Network,
|
||||||
|
Overview = show.Overview.RemoveHtml(),
|
||||||
|
Rating = show.Rating.ToString(),
|
||||||
|
Runtime = show.Runtime.ToString(),
|
||||||
|
SeriesName = show.Title,
|
||||||
|
Status = show.Status.DisplayName,
|
||||||
|
DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode,
|
||||||
|
DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason,
|
||||||
|
EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason),
|
||||||
|
Trailer = show.Trailer,
|
||||||
|
Homepage = show.Homepage
|
||||||
|
};
|
||||||
|
shows.Add(model);
|
||||||
|
}
|
||||||
|
shows = await MapToTvModel(shows, prSettings);
|
||||||
|
break;
|
||||||
|
case ShowSearchType.Trending:
|
||||||
|
Analytics.TrackEventAsync(Category.Search, Action.TvShow, "Trending", Username, CookieHelper.GetAnalyticClientId(Cookies));
|
||||||
|
var trending = await TraktApi.GetTrendingShows();
|
||||||
|
foreach (var watched in trending)
|
||||||
|
{
|
||||||
|
var show = watched.Show;
|
||||||
|
var theTvDbId = int.Parse(show.Ids.Tvdb.ToString());
|
||||||
|
var model = new SearchTvShowViewModel
|
||||||
|
{
|
||||||
|
FirstAired = show.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"),
|
||||||
|
Id = theTvDbId,
|
||||||
|
ImdbId = show.Ids.Imdb,
|
||||||
|
Network = show.Network,
|
||||||
|
Overview = show.Overview.RemoveHtml(),
|
||||||
|
Rating = show.Rating.ToString(),
|
||||||
|
Runtime = show.Runtime.ToString(),
|
||||||
|
SeriesName = show.Title,
|
||||||
|
Status = show.Status.DisplayName,
|
||||||
|
DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode,
|
||||||
|
DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason,
|
||||||
|
EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason),
|
||||||
|
Trailer = show.Trailer,
|
||||||
|
Homepage = show.Homepage
|
||||||
|
};
|
||||||
|
shows.Add(model);
|
||||||
|
}
|
||||||
|
shows = await MapToTvModel(shows, prSettings);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Response.AsJson(shows);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<SearchTvShowViewModel>> MapToTvModel(List<SearchTvShowViewModel> shows, PlexRequestSettings prSettings)
|
||||||
|
{
|
||||||
|
|
||||||
|
var plexSettings = await PlexService.GetSettingsAsync();
|
||||||
|
|
||||||
|
var providerId = string.Empty;
|
||||||
|
// Get the requests
|
||||||
|
var allResults = await RequestService.GetAllAsync();
|
||||||
|
allResults = allResults.Where(x => x.Type == RequestType.TvShow);
|
||||||
|
var distinctResults = allResults.DistinctBy(x => x.ProviderId);
|
||||||
|
var dbTv = distinctResults.ToDictionary(x => x.ProviderId);
|
||||||
|
|
||||||
|
// Check the external applications
|
||||||
|
var sonarrCached = SonarrCacher.QueuedIds().ToList();
|
||||||
|
var sickRageCache = SickRageCacher.QueuedIds(); // consider just merging sonarr/sickrage arrays
|
||||||
|
var content = PlexContentRepository.GetAll();
|
||||||
|
var plexTvShows = Checker.GetPlexTvShows(content).ToList();
|
||||||
|
|
||||||
|
foreach (var show in shows)
|
||||||
|
{
|
||||||
|
if (plexSettings.AdvancedSearch)
|
||||||
|
{
|
||||||
|
providerId = show.Id.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
var plexShow = Checker.GetTvShow(plexTvShows.ToArray(), show.SeriesName, show.FirstAired?.Substring(0, 4),
|
||||||
|
providerId);
|
||||||
|
if (plexShow != null)
|
||||||
|
{
|
||||||
|
show.Available = true;
|
||||||
|
show.PlexUrl = plexShow.Url;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dbTv.ContainsKey(show.Id))
|
||||||
|
{
|
||||||
|
var dbt = dbTv[show.Id];
|
||||||
|
|
||||||
|
show.Requested = true;
|
||||||
|
show.Episodes = dbt.Episodes.ToList();
|
||||||
|
show.Approved = dbt.Approved;
|
||||||
|
}
|
||||||
|
if (sonarrCached.Select(x => x.TvdbId).Contains(show.Id) || sickRageCache.Contains(show.Id))
|
||||||
|
// compare to the sonarr/sickrage db
|
||||||
|
{
|
||||||
|
show.Requested = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shows;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<Response> SearchTvShow(string searchTerm)
|
private async Task<Response> SearchTvShow(string searchTerm)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -345,6 +576,10 @@ namespace Ombi.UI.Modules
|
||||||
var viewTv = new List<SearchTvShowViewModel>();
|
var viewTv = new List<SearchTvShowViewModel>();
|
||||||
foreach (var t in apiTv)
|
foreach (var t in apiTv)
|
||||||
{
|
{
|
||||||
|
if (!(t.show.externals?.thetvdb.HasValue) ?? false)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
var banner = t.show.image?.medium;
|
var banner = t.show.image?.medium;
|
||||||
if (!string.IsNullOrEmpty(banner))
|
if (!string.IsNullOrEmpty(banner))
|
||||||
{
|
{
|
||||||
|
@ -574,7 +809,17 @@ namespace Ombi.UI.Modules
|
||||||
if (result.Result)
|
if (result.Result)
|
||||||
{
|
{
|
||||||
return await AddRequest(model, settings,
|
return await AddRequest(model, settings,
|
||||||
$"{fullMovieName} {Resources.UI.Search_SuccessfullyAdded}");
|
$"{fullMovieName} {Resources.UI.Search_SuccessfullyAdded}");
|
||||||
|
}
|
||||||
|
if (result.Error)
|
||||||
|
|
||||||
|
{
|
||||||
|
return
|
||||||
|
Response.AsJson(new JsonResponseModel
|
||||||
|
{
|
||||||
|
Message = "Could not add movie, please contract your administrator",
|
||||||
|
Result = false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (!result.MovieSendingEnabled)
|
if (!result.MovieSendingEnabled)
|
||||||
{
|
{
|
||||||
|
@ -679,11 +924,13 @@ namespace Ombi.UI.Modules
|
||||||
DateTime.TryParse(showInfo.premiered, out firstAir);
|
DateTime.TryParse(showInfo.premiered, out firstAir);
|
||||||
string fullShowName = $"{showInfo.name} ({firstAir.Year})";
|
string fullShowName = $"{showInfo.name} ({firstAir.Year})";
|
||||||
|
|
||||||
|
// For some reason the poster path is always http
|
||||||
|
var posterPath = showInfo.image?.medium.Replace("http:", "https:");
|
||||||
var model = new RequestedModel
|
var model = new RequestedModel
|
||||||
{
|
{
|
||||||
Type = RequestType.TvShow,
|
Type = RequestType.TvShow,
|
||||||
Overview = showInfo.summary.RemoveHtml(),
|
Overview = showInfo.summary.RemoveHtml(),
|
||||||
PosterPath = showInfo.image?.medium,
|
PosterPath = posterPath,
|
||||||
Title = showInfo.name,
|
Title = showInfo.name,
|
||||||
ReleaseDate = firstAir,
|
ReleaseDate = firstAir,
|
||||||
Status = showInfo.status,
|
Status = showInfo.status,
|
||||||
|
@ -762,6 +1009,11 @@ namespace Ombi.UI.Modules
|
||||||
existingRequest.Episodes.AddRange(newEpisodes ?? Enumerable.Empty<EpisodesModel>());
|
existingRequest.Episodes.AddRange(newEpisodes ?? Enumerable.Empty<EpisodesModel>());
|
||||||
|
|
||||||
// It's technically a new request now, so set the status to not approved.
|
// It's technically a new request now, so set the status to not approved.
|
||||||
|
var autoApprove = ShouldAutoApprove(RequestType.TvShow);
|
||||||
|
if (autoApprove)
|
||||||
|
{
|
||||||
|
return await SendTv(model, sonarrSettings, existingRequest, fullShowName, settings);
|
||||||
|
}
|
||||||
existingRequest.Approved = false;
|
existingRequest.Approved = false;
|
||||||
|
|
||||||
return await AddUserToRequest(existingRequest, settings, fullShowName, true);
|
return await AddUserToRequest(existingRequest, settings, fullShowName, true);
|
||||||
|
@ -888,54 +1140,7 @@ namespace Ombi.UI.Modules
|
||||||
{
|
{
|
||||||
if (ShouldAutoApprove(RequestType.TvShow))
|
if (ShouldAutoApprove(RequestType.TvShow))
|
||||||
{
|
{
|
||||||
model.Approved = true;
|
return await SendTv(model, sonarrSettings, existingRequest, fullShowName, settings);
|
||||||
var s = await sonarrSettings;
|
|
||||||
var sender = new TvSenderOld(SonarrApi, SickrageApi); // TODO put back
|
|
||||||
if (s.Enabled)
|
|
||||||
{
|
|
||||||
var result = await sender.SendToSonarr(s, model);
|
|
||||||
if (!string.IsNullOrEmpty(result?.title))
|
|
||||||
{
|
|
||||||
if (existingRequest != null)
|
|
||||||
{
|
|
||||||
return await UpdateRequest(model, settings,
|
|
||||||
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
|
|
||||||
}
|
|
||||||
return
|
|
||||||
await
|
|
||||||
AddRequest(model, settings,
|
|
||||||
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
|
|
||||||
}
|
|
||||||
Log.Debug("Error with sending to sonarr.");
|
|
||||||
return
|
|
||||||
Response.AsJson(ValidationHelper.SendSonarrError(result?.ErrorMessages ?? new List<string>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
var srSettings = SickRageService.GetSettings();
|
|
||||||
if (srSettings.Enabled)
|
|
||||||
{
|
|
||||||
var result = sender.SendToSickRage(srSettings, model);
|
|
||||||
if (result?.result == "success")
|
|
||||||
{
|
|
||||||
return await AddRequest(model, settings,
|
|
||||||
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
|
|
||||||
}
|
|
||||||
return
|
|
||||||
Response.AsJson(new JsonResponseModel
|
|
||||||
{
|
|
||||||
Result = false,
|
|
||||||
Message = result?.message ?? Resources.UI.Search_SickrageError
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!srSettings.Enabled && !s.Enabled)
|
|
||||||
{
|
|
||||||
return await AddRequest(model, settings, $"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
Response.AsJson(new JsonResponseModel { Result = false, Message = Resources.UI.Search_TvNotSetUp });
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return await AddRequest(model, settings, $"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
|
return await AddRequest(model, settings, $"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
|
||||||
}
|
}
|
||||||
|
@ -1385,5 +1590,64 @@ namespace Ombi.UI.Modules
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum ShowSearchType
|
||||||
|
{
|
||||||
|
Popular,
|
||||||
|
Anticipated,
|
||||||
|
MostWatched,
|
||||||
|
Trending
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Response> SendTv(RequestedModel model, Task<SonarrSettings> sonarrSettings, RequestedModel existingRequest, string fullShowName, PlexRequestSettings settings)
|
||||||
|
{
|
||||||
|
model.Approved = true;
|
||||||
|
var s = await sonarrSettings;
|
||||||
|
var sender = new TvSenderOld(SonarrApi, SickrageApi, Cache); // TODO put back
|
||||||
|
if (s.Enabled)
|
||||||
|
{
|
||||||
|
var result = await sender.SendToSonarr(s, model);
|
||||||
|
if (!string.IsNullOrEmpty(result?.title))
|
||||||
|
{
|
||||||
|
if (existingRequest != null)
|
||||||
|
{
|
||||||
|
return await UpdateRequest(model, settings,
|
||||||
|
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
|
||||||
|
}
|
||||||
|
return
|
||||||
|
await
|
||||||
|
AddRequest(model, settings,
|
||||||
|
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
|
||||||
|
}
|
||||||
|
Log.Debug("Error with sending to sonarr.");
|
||||||
|
return
|
||||||
|
Response.AsJson(ValidationHelper.SendSonarrError(result?.ErrorMessages ?? new List<string>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
var srSettings = SickRageService.GetSettings();
|
||||||
|
if (srSettings.Enabled)
|
||||||
|
{
|
||||||
|
var result = sender.SendToSickRage(srSettings, model);
|
||||||
|
if (result?.result == "success")
|
||||||
|
{
|
||||||
|
return await AddRequest(model, settings,
|
||||||
|
$"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
|
||||||
|
}
|
||||||
|
return
|
||||||
|
Response.AsJson(new JsonResponseModel
|
||||||
|
{
|
||||||
|
Result = false,
|
||||||
|
Message = result?.message ?? Resources.UI.Search_SickrageError
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!srSettings.Enabled && !s.Enabled)
|
||||||
|
{
|
||||||
|
return await AddRequest(model, settings, $"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
Response.AsJson(new JsonResponseModel { Result = false, Message = Resources.UI.Search_TvNotSetUp });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
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