mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-14 02:26:55 -07:00
commit
170b2c86f0
52 changed files with 3505 additions and 146 deletions
|
@ -33,7 +33,8 @@ namespace PlexRequests.Api.Interfaces
|
|||
{
|
||||
public interface ICouchPotatoApi
|
||||
{
|
||||
bool AddMovie(string imdbid, string apiKey, string title, Uri baseUrl);
|
||||
bool AddMovie(string imdbid, string apiKey, string title, Uri baseUrl, string profileID = default(string));
|
||||
CouchPotatoStatus GetStatus(Uri url, string apiKey);
|
||||
CouchPotatoProfiles GetProfiles(Uri url, string apiKey);
|
||||
}
|
||||
}
|
40
PlexRequests.Api.Interfaces/ISickRageApi.cs
Normal file
40
PlexRequests.Api.Interfaces/ISickRageApi.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: ISickRageApi.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 PlexRequests.Api.Models.SickRage;
|
||||
|
||||
namespace PlexRequests.Api.Interfaces
|
||||
{
|
||||
public interface ISickRageApi
|
||||
{
|
||||
SickRageTvAdd AddSeries(int tvdbId, bool latest, string quality, string apiKey,
|
||||
Uri baseUrl);
|
||||
|
||||
SickRagePing Ping(string apiKey, Uri baseUrl);
|
||||
}
|
||||
}
|
|
@ -49,6 +49,7 @@
|
|||
<Compile Include="ICouchPotatoApi.cs" />
|
||||
<Compile Include="IPlexApi.cs" />
|
||||
<Compile Include="IPushbulletApi.cs" />
|
||||
<Compile Include="ISickRageApi.cs" />
|
||||
<Compile Include="ISonarrApi.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
|
53
PlexRequests.Api.Models/Movie/CouchPotatoProfiles.cs
Normal file
53
PlexRequests.Api.Models/Movie/CouchPotatoProfiles.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: CouchPotatoProfiles.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 PlexRequests.Api.Models.Movie
|
||||
{
|
||||
public class ProfileList
|
||||
{
|
||||
public bool core { get; set; }
|
||||
public string _rev { get; set; }
|
||||
public List<bool> finish { get; set; }
|
||||
public List<string> qualities { get; set; }
|
||||
public string _id { get; set; }
|
||||
public string _t { get; set; }
|
||||
public string label { get; set; }
|
||||
public int minimum_score { get; set; }
|
||||
public List<int> stop_after { get; set; }
|
||||
public List<int> wait_for { get; set; }
|
||||
public int order { get; set; }
|
||||
public List<object> __invalid_name__3d { get; set; }
|
||||
}
|
||||
|
||||
public class CouchPotatoProfiles
|
||||
{
|
||||
public List<ProfileList> list { get; set; }
|
||||
public bool success { get; set; }
|
||||
}
|
||||
}
|
|
@ -46,6 +46,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Movie\CouchPotatoAdd.cs" />
|
||||
<Compile Include="Movie\CouchPotatoProfiles.cs" />
|
||||
<Compile Include="Movie\CouchPotatoStatus.cs" />
|
||||
<Compile Include="Notifications\PushbulletPush.cs" />
|
||||
<Compile Include="Notifications\PushbulletResponse.cs" />
|
||||
|
@ -57,6 +58,9 @@
|
|||
<Compile Include="Plex\PlexStatus.cs" />
|
||||
<Compile Include="Plex\PlexUserRequest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SickRage\SickRagePing.cs" />
|
||||
<Compile Include="SickRage\SickRageStatus.cs" />
|
||||
<Compile Include="SickRage\SickRageTvAdd.cs" />
|
||||
<Compile Include="Sonarr\SonarrAddSeries.cs" />
|
||||
<Compile Include="Sonarr\SonarrProfile.cs" />
|
||||
<Compile Include="Sonarr\SystemStatus.cs" />
|
||||
|
|
40
PlexRequests.Api.Models/SickRage/SickRagePing.cs
Normal file
40
PlexRequests.Api.Models/SickRage/SickRagePing.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SickRagePing.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 PlexRequests.Api.Models.SickRage
|
||||
{
|
||||
public class SickRagePingData
|
||||
{
|
||||
public int pid { get; set; }
|
||||
}
|
||||
|
||||
public class SickRagePing
|
||||
{
|
||||
public SickRagePingData data { get; set; }
|
||||
public string message { get; set; }
|
||||
public string result { get; set; }
|
||||
}
|
||||
}
|
35
PlexRequests.Api.Models/SickRage/SickRageStatus.cs
Normal file
35
PlexRequests.Api.Models/SickRage/SickRageStatus.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SickRageStatus.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 PlexRequests.Api.Models.SickRage
|
||||
{
|
||||
public static class SickRageStatus
|
||||
{
|
||||
public const string Wanted = "wanted";
|
||||
public const string Skipped = "skipped";
|
||||
public const string Ignored = "Ignored";
|
||||
}
|
||||
}
|
41
PlexRequests.Api.Models/SickRage/SickRageTvAdd.cs
Normal file
41
PlexRequests.Api.Models/SickRage/SickRageTvAdd.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SickRageTvAdd.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 PlexRequests.Api.Models.SickRage
|
||||
{
|
||||
public class SickRageTvAddData
|
||||
{
|
||||
public string name { get; set; }
|
||||
}
|
||||
|
||||
public class SickRageTvAdd
|
||||
{
|
||||
public SickRageTvAddData data { get; set; }
|
||||
public string message { get; set; }
|
||||
public string result { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -45,9 +45,17 @@ namespace PlexRequests.Api
|
|||
private ApiRequest Api { get; set; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public bool AddMovie(string imdbid, string apiKey, string title, Uri baseUrl)
|
||||
public bool AddMovie(string imdbid, string apiKey, string title, Uri baseUrl, string profileId = default(string))
|
||||
{
|
||||
var request = new RestRequest { Resource = "/api/{apikey}/movie.add?title={title}&identifier={imdbid}" };
|
||||
RestRequest request;
|
||||
request = string.IsNullOrEmpty(profileId)
|
||||
? new RestRequest {Resource = "/api/{apikey}/movie.add?title={title}&identifier={imdbid}"}
|
||||
: new RestRequest { Resource = "/api/{apikey}/movie.add?title={title}&identifier={imdbid}&profile_id={profileId}" };
|
||||
|
||||
if (!string.IsNullOrEmpty(profileId))
|
||||
{
|
||||
request.AddUrlSegment("profileId", profileId);
|
||||
}
|
||||
|
||||
request.AddUrlSegment("apikey", apiKey);
|
||||
request.AddUrlSegment("imdbid", imdbid);
|
||||
|
@ -93,5 +101,19 @@ namespace PlexRequests.Api
|
|||
|
||||
return Api.Execute<CouchPotatoStatus>(request,url);
|
||||
}
|
||||
|
||||
public CouchPotatoProfiles GetProfiles(Uri url, string apiKey)
|
||||
{
|
||||
Log.Trace("Getting CP Profiles, ApiKey = {0}", apiKey);
|
||||
var request = new RestRequest
|
||||
{
|
||||
Resource = "api/{apikey}/profile.list/",
|
||||
Method = Method.GET
|
||||
};
|
||||
|
||||
request.AddUrlSegment("apikey", apiKey);
|
||||
|
||||
return Api.Execute<CouchPotatoProfiles>(request, url);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -73,6 +73,7 @@
|
|||
</Compile>
|
||||
<Compile Include="Mocks\MockSonarrApi.cs" />
|
||||
<Compile Include="PushbulletApi.cs" />
|
||||
<Compile Include="SickrageApi.cs" />
|
||||
<Compile Include="SonarrApi.cs" />
|
||||
<Compile Include="CouchPotatoApi.cs" />
|
||||
<Compile Include="MovieBase.cs" />
|
||||
|
|
91
PlexRequests.Api/SickrageApi.cs
Normal file
91
PlexRequests.Api/SickrageApi.cs
Normal file
|
@ -0,0 +1,91 @@
|
|||
#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 NLog;
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Api.Models.SickRage;
|
||||
using RestSharp;
|
||||
|
||||
namespace PlexRequests.Api
|
||||
{
|
||||
public class SickrageApi : ISickRageApi
|
||||
{
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public SickrageApi()
|
||||
{
|
||||
Api = new ApiRequest();
|
||||
}
|
||||
|
||||
private ApiRequest Api { get; }
|
||||
|
||||
|
||||
public SickRageTvAdd AddSeries(int tvdbId, bool latest, string quality, string apiKey,
|
||||
Uri baseUrl)
|
||||
{
|
||||
string status;
|
||||
var futureStatus = SickRageStatus.Wanted;
|
||||
|
||||
status = latest ? SickRageStatus.Skipped : SickRageStatus.Wanted;
|
||||
|
||||
var request = new RestRequest
|
||||
{
|
||||
Resource = "/api/{apiKey}/?cmd=show.addnew",
|
||||
Method = Method.GET
|
||||
};
|
||||
request.AddUrlSegment("apiKey", apiKey);
|
||||
request.AddQueryParameter("tvdbid", tvdbId.ToString());
|
||||
request.AddQueryParameter("status", status);
|
||||
request.AddQueryParameter("future_status", futureStatus);
|
||||
if (!quality.Equals("default", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
request.AddQueryParameter("initial", quality);
|
||||
}
|
||||
|
||||
var obj = Api.Execute<SickRageTvAdd>(request, baseUrl);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public SickRagePing Ping(string apiKey, Uri baseUrl)
|
||||
{
|
||||
var request = new RestRequest
|
||||
{
|
||||
Resource = "/api/{apiKey}/?cmd=sb.ping",
|
||||
Method = Method.GET
|
||||
};
|
||||
|
||||
request.AddUrlSegment("apiKey", apiKey);
|
||||
var obj = Api.ExecuteJson<SickRagePing>(request, baseUrl);
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,5 +69,18 @@ namespace PlexRequests.Api
|
|||
return Api.Execute<TvMazeShow>(request, new Uri(Uri));
|
||||
}
|
||||
|
||||
public TvMazeShow ShowLookupByTheTvDbId(int theTvDbId)
|
||||
{
|
||||
var request = new RestRequest
|
||||
{
|
||||
Method = Method.GET,
|
||||
Resource = "lookup/shows?thetvdb={id}"
|
||||
};
|
||||
request.AddUrlSegment("id", theTvDbId.ToString());
|
||||
request.AddHeader("Content-Type", "application/json");
|
||||
|
||||
return Api.Execute<TvMazeShow>(request, new Uri(Uri));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -94,6 +94,10 @@
|
|||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PlexRequests.Api.Models\PlexRequests.Api.Models.csproj">
|
||||
<Project>{CB37A5F8-6DFC-4554-99D3-A42B502E4591}</Project>
|
||||
<Name>PlexRequests.Api.Models</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\PlexRequests.Api\PlexRequests.Api.csproj">
|
||||
<Project>{8CB8D235-2674-442D-9C6A-35FCAEEB160D}</Project>
|
||||
<Name>PlexRequests.Api</Name>
|
||||
|
|
|
@ -37,12 +37,19 @@ namespace PlexRequests.Core.SettingModels
|
|||
public int Port { get; set; }
|
||||
public string ApiKey { get; set; }
|
||||
public bool Ssl { get; set; }
|
||||
public string ProfileId { get; set; }
|
||||
public string SubDir { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Uri FullUri
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(SubDir))
|
||||
{
|
||||
var formattedSubDir = Ip.ReturnUriWithSubDir(Port, Ssl, SubDir);
|
||||
return formattedSubDir;
|
||||
}
|
||||
var formatted = Ip.ReturnUri(Port, Ssl);
|
||||
return formatted;
|
||||
}
|
||||
|
|
|
@ -36,12 +36,18 @@ namespace PlexRequests.Core.SettingModels
|
|||
public string Ip { get; set; }
|
||||
public int Port { get; set; }
|
||||
public bool Ssl { get; set; }
|
||||
public string SubDir { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Uri FullUri
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(SubDir))
|
||||
{
|
||||
var formattedSubDir = Ip.ReturnUriWithSubDir(Port, Ssl, SubDir);
|
||||
return formattedSubDir;
|
||||
}
|
||||
var formatted = Ip.ReturnUri(Port, Ssl);
|
||||
return formatted;
|
||||
}
|
||||
|
|
|
@ -24,13 +24,36 @@
|
|||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using PlexRequests.Helpers;
|
||||
|
||||
namespace PlexRequests.Core.SettingModels
|
||||
{
|
||||
public class SickRageSettings : Settings
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public string Ip { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string ApiKey { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public string QualityProfile { get; set; }
|
||||
public bool Ssl { get; set; }
|
||||
public string SubDir { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Uri FullUri
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(SubDir))
|
||||
{
|
||||
var formattedSubDir = Ip.ReturnUriWithSubDir(Port, Ssl, SubDir);
|
||||
return formattedSubDir;
|
||||
}
|
||||
var formatted = Ip.ReturnUri(Port, Ssl);
|
||||
return formatted;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ namespace PlexRequests.Core.SettingModels
|
|||
{
|
||||
public class SonarrSettings : Settings
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public string Ip { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string ApiKey { get; set; }
|
||||
|
@ -40,12 +41,18 @@ namespace PlexRequests.Core.SettingModels
|
|||
public bool SeasonFolders { get; set; }
|
||||
public string RootPath { get; set; }
|
||||
public bool Ssl { get; set; }
|
||||
public string SubDir { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Uri FullUri
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(SubDir))
|
||||
{
|
||||
var formattedSubDir = Ip.ReturnUriWithSubDir(Port, Ssl, SubDir);
|
||||
return formattedSubDir;
|
||||
}
|
||||
var formatted = Ip.ReturnUri(Port, Ssl);
|
||||
return formatted;
|
||||
}
|
||||
|
|
|
@ -24,10 +24,13 @@
|
|||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Mono.Data.Sqlite;
|
||||
using PlexRequests.Api;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Store;
|
||||
|
@ -70,20 +73,61 @@ namespace PlexRequests.Core
|
|||
|
||||
private void MigrateDb() // TODO: Remove when no longer needed
|
||||
{
|
||||
var result = new List<long>();
|
||||
RequestedModel[] requestedModels;
|
||||
var repo = new GenericRepository<RequestedModel>(Db);
|
||||
var records = repo.GetAll();
|
||||
var requestedModels = records as RequestedModel[] ?? records.ToArray();
|
||||
if(!requestedModels.Any())
|
||||
try
|
||||
{
|
||||
var records = repo.GetAll();
|
||||
requestedModels = records as RequestedModel[] ?? records.ToArray();
|
||||
}
|
||||
catch (SqliteException)
|
||||
{
|
||||
// There is no requested table so they do not have an old version of the DB
|
||||
return;
|
||||
}
|
||||
|
||||
if (!requestedModels.Any())
|
||||
{ return; }
|
||||
|
||||
var jsonRepo = new JsonRequestService(new RequestJsonRepository(Db, new MemoryCacheProvider()));
|
||||
var result = new List<long>();
|
||||
foreach (var r in requestedModels)
|
||||
|
||||
var api = new TvMazeApi();
|
||||
|
||||
foreach (var r in requestedModels.Where(x => x.Type == RequestType.TvShow))
|
||||
{
|
||||
var id = jsonRepo.AddRequest(r);
|
||||
var show = api.ShowLookupByTheTvDbId(r.ProviderId);
|
||||
|
||||
var model = new RequestedModel
|
||||
{
|
||||
Title = show.name,
|
||||
PosterPath = show.image?.medium,
|
||||
Type = RequestType.TvShow,
|
||||
ProviderId = show.externals.thetvdb ?? 0,
|
||||
ReleaseDate = r.ReleaseDate,
|
||||
AdminNote = r.AdminNote,
|
||||
Approved = r.Approved,
|
||||
Available = r.Available,
|
||||
ImdbId = show.externals.imdb,
|
||||
Issues = r.Issues,
|
||||
LatestTv = r.LatestTv,
|
||||
OtherMessage = r.OtherMessage,
|
||||
Overview = show.summary.RemoveHtml(),
|
||||
RequestedBy = r.RequestedBy,
|
||||
RequestedDate = r.ReleaseDate,
|
||||
Status = show.status
|
||||
};
|
||||
var id = jsonRepo.AddRequest(model);
|
||||
result.Add(id);
|
||||
}
|
||||
|
||||
foreach (var source in requestedModels.Where(x => x.Type== RequestType.Movie))
|
||||
{
|
||||
var id = jsonRepo.AddRequest(source);
|
||||
result.Add(id);
|
||||
}
|
||||
|
||||
|
||||
if (result.Any(x => x == -1))
|
||||
{
|
||||
throw new SqliteException("Could not migrate the DB!");
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace PlexRequests.Helpers.Tests
|
||||
|
@ -35,7 +36,7 @@ namespace PlexRequests.Helpers.Tests
|
|||
{
|
||||
[TestCaseSource(nameof(UriData))]
|
||||
public void CreateUri1(string uri, Uri expected)
|
||||
{
|
||||
{
|
||||
var result = uri.ReturnUri();
|
||||
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
|
@ -58,6 +59,14 @@ namespace PlexRequests.Helpers.Tests
|
|||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(UriDataWithSubDir))]
|
||||
public void CreateUriWithSubDir(string uri, int port, bool ssl, string subDir, Uri expected)
|
||||
{
|
||||
var result = uri.ReturnUriWithSubDir(port, ssl, subDir);
|
||||
|
||||
Assert.That(result, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
static readonly object[] UriData =
|
||||
{
|
||||
new object[] { "google.com", new Uri("http://google.com/"), },
|
||||
|
@ -84,5 +93,13 @@ namespace PlexRequests.Helpers.Tests
|
|||
new object[] {"http://www.google.com/id=2", 443, new Uri("http://www.google.com:443/id=2") },
|
||||
new object[] {"https://www.google.com/id=2", 443, new Uri("https://www.google.com:443/id=2") },
|
||||
};
|
||||
|
||||
static readonly object[] UriDataWithSubDir =
|
||||
{
|
||||
new object[] {"www.google.com", 80, false,"test", new Uri("http://www.google.com:80/test"), },
|
||||
new object[] {"www.google.com", 443, false,"test", new Uri("http://www.google.com:443/test") },
|
||||
new object[] {"http://www.google.com", 443, true,"test", new Uri("https://www.google.com:443/test") },
|
||||
new object[] {"https://www.google.com", 443,true,"test", new Uri("https://www.google.com:443/test") },
|
||||
};
|
||||
}
|
||||
}
|
|
@ -33,6 +33,10 @@ namespace PlexRequests.Helpers
|
|||
{
|
||||
public static string RemoveHtml(this string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
var step1 = Regex.Replace(value, @"<[^>]+>| ", "").Trim();
|
||||
var step2 = Regex.Replace(step1, @"\s{2,}", " ");
|
||||
return step2;
|
||||
|
|
|
@ -53,7 +53,10 @@ namespace PlexRequests.Helpers
|
|||
/// </summary>
|
||||
/// <param name="val">The value.</param>
|
||||
/// <param name="port">The port.</param>
|
||||
/// <param name="ssl">if set to <c>true</c> [SSL].</param>
|
||||
/// <param name="subdir">The subdir.</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ApplicationSettingsException">The URI is null, please check your settings to make sure you have configured the applications correctly.</exception>
|
||||
/// <exception cref="System.Exception"></exception>
|
||||
public static Uri ReturnUri(this string val, int port, bool ssl = default(bool))
|
||||
{
|
||||
|
@ -93,5 +96,21 @@ namespace PlexRequests.Helpers
|
|||
throw new Exception(exception.Message, exception);
|
||||
}
|
||||
}
|
||||
|
||||
public static Uri ReturnUriWithSubDir(this string val, int port, bool ssl, string subDir)
|
||||
{
|
||||
var uriBuilder = new UriBuilder(val);
|
||||
if (ssl)
|
||||
{
|
||||
uriBuilder.Scheme = Uri.UriSchemeHttps;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(subDir))
|
||||
{
|
||||
uriBuilder.Path = subDir;
|
||||
}
|
||||
uriBuilder.Port = port;
|
||||
|
||||
return uriBuilder.Uri;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -108,7 +108,7 @@ namespace PlexRequests.Services.Tests
|
|||
var requestMock = new Mock<IRequestService>();
|
||||
var plexMock = new Mock<IPlexApi>();
|
||||
|
||||
var searchResult = new PlexSearch { Video = new List<Video> { new Video { Title = "wrong title", Year = "2011"} } };
|
||||
var searchResult = new PlexSearch { Video = new List<Video> { new Video { Title = "wrong tistle", Year = "2011"} } };
|
||||
|
||||
settingsMock.Setup(x => x.GetSettings()).Returns(new PlexSettings { Ip = "abc" });
|
||||
authMock.Setup(x => x.GetSettings()).Returns(new AuthenticationSettings { PlexAuthToken = "abc" });
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace PlexRequests.Services
|
|||
{
|
||||
ConfigurationReader = new ConfigurationReader();
|
||||
var repo = new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider());
|
||||
Checker = new PlexAvailabilityChecker(new SettingsServiceV2<PlexSettings>(repo), new SettingsServiceV2<AuthenticationSettings>(repo), new RequestService(new GenericRepository<RequestedModel>(new DbConfiguration(new SqliteFactory()))), new PlexApi());
|
||||
Checker = new PlexAvailabilityChecker(new SettingsServiceV2<PlexSettings>(repo), new SettingsServiceV2<AuthenticationSettings>(repo), new JsonRequestService(new RequestJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider())), new PlexApi());
|
||||
HostingEnvironment.RegisterObject(this);
|
||||
}
|
||||
|
||||
|
@ -82,4 +82,4 @@ namespace PlexRequests.Services
|
|||
{
|
||||
void Start(Configuration c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,11 +97,21 @@ namespace PlexRequests.Services
|
|||
{
|
||||
throw new ApplicationSettingsException("The settings are not configured for Plex or Authentication");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(year))
|
||||
{
|
||||
var results = PlexApi.SearchContent(authSettings.PlexAuthToken, title, plexSettings.FullUri);
|
||||
var result = results.Video?.FirstOrDefault(x => x.Title.Contains(title) && x.Year == year);
|
||||
var directoryTitle = results.Directory?.Title == title && results.Directory?.Year == year;
|
||||
return result?.Title != null || directoryTitle;
|
||||
}
|
||||
else
|
||||
{
|
||||
var results = PlexApi.SearchContent(authSettings.PlexAuthToken, title, plexSettings.FullUri);
|
||||
var result = results.Video?.FirstOrDefault(x => x.Title.Contains(title));
|
||||
var directoryTitle = results.Directory?.Title == title;
|
||||
return result?.Title != null || directoryTitle;
|
||||
}
|
||||
|
||||
var results = PlexApi.SearchContent(authSettings.PlexAuthToken, title, plexSettings.FullUri);
|
||||
var result = results.Video?.FirstOrDefault(x => x.Title == title && x.Year == year);
|
||||
var directoryTitle = results.Directory?.Title == title && results.Directory?.Year == year;
|
||||
return result?.Title != null || directoryTitle;
|
||||
}
|
||||
|
||||
private bool ValidateSettings(PlexSettings plex, AuthenticationSettings auth, IEnumerable<RequestedModel> requests)
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace PlexRequests.Store.Repository
|
|||
|
||||
public RequestBlobs Get(int id)
|
||||
{
|
||||
var key = TypeName + "Get";
|
||||
var key = TypeName + "Get" + id;
|
||||
var item = Cache.GetOrSet(key, () =>
|
||||
{
|
||||
using (var con = Db.DbConnection())
|
||||
|
@ -112,8 +112,8 @@ namespace PlexRequests.Store.Repository
|
|||
|
||||
public bool UpdateAll(IEnumerable<RequestBlobs> entity)
|
||||
{
|
||||
ResetCache();
|
||||
var result = new HashSet<bool>();
|
||||
|
||||
using (var db = Db.DbConnection())
|
||||
{
|
||||
db.Open();
|
||||
|
|
|
@ -36,24 +36,3 @@ CREATE TABLE IF NOT EXISTS Log
|
|||
CallSite varchar(100) NOT NULL,
|
||||
Exception varchar(100) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS Requested
|
||||
(
|
||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
Type INTEGER NOT NULL,
|
||||
ProviderId INTEGER NOT NULL,
|
||||
ImdbId varchar(50),
|
||||
Overview varchar(50),
|
||||
Title varchar(50) NOT NULL,
|
||||
PosterPath varchar(50) NOT NULL,
|
||||
ReleaseDate varchar(50) NOT NULL,
|
||||
Status varchar(50) NOT NULL,
|
||||
AdminNote varchar(50),
|
||||
Approved INTEGER NOT NULL,
|
||||
LatestTv INTEGER NOT NULL,
|
||||
RequestedBy varchar(50),
|
||||
RequestedDate varchar(50) NOT NULL,
|
||||
Available INTEGER(50),
|
||||
Issues INTEGER,
|
||||
OtherMessage varchar(50)
|
||||
);
|
|
@ -52,11 +52,13 @@ namespace PlexRequests.UI.Tests
|
|||
private Mock<ISettingsService<AuthenticationSettings>> AuthMock { get; set; }
|
||||
private Mock<ISettingsService<PlexSettings>> PlexSettingsMock { get; set; }
|
||||
private Mock<ISettingsService<SonarrSettings>> SonarrSettingsMock { get; set; }
|
||||
private Mock<ISettingsService<SickRageSettings>> SickRageSettingsMock { get; set; }
|
||||
private Mock<ISettingsService<EmailNotificationSettings>> EmailMock { get; set; }
|
||||
private Mock<ISettingsService<PushbulletNotificationSettings>> PushbulletSettings { get; set; }
|
||||
private Mock<IPlexApi> PlexMock { get; set; }
|
||||
private Mock<ISonarrApi> SonarrApiMock { get; set; }
|
||||
private Mock<IPushbulletApi> PushbulletApi { get; set; }
|
||||
private Mock<ICouchPotatoApi> CpApi { get; set; }
|
||||
|
||||
private ConfigurableBootstrapper Bootstrapper { get; set; }
|
||||
|
||||
|
@ -79,6 +81,8 @@ namespace PlexRequests.UI.Tests
|
|||
EmailMock = new Mock<ISettingsService<EmailNotificationSettings>>();
|
||||
PushbulletApi = new Mock<IPushbulletApi>();
|
||||
PushbulletSettings = new Mock<ISettingsService<PushbulletNotificationSettings>>();
|
||||
CpApi = new Mock<ICouchPotatoApi>();
|
||||
SickRageSettingsMock = new Mock<ISettingsService<SickRageSettings>>();
|
||||
|
||||
Bootstrapper = new ConfigurableBootstrapper(with =>
|
||||
{
|
||||
|
@ -93,6 +97,8 @@ namespace PlexRequests.UI.Tests
|
|||
with.Dependency(EmailMock.Object);
|
||||
with.Dependency(PushbulletApi.Object);
|
||||
with.Dependency(PushbulletSettings.Object);
|
||||
with.Dependency(CpApi.Object);
|
||||
with.Dependency(SickRageSettingsMock.Object);
|
||||
with.RootPathProvider<TestRootPathProvider>();
|
||||
with.RequestStartup((container, pipelines, context) =>
|
||||
{
|
||||
|
|
|
@ -36,7 +36,6 @@ using Newtonsoft.Json;
|
|||
using NUnit.Framework;
|
||||
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Api.Models;
|
||||
using PlexRequests.Api.Models.Plex;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
|
@ -81,7 +80,7 @@ namespace PlexRequests.UI.Tests
|
|||
with.Header("Accept", "application/json");
|
||||
with.FormValue("Username", "abc");
|
||||
});
|
||||
|
||||
|
||||
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
|
||||
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc"));
|
||||
|
||||
|
@ -142,6 +141,7 @@ namespace PlexRequests.UI.Tests
|
|||
|
||||
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
|
||||
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
|
||||
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(new PlexAccount());
|
||||
|
||||
var bootstrapper = new ConfigurableBootstrapper(with =>
|
||||
{
|
||||
|
@ -188,6 +188,7 @@ namespace PlexRequests.UI.Tests
|
|||
|
||||
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
|
||||
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
|
||||
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(new PlexAccount());
|
||||
|
||||
var bootstrapper = new ConfigurableBootstrapper(with =>
|
||||
{
|
||||
|
@ -245,6 +246,7 @@ namespace PlexRequests.UI.Tests
|
|||
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
|
||||
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
|
||||
PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(plexAuth);
|
||||
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(new PlexAccount());
|
||||
|
||||
var bootstrapper = new ConfigurableBootstrapper(with =>
|
||||
{
|
||||
|
@ -376,7 +378,7 @@ namespace PlexRequests.UI.Tests
|
|||
with.RootPathProvider<TestRootPathProvider>();
|
||||
});
|
||||
|
||||
bootstrapper.WithSession(new Dictionary<string, object> { {SessionKeys.UsernameKey, "abc"} });
|
||||
bootstrapper.WithSession(new Dictionary<string, object> { { SessionKeys.UsernameKey, "abc" } });
|
||||
|
||||
var browser = new Browser(bootstrapper);
|
||||
var result = browser.Get("/userlogin/logout", with =>
|
||||
|
@ -388,5 +390,108 @@ namespace PlexRequests.UI.Tests
|
|||
Assert.That(HttpStatusCode.SeeOther, Is.EqualTo(result.StatusCode));
|
||||
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoginWithOwnerUsernameSuccessfully()
|
||||
{
|
||||
var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" };
|
||||
var plexFriends = new PlexFriends
|
||||
{
|
||||
User = new[]
|
||||
{
|
||||
new UserFriends()
|
||||
}
|
||||
};
|
||||
|
||||
var account = new PlexAccount { Username = "Jamie" };
|
||||
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
|
||||
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
|
||||
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(account);
|
||||
PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(new PlexAuthentication { user = new User { username = "Jamie" } });
|
||||
|
||||
var bootstrapper = new ConfigurableBootstrapper(with =>
|
||||
{
|
||||
with.Module<UserLoginModule>();
|
||||
with.Dependency(AuthMock.Object);
|
||||
with.Dependency(PlexMock.Object);
|
||||
with.RootPathProvider<TestRootPathProvider>();
|
||||
});
|
||||
|
||||
bootstrapper.WithSession(new Dictionary<string, object>());
|
||||
|
||||
var browser = new Browser(bootstrapper);
|
||||
var result = browser.Post("/userlogin", with =>
|
||||
{
|
||||
with.HttpRequest();
|
||||
with.Header("Accept", "application/json");
|
||||
with.FormValue("Username", "Jamie");
|
||||
});
|
||||
|
||||
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
|
||||
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("Jamie"));
|
||||
|
||||
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
|
||||
Assert.That(body.Result, Is.EqualTo(true));
|
||||
AuthMock.Verify(x => x.GetSettings(), Times.Once);
|
||||
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
|
||||
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoginWithOwnerUsernameAndPasswordSuccessfully()
|
||||
{
|
||||
var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" };
|
||||
var plexFriends = new PlexFriends
|
||||
{
|
||||
User = new[]
|
||||
{
|
||||
new UserFriends()
|
||||
}
|
||||
};
|
||||
var plexAuth = new PlexAuthentication
|
||||
{
|
||||
user = new User
|
||||
{
|
||||
authentication_token = "abc",
|
||||
username = "Jamie"
|
||||
}
|
||||
};
|
||||
|
||||
var account = new PlexAccount { Username = "Jamie" };
|
||||
|
||||
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
|
||||
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
|
||||
PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(plexAuth);
|
||||
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(account);
|
||||
|
||||
var bootstrapper = new ConfigurableBootstrapper(with =>
|
||||
{
|
||||
with.Module<UserLoginModule>();
|
||||
with.Dependency(AuthMock.Object);
|
||||
with.Dependency(PlexMock.Object);
|
||||
with.RootPathProvider<TestRootPathProvider>();
|
||||
});
|
||||
|
||||
bootstrapper.WithSession(new Dictionary<string, object>());
|
||||
|
||||
var browser = new Browser(bootstrapper);
|
||||
var result = browser.Post("/userlogin", with =>
|
||||
{
|
||||
with.HttpRequest();
|
||||
with.Header("Accept", "application/json");
|
||||
with.FormValue("Username", "jamie");
|
||||
with.FormValue("Password", "abc");
|
||||
});
|
||||
|
||||
|
||||
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
|
||||
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("jamie"));
|
||||
|
||||
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
|
||||
Assert.That(body.Result, Is.EqualTo(true));
|
||||
AuthMock.Verify(x => x.GetSettings(), Times.Once);
|
||||
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
|
||||
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -62,33 +62,34 @@ namespace PlexRequests.UI
|
|||
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
|
||||
{
|
||||
container.Register<IUserMapper, UserMapper>();
|
||||
|
||||
container.Register<ISqliteConfiguration, DbConfiguration>(new DbConfiguration(new SqliteFactory()));
|
||||
|
||||
container.Register<ISettingsRepository, SettingsJsonRepository>();
|
||||
container.Register<ICacheProvider, MemoryCacheProvider>();
|
||||
|
||||
// Settings
|
||||
container.Register<ISettingsService<PlexRequestSettings>, SettingsServiceV2<PlexRequestSettings>>();
|
||||
container.Register<ISettingsService<CouchPotatoSettings>, SettingsServiceV2<CouchPotatoSettings>>();
|
||||
container.Register<ISettingsService<AuthenticationSettings>, SettingsServiceV2<AuthenticationSettings>>();
|
||||
container.Register<ISettingsService<PlexSettings>, SettingsServiceV2<PlexSettings>>();
|
||||
container.Register<ISettingsService<SonarrSettings>, SettingsServiceV2<SonarrSettings>>();
|
||||
container.Register<ISettingsService<SickRageSettings>, SettingsServiceV2<SickRageSettings>>();
|
||||
container.Register<ISettingsService<EmailNotificationSettings>, SettingsServiceV2<EmailNotificationSettings>>();
|
||||
container.Register<ISettingsService<PushbulletNotificationSettings>, SettingsServiceV2<PushbulletNotificationSettings>>();
|
||||
|
||||
// Repo's
|
||||
container.Register<IRepository<RequestedModel>, GenericRepository<RequestedModel>>();
|
||||
container.Register<IRequestService, JsonRequestService>();
|
||||
container.Register<ISettingsRepository, SettingsJsonRepository>();
|
||||
|
||||
// Services
|
||||
container.Register<IAvailabilityChecker, PlexAvailabilityChecker>();
|
||||
container.Register<IConfigurationReader, ConfigurationReader>();
|
||||
container.Register<IIntervals, UpdateInterval>();
|
||||
|
||||
// Api's
|
||||
container.Register<ICouchPotatoApi, CouchPotatoApi>();
|
||||
container.Register<IPushbulletApi, PushbulletApi>();
|
||||
|
||||
container.Register<ISickRageApi, SickrageApi>();
|
||||
container.Register<ISonarrApi, SonarrApi>();
|
||||
//container.Register<ISonarrApi, MockSonarrApi>();
|
||||
|
||||
|
||||
container.Register<IPlexApi, PlexApi>();
|
||||
|
||||
SubscribeAllObservers(container);
|
||||
|
@ -101,7 +102,7 @@ namespace PlexRequests.UI
|
|||
TaskManager.Initialize(new PlexRegistry());
|
||||
|
||||
CookieBasedSessions.Enable(pipelines, CryptographyConfiguration.Default);
|
||||
|
||||
|
||||
StaticConfiguration.DisableErrorTraces = false;
|
||||
|
||||
base.ApplicationStartup(container, pipelines);
|
||||
|
|
|
@ -120,3 +120,9 @@ label {
|
|||
background-color: #5cb85c !important;
|
||||
border-color: #5cb85c !important; }
|
||||
|
||||
#movieList .mix {
|
||||
display: none; }
|
||||
|
||||
#tvList .mix {
|
||||
display: none; }
|
||||
|
||||
|
|
2
PlexRequests.UI/Content/custom.min.css
vendored
2
PlexRequests.UI/Content/custom.min.css
vendored
|
@ -1 +1 @@
|
|||
@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.btn{border-radius:.25rem !important;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#4e5d6c !important;color:#fff !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}
|
||||
@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.btn{border-radius:.25rem !important;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#4e5d6c !important;color:#fff !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}#movieList .mix{display:none;}#tvList .mix{display:none;}
|
|
@ -157,3 +157,10 @@ label {
|
|||
background-color: $success-colour $i;
|
||||
border-color: $success-colour $i;
|
||||
}
|
||||
|
||||
#movieList .mix{
|
||||
display: none;
|
||||
}
|
||||
#tvList .mix{
|
||||
display: none;
|
||||
}
|
2098
PlexRequests.UI/Content/jquery.mixitup.js
Normal file
2098
PlexRequests.UI/Content/jquery.mixitup.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,23 @@ var tvimer = 0;
|
|||
movieLoad();
|
||||
tvLoad();
|
||||
|
||||
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
var target = $(e.target).attr('href');
|
||||
if (target === "#TvShowTab") {
|
||||
if (!$('#tvList').mixItUp('isLoaded')) {
|
||||
$('#tvList').mixItUp({
|
||||
layout: {
|
||||
display: 'block'
|
||||
},
|
||||
load: {
|
||||
filter: 'all'
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Approve all
|
||||
$('#approveAll').click(function () {
|
||||
$.ajax({
|
||||
|
@ -210,7 +227,7 @@ $(document).on("click", ".clear", function (e) {
|
|||
|
||||
if (checkJsonResponse(response)) {
|
||||
generateNotify("Success! Issues Cleared.", "info");
|
||||
$('#issueArea').html("<div>Issue: None</div>");
|
||||
$('#issueArea'+buttonId).html("<div>Issue: None</div>");
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
|
@ -274,6 +291,14 @@ function movieLoad() {
|
|||
var html = searchTemplate(context);
|
||||
$("#movieList").append(html);
|
||||
});
|
||||
$('#movieList').mixItUp({
|
||||
layout: {
|
||||
display: 'block'
|
||||
},
|
||||
load: {
|
||||
filter: 'all'
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
77
PlexRequests.UI/Helpers/TvSender.cs
Normal file
77
PlexRequests.UI/Helpers/TvSender.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: TvSender.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 Nancy;
|
||||
using NLog;
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Api.Models.SickRage;
|
||||
using PlexRequests.Api.Models.Sonarr;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.UI.Models;
|
||||
|
||||
namespace PlexRequests.UI.Helpers
|
||||
{
|
||||
public class TvSender
|
||||
{
|
||||
public TvSender(ISonarrApi sonarrApi, ISickRageApi srApi)
|
||||
{
|
||||
SonarrApi = sonarrApi;
|
||||
SickrageApi = srApi;
|
||||
}
|
||||
private ISonarrApi SonarrApi { get; }
|
||||
private ISickRageApi SickrageApi { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public SonarrAddSeries SendToSonarr(SonarrSettings sonarrSettings, RequestedModel model)
|
||||
{
|
||||
int qualityProfile;
|
||||
int.TryParse(sonarrSettings.QualityProfile, out qualityProfile);
|
||||
var result = SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile,
|
||||
sonarrSettings.SeasonFolders, sonarrSettings.RootPath, model.LatestTv, sonarrSettings.ApiKey,
|
||||
sonarrSettings.FullUri);
|
||||
|
||||
Log.Trace("Sonarr Add Result: ");
|
||||
Log.Trace(result.DumpJson());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public SickRageTvAdd SendToSickRage(SickRageSettings sickRageSettings, RequestedModel model)
|
||||
{
|
||||
var result = SickrageApi.AddSeries(model.ProviderId, model.LatestTv, sickRageSettings.QualityProfile,
|
||||
sickRageSettings.ApiKey, sickRageSettings.FullUri);
|
||||
|
||||
Log.Trace("SickRage Add Result: ");
|
||||
Log.Trace(result.DumpJson());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -54,11 +54,13 @@ namespace PlexRequests.UI.Modules
|
|||
private ISettingsService<AuthenticationSettings> AuthService { get; }
|
||||
private ISettingsService<PlexSettings> PlexService { get; }
|
||||
private ISettingsService<SonarrSettings> SonarrService { get; }
|
||||
private ISettingsService<SickRageSettings> SickRageService { get; }
|
||||
private ISettingsService<EmailNotificationSettings> EmailService { get; }
|
||||
private ISettingsService<PushbulletNotificationSettings> PushbulletService { get; }
|
||||
private IPlexApi PlexApi { get; }
|
||||
private ISonarrApi SonarrApi { get; }
|
||||
private PushbulletApi PushbulletApi { get; }
|
||||
private ICouchPotatoApi CpApi { get; }
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
public AdminModule(ISettingsService<PlexRequestSettings> rpService,
|
||||
|
@ -66,11 +68,13 @@ namespace PlexRequests.UI.Modules
|
|||
ISettingsService<AuthenticationSettings> auth,
|
||||
ISettingsService<PlexSettings> plex,
|
||||
ISettingsService<SonarrSettings> sonarr,
|
||||
ISettingsService<SickRageSettings> sickrage,
|
||||
ISonarrApi sonarrApi,
|
||||
ISettingsService<EmailNotificationSettings> email,
|
||||
IPlexApi plexApi,
|
||||
ISettingsService<PushbulletNotificationSettings> pbSettings,
|
||||
PushbulletApi pbApi) : base("admin")
|
||||
PushbulletApi pbApi,
|
||||
ICouchPotatoApi cpApi) : base("admin")
|
||||
{
|
||||
RpService = rpService;
|
||||
CpService = cpService;
|
||||
|
@ -82,6 +86,8 @@ namespace PlexRequests.UI.Modules
|
|||
PlexApi = plexApi;
|
||||
PushbulletService = pbSettings;
|
||||
PushbulletApi = pbApi;
|
||||
CpApi = cpApi;
|
||||
SickRageService = sickrage;
|
||||
|
||||
#if !DEBUG
|
||||
this.RequiresAuthentication();
|
||||
|
@ -106,7 +112,11 @@ namespace PlexRequests.UI.Modules
|
|||
Get["/sonarr"] = _ => Sonarr();
|
||||
Post["/sonarr"] = _ => SaveSonarr();
|
||||
|
||||
Get["/sickrage"] = _ => Sickrage();
|
||||
Post["/sickrage"] = _ => SaveSickrage();
|
||||
|
||||
Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles();
|
||||
Post["/cpprofiles"] = _ => GetCpProfiles();
|
||||
|
||||
Get["/emailnotification"] = _ => EmailNotifications();
|
||||
Post["/emailnotification"] = _ => SaveEmailNotifications();
|
||||
|
@ -279,7 +289,11 @@ namespace PlexRequests.UI.Modules
|
|||
{
|
||||
return Response.AsJson(valid.SendJsonError());
|
||||
}
|
||||
|
||||
var sickRageEnabled = SickRageService.GetSettings().Enabled;
|
||||
if (sickRageEnabled)
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "SickRage is enabled, we cannot enable Sonarr and SickRage" });
|
||||
}
|
||||
var result = SonarrService.SaveSettings(sonarrSettings);
|
||||
|
||||
return Response.AsJson(result
|
||||
|
@ -287,6 +301,35 @@ namespace PlexRequests.UI.Modules
|
|||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||
}
|
||||
|
||||
private Negotiator Sickrage()
|
||||
{
|
||||
var settings = SickRageService.GetSettings();
|
||||
|
||||
return View["Sickrage", settings];
|
||||
}
|
||||
|
||||
private Response SaveSickrage()
|
||||
{
|
||||
var sickRageSettings = this.Bind<SickRageSettings>();
|
||||
|
||||
var valid = this.Validate(sickRageSettings);
|
||||
if (!valid.IsValid)
|
||||
{
|
||||
return Response.AsJson(valid.SendJsonError());
|
||||
}
|
||||
|
||||
var sonarrEnabled = SonarrService.GetSettings().Enabled;
|
||||
if (sonarrEnabled)
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Sonarr is enabled, we cannot enable Sonarr and SickRage" });
|
||||
}
|
||||
var result = SickRageService.SaveSettings(sickRageSettings);
|
||||
|
||||
return Response.AsJson(result
|
||||
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for SickRage!" }
|
||||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||
}
|
||||
|
||||
private Response GetSonarrQualityProfiles()
|
||||
{
|
||||
var settings = this.Bind<SonarrSettings>();
|
||||
|
@ -354,5 +397,13 @@ namespace PlexRequests.UI.Modules
|
|||
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Pushbullet Notifications!" }
|
||||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||
}
|
||||
|
||||
private Response GetCpProfiles()
|
||||
{
|
||||
var settings = this.Bind<CouchPotatoSettings>();
|
||||
var profiles = CpApi.GetProfiles(settings.FullUri, settings.ApiKey);
|
||||
|
||||
return Response.AsJson(profiles);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ namespace PlexRequests.UI.Modules
|
|||
{
|
||||
|
||||
public ApplicationTesterModule(ICouchPotatoApi cpApi, ISonarrApi sonarrApi, IPlexApi plexApi,
|
||||
ISettingsService<AuthenticationSettings> authSettings) : base("test")
|
||||
ISettingsService<AuthenticationSettings> authSettings, ISickRageApi srApi) : base("test")
|
||||
{
|
||||
this.RequiresAuthentication();
|
||||
|
||||
|
@ -51,10 +51,12 @@ namespace PlexRequests.UI.Modules
|
|||
SonarrApi = sonarrApi;
|
||||
PlexApi = plexApi;
|
||||
AuthSettings = authSettings;
|
||||
SickRageApi = srApi;
|
||||
|
||||
Post["/cp"] = _ => CouchPotatoTest();
|
||||
Post["/sonarr"] = _ => SonarrTest();
|
||||
Post["/plex"] = _ => PlexTest();
|
||||
Post["/sickrage"] = _ => SickRageTest();
|
||||
|
||||
}
|
||||
|
||||
|
@ -62,6 +64,7 @@ namespace PlexRequests.UI.Modules
|
|||
private ISonarrApi SonarrApi { get; }
|
||||
private ICouchPotatoApi CpApi { get; }
|
||||
private IPlexApi PlexApi { get; }
|
||||
private ISickRageApi SickRageApi { get; }
|
||||
private ISettingsService<AuthenticationSettings> AuthSettings { get; }
|
||||
|
||||
private Response CouchPotatoTest()
|
||||
|
@ -99,7 +102,7 @@ namespace PlexRequests.UI.Modules
|
|||
: Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Sonarr, please check your settings." });
|
||||
|
||||
}
|
||||
catch (ApplicationException e) // Exceptions are expected if we cannot connect so we will just log and swallow them.
|
||||
catch (ApplicationException 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(e);
|
||||
|
@ -128,7 +131,7 @@ namespace PlexRequests.UI.Modules
|
|||
: Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Plex, please check your settings." });
|
||||
|
||||
}
|
||||
catch (ApplicationException e) // Exceptions are expected if we cannot connect so we will just log and swallow them.
|
||||
catch (ApplicationException e) // Exceptions are expected, if we cannot connect so we will just log and swallow them.
|
||||
{
|
||||
Log.Warn("Exception thrown when attempting to get Plex's status: ");
|
||||
Log.Warn(e);
|
||||
|
@ -140,5 +143,30 @@ namespace PlexRequests.UI.Modules
|
|||
return Response.AsJson(new JsonResponseModel { Result = false, Message = message });
|
||||
}
|
||||
}
|
||||
|
||||
private Response SickRageTest()
|
||||
{
|
||||
var sickRageSettings = this.Bind<SickRageSettings>();
|
||||
|
||||
try
|
||||
{
|
||||
var status = SickRageApi.Ping(sickRageSettings.ApiKey, sickRageSettings.FullUri);
|
||||
return status?.result == "success"
|
||||
? Response.AsJson(new JsonResponseModel { Result = true, Message = "Connected to SickRage successfully!" })
|
||||
: Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to SickRage, please check your settings." });
|
||||
|
||||
}
|
||||
catch (ApplicationException e) // Exceptions are expected, if we cannot connect so we will just log and swallow them.
|
||||
{
|
||||
Log.Warn("Exception thrown when attempting to get SickRage's status: ");
|
||||
Log.Warn(e);
|
||||
var message = $"Could not connect to SickRage, please check your settings. <strong>Exception Message:</strong> {e.Message}";
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
message = $"Could not connect to SickRage, please check your settings. <strong>Exception Message:</strong> {e.InnerException.Message}";
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = message });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using System.Linq.Expressions;
|
||||
using Nancy;
|
||||
using Nancy.Security;
|
||||
|
||||
|
@ -36,7 +36,9 @@ using PlexRequests.Api;
|
|||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.UI.Helpers;
|
||||
using PlexRequests.UI.Models;
|
||||
|
||||
namespace PlexRequests.UI.Modules
|
||||
|
@ -45,7 +47,7 @@ namespace PlexRequests.UI.Modules
|
|||
{
|
||||
|
||||
public ApprovalModule(IRequestService service, ISettingsService<CouchPotatoSettings> cpService, ICouchPotatoApi cpApi, ISonarrApi sonarrApi,
|
||||
ISettingsService<SonarrSettings> sonarrSettings) : base("approval")
|
||||
ISettingsService<SonarrSettings> sonarrSettings, ISickRageApi srApi, ISettingsService<SickRageSettings> srSettings) : base("approval")
|
||||
{
|
||||
this.RequiresAuthentication();
|
||||
|
||||
|
@ -54,6 +56,8 @@ namespace PlexRequests.UI.Modules
|
|||
CpApi = cpApi;
|
||||
SonarrApi = sonarrApi;
|
||||
SonarrSettings = sonarrSettings;
|
||||
SickRageApi = srApi;
|
||||
SickRageSettings = srSettings;
|
||||
|
||||
Post["/approve"] = parameters => Approve((int)Request.Form.requestid);
|
||||
Post["/approveall"] = x => ApproveAll();
|
||||
|
@ -63,8 +67,10 @@ namespace PlexRequests.UI.Modules
|
|||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private ISettingsService<SonarrSettings> SonarrSettings { get; }
|
||||
private ISettingsService<SickRageSettings> SickRageSettings { get; }
|
||||
private ISettingsService<CouchPotatoSettings> CpService { get; }
|
||||
private ISonarrApi SonarrApi { get; }
|
||||
private ISickRageApi SickRageApi { get; }
|
||||
private ICouchPotatoApi CpApi { get; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -74,6 +80,7 @@ namespace PlexRequests.UI.Modules
|
|||
/// <returns></returns>
|
||||
private Response Approve(int requestId)
|
||||
{
|
||||
Log.Info("approving request {0}", requestId);
|
||||
if (!Context.CurrentUser.IsAuthenticated())
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "You are not an Admin, so you cannot approve any requests." });
|
||||
|
@ -100,20 +107,63 @@ namespace PlexRequests.UI.Modules
|
|||
|
||||
private Response RequestTvAndUpdateStatus(RequestedModel request)
|
||||
{
|
||||
var sonarrSettings = SonarrSettings.GetSettings();
|
||||
int qualityProfile;
|
||||
int.TryParse(sonarrSettings.QualityProfile, out qualityProfile);
|
||||
var result = SonarrApi.AddSeries(request.ProviderId, request.Title, qualityProfile,
|
||||
sonarrSettings.SeasonFolders, sonarrSettings.RootPath, request.LatestTv, sonarrSettings.ApiKey,
|
||||
sonarrSettings.FullUri);
|
||||
var sender = new TvSender(SonarrApi, SickRageApi);
|
||||
|
||||
if (!string.IsNullOrEmpty(result.title))
|
||||
var sonarrSettings = SonarrSettings.GetSettings();
|
||||
if (sonarrSettings.Enabled)
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||
Log.Trace("Sending to Sonarr");
|
||||
var result = sender.SendToSonarr(sonarrSettings, request);
|
||||
Log.Trace("Sonarr Result: ");
|
||||
Log.Trace(result.DumpJson());
|
||||
if (!string.IsNullOrEmpty(result.title))
|
||||
{
|
||||
Log.Info("Sent successfully, Approving request now.");
|
||||
request.Approved = true;
|
||||
var requestResult = Service.UpdateRequest(request);
|
||||
Log.Trace("Approval result: {0}",requestResult);
|
||||
if (requestResult)
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Updated Sonarr but could not approve it in PlexRequests :("});
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel
|
||||
{
|
||||
Result = false,
|
||||
Message = "Could not add the series to Sonarr"
|
||||
});
|
||||
}
|
||||
|
||||
var srSettings = SickRageSettings.GetSettings();
|
||||
if (srSettings.Enabled)
|
||||
{
|
||||
Log.Trace("Sending to SickRage");
|
||||
var result = sender.SendToSickRage(srSettings, request);
|
||||
Log.Trace("SickRage Result: ");
|
||||
Log.Trace(result.DumpJson());
|
||||
if (result?.result == "success")
|
||||
{
|
||||
Log.Info("Sent successfully, Approving request now.");
|
||||
request.Approved = true;
|
||||
var requestResult = Service.UpdateRequest(request);
|
||||
Log.Trace("Approval result: {0}", requestResult);
|
||||
if (requestResult)
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Updated SickRage but could not approve it in PlexRequests :(" });
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel
|
||||
{
|
||||
Result = false,
|
||||
Message = result?.message != null ? "<b>Message From SickRage: </b>" + result.message : "Could not add the series to SickRage"
|
||||
});
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel
|
||||
{
|
||||
Result = false, Message = "Could not add the series to Sonarr"
|
||||
Result = false,
|
||||
Message = "SickRage or Sonarr are not set up!"
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -127,7 +177,7 @@ namespace PlexRequests.UI.Modules
|
|||
var cpSettings = CpService.GetSettings();
|
||||
var cp = new CouchPotatoApi();
|
||||
Log.Info("Adding movie to CP : {0}", request.Title);
|
||||
var result = cp.AddMovie(request.ImdbId, cpSettings.ApiKey, request.Title, cpSettings.FullUri);
|
||||
var result = cp.AddMovie(request.ImdbId, cpSettings.ApiKey, request.Title, cpSettings.FullUri, cpSettings.ProfileId);
|
||||
Log.Trace("Adding movie to CP result {0}", result);
|
||||
if (result)
|
||||
{
|
||||
|
@ -184,12 +234,42 @@ namespace PlexRequests.UI.Modules
|
|||
}
|
||||
else
|
||||
{
|
||||
Log.Error("Could not approve send the movie {0} to couch potato!", r.Title);
|
||||
Log.Error("Could not approve and send the movie {0} to couch potato!", r.Title);
|
||||
}
|
||||
}
|
||||
if (r.Type == RequestType.TvShow)
|
||||
{
|
||||
// TODO
|
||||
var sender = new TvSender(SonarrApi,SickRageApi);
|
||||
var sr = SickRageSettings.GetSettings();
|
||||
var sonarr = SonarrSettings.GetSettings();
|
||||
if (sr.Enabled)
|
||||
{
|
||||
var result = sender.SendToSickRage(sr, r);
|
||||
if (result?.result == "success")
|
||||
{
|
||||
r.Approved = true;
|
||||
updatedRequests.Add(r);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("Could not approve and send the TV {0} to SickRage!", r.Title);
|
||||
Log.Error("SickRage Message: {0}", result?.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (sonarr.Enabled)
|
||||
{
|
||||
var result = sender.SendToSonarr(sonarr, r);
|
||||
if (result != null)
|
||||
{
|
||||
r.Approved = true;
|
||||
updatedRequests.Add(r);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("Could not approve and send the TV {0} to Sonarr!", r.Title);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try
|
||||
|
@ -208,11 +288,10 @@ namespace PlexRequests.UI.Modules
|
|||
|
||||
}
|
||||
|
||||
|
||||
private bool SendMovie(CouchPotatoSettings settings, RequestedModel r, ICouchPotatoApi cp)
|
||||
{
|
||||
Log.Info("Adding movie to CP : {0}", r.Title);
|
||||
var result = cp.AddMovie(r.ImdbId, settings.ApiKey, r.Title, settings.FullUri);
|
||||
var result = cp.AddMovie(r.ImdbId, settings.ApiKey, r.Title, settings.FullUri, settings.ProfileId);
|
||||
Log.Trace("Adding movie to CP result {0}", result);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ using PlexRequests.Helpers;
|
|||
using PlexRequests.Services.Interfaces;
|
||||
using PlexRequests.Services.Notification;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.UI.Helpers;
|
||||
using PlexRequests.UI.Models;
|
||||
|
||||
namespace PlexRequests.UI.Modules
|
||||
|
@ -51,7 +52,7 @@ namespace PlexRequests.UI.Modules
|
|||
public SearchModule(ICacheProvider cache, ISettingsService<CouchPotatoSettings> cpSettings,
|
||||
ISettingsService<PlexRequestSettings> prSettings, IAvailabilityChecker checker,
|
||||
IRequestService request, ISonarrApi sonarrApi, ISettingsService<SonarrSettings> sonarrSettings,
|
||||
ICouchPotatoApi cpApi) : base("search")
|
||||
ISettingsService<SickRageSettings> sickRageService, ICouchPotatoApi cpApi, ISickRageApi srApi) : base("search")
|
||||
{
|
||||
CpService = cpSettings;
|
||||
PrService = prSettings;
|
||||
|
@ -63,6 +64,8 @@ namespace PlexRequests.UI.Modules
|
|||
SonarrApi = sonarrApi;
|
||||
SonarrService = sonarrSettings;
|
||||
CouchPotatoApi = cpApi;
|
||||
SickRageService = sickRageService;
|
||||
SickrageApi = srApi;
|
||||
|
||||
Get["/"] = parameters => RequestLoad();
|
||||
|
||||
|
@ -79,11 +82,13 @@ namespace PlexRequests.UI.Modules
|
|||
private ICouchPotatoApi CouchPotatoApi { get; }
|
||||
private ISonarrApi SonarrApi { get; }
|
||||
private TheTvDbApi TvApi { get; }
|
||||
private ISickRageApi SickrageApi { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private ISettingsService<CouchPotatoSettings> CpService { get; }
|
||||
private ISettingsService<PlexRequestSettings> PrService { get; }
|
||||
private ISettingsService<SonarrSettings> SonarrService { get; }
|
||||
private ISettingsService<SickRageSettings> SickRageService { get; }
|
||||
private IAvailabilityChecker Checker { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private string AuthToken => Cache.GetOrSet(CacheKeys.TvDbToken, TvApi.Authenticate, 50);
|
||||
|
@ -124,7 +129,7 @@ namespace PlexRequests.UI.Modules
|
|||
// http://thetvdb.com/banners/_cache/posters/ID-1.jpg
|
||||
Banner = t.show.image?.medium,
|
||||
FirstAired = t.show.premiered,
|
||||
Id = t.show.id,
|
||||
Id = t.show.externals?.thetvdb ?? 0,
|
||||
ImdbId = t.show.externals?.imdb,
|
||||
Network = t.show.network?.name,
|
||||
NetworkId = t.show.network?.id.ToString(),
|
||||
|
@ -133,7 +138,7 @@ namespace PlexRequests.UI.Modules
|
|||
Runtime = t.show.runtime.ToString(),
|
||||
SeriesId = t.show.id,
|
||||
SeriesName = t.show.name,
|
||||
|
||||
|
||||
Status = t.show.status,
|
||||
});
|
||||
}
|
||||
|
@ -186,12 +191,12 @@ namespace PlexRequests.UI.Modules
|
|||
Log.Trace("Getting movie info from TheMovieDb");
|
||||
Log.Trace(movieInfo.DumpJson);
|
||||
|
||||
//#if !DEBUG
|
||||
//#if !DEBUG
|
||||
if (CheckIfTitleExistsInPlex(movieInfo.Title, movieInfo.ReleaseDate?.Year.ToString()))
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = $"{movieInfo.Title} is already in Plex!" });
|
||||
}
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
var model = new RequestedModel
|
||||
{
|
||||
|
@ -215,7 +220,7 @@ namespace PlexRequests.UI.Modules
|
|||
if (!settings.RequireApproval)
|
||||
{
|
||||
Log.Info("Adding movie to CP (No approval required)");
|
||||
var result = CouchPotatoApi.AddMovie(model.ImdbId, cpSettings.ApiKey, model.Title, cpSettings.FullUri);
|
||||
var result = CouchPotatoApi.AddMovie(model.ImdbId, cpSettings.ApiKey, model.Title, cpSettings.FullUri, cpSettings.ProfileId);
|
||||
Log.Debug("Adding movie to CP result {0}", result);
|
||||
if (result)
|
||||
{
|
||||
|
@ -260,21 +265,21 @@ namespace PlexRequests.UI.Modules
|
|||
|
||||
var tvApi = new TvMazeApi();
|
||||
|
||||
var showInfo = tvApi.ShowLookup(showId);
|
||||
var showInfo = tvApi.ShowLookupByTheTvDbId(showId);
|
||||
|
||||
//#if !DEBUG
|
||||
if (CheckIfTitleExistsInPlex(showInfo.name, showInfo.premiered.Substring(0,4))) // Take only the year Format = 2014-01-01
|
||||
//#if !DEBUG
|
||||
if (CheckIfTitleExistsInPlex(showInfo.name, showInfo.premiered?.Substring(0, 4))) // Take only the year Format = 2014-01-01
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = $"{showInfo.name} is already in Plex!" });
|
||||
}
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
DateTime firstAir;
|
||||
DateTime.TryParse(showInfo.premiered, out firstAir);
|
||||
|
||||
var model = new RequestedModel
|
||||
{
|
||||
ProviderId = showInfo.id,
|
||||
ProviderId = showInfo.externals?.thetvdb ?? 0,
|
||||
Type = RequestType.TvShow,
|
||||
Overview = showInfo.summary.RemoveHtml(),
|
||||
PosterPath = showInfo.image?.medium,
|
||||
|
@ -293,20 +298,39 @@ namespace PlexRequests.UI.Modules
|
|||
if (!settings.RequireApproval)
|
||||
{
|
||||
var sonarrSettings = SonarrService.GetSettings();
|
||||
int qualityProfile;
|
||||
int.TryParse(sonarrSettings.QualityProfile, out qualityProfile);
|
||||
var result = SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile,
|
||||
sonarrSettings.SeasonFolders, sonarrSettings.RootPath, model.LatestTv, sonarrSettings.ApiKey,
|
||||
sonarrSettings.FullUri);
|
||||
if (result != null)
|
||||
var sender = new TvSender(SonarrApi, SickrageApi);
|
||||
if (sonarrSettings.Enabled)
|
||||
{
|
||||
model.Approved = true;
|
||||
Log.Debug("Adding tv to database requests (No approval required)");
|
||||
RequestService.AddRequest(model);
|
||||
var result = sender.SendToSonarr(sonarrSettings, model);
|
||||
if (result != null)
|
||||
{
|
||||
model.Approved = true;
|
||||
Log.Debug("Adding tv to database requests (No approval required & Sonarr)");
|
||||
RequestService.AddRequest(model);
|
||||
|
||||
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something went wrong adding the movie to Sonarr! Please check your settings." });
|
||||
|
||||
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something went wrong adding the movie to CouchPotato! Please check your settings." });
|
||||
|
||||
var srSettings = SickRageService.GetSettings();
|
||||
if (srSettings.Enabled)
|
||||
{
|
||||
var result = sender.SendToSickRage(srSettings, model);
|
||||
if (result?.result == "success")
|
||||
{
|
||||
model.Approved = true;
|
||||
Log.Debug("Adding tv to database requests (No approval required & SickRage)");
|
||||
RequestService.AddRequest(model);
|
||||
|
||||
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = result?.message != null ? "<b>Message From SickRage: </b>" + result.message : "Something went wrong adding the movie to SickRage! Please check your settings." });
|
||||
}
|
||||
|
||||
return Response.AsJson("The request of TV Shows is not correctly set up. Please contact your admin.");
|
||||
|
||||
}
|
||||
|
||||
RequestService.AddRequest(model);
|
||||
|
@ -314,15 +338,30 @@ namespace PlexRequests.UI.Modules
|
|||
|
||||
return Response.AsJson(new { Result = true });
|
||||
}
|
||||
private string GetTvDbAuthToken(TheTvDbApi api)
|
||||
{
|
||||
return Cache.GetOrSet(CacheKeys.TvDbToken, api.Authenticate, 50);
|
||||
}
|
||||
|
||||
private bool CheckIfTitleExistsInPlex(string title, string year)
|
||||
{
|
||||
var result = Checker.IsAvailable(title, year);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Response SendToSickRage(SickRageSettings sickRageSettings, RequestedModel model)
|
||||
{
|
||||
var result = SickrageApi.AddSeries(model.ProviderId, model.LatestTv, sickRageSettings.QualityProfile,
|
||||
sickRageSettings.ApiKey, sickRageSettings.FullUri);
|
||||
|
||||
Log.Trace("SickRage Result: ");
|
||||
Log.Trace(result.DumpJson());
|
||||
|
||||
if (result?.result == "success")
|
||||
{
|
||||
model.Approved = true;
|
||||
Log.Debug("Adding tv to database requests (No approval required & SickRage)");
|
||||
RequestService.AddRequest(model);
|
||||
|
||||
return Response.AsJson(new JsonResponseModel { Result = true });
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something went wrong adding the movie to SickRage! Please check your settings." });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@
|
|||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -101,7 +102,7 @@ namespace PlexRequests.UI.Modules
|
|||
if (signedIn.user?.authentication_token != null)
|
||||
{
|
||||
Log.Debug("Correct credentials, checking if the user is account owner or in the friends list");
|
||||
if (CheckIfUserIsOwner(settings.PlexAuthToken, username))
|
||||
if (CheckIfUserIsOwner(settings.PlexAuthToken, signedIn.user?.username))
|
||||
{
|
||||
Log.Debug("User is the account owner");
|
||||
authenticated = true;
|
||||
|
@ -117,6 +118,11 @@ namespace PlexRequests.UI.Modules
|
|||
{
|
||||
Log.Debug("Need to auth");
|
||||
authenticated = CheckIfUserIsInPlexFriends(username, settings.PlexAuthToken);
|
||||
if (CheckIfUserIsOwner(settings.PlexAuthToken, username))
|
||||
{
|
||||
Log.Debug("User is the account owner");
|
||||
authenticated = true;
|
||||
}
|
||||
Log.Debug("Friends list result = {0}", authenticated);
|
||||
}
|
||||
else if(!settings.UserAuthentication) // No auth, let them pass!
|
||||
|
@ -152,7 +158,11 @@ namespace PlexRequests.UI.Modules
|
|||
private bool CheckIfUserIsOwner(string authToken, string userName)
|
||||
{
|
||||
var userAccount = Api.GetAccount(authToken);
|
||||
return userAccount.Username == userName;
|
||||
if (userAccount == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return userAccount.Username != null && userAccount.Username.Equals(userName, StringComparison.CurrentCultureIgnoreCase);
|
||||
}
|
||||
|
||||
private bool CheckIfUserIsInPlexFriends(string username, string authToken)
|
||||
|
@ -160,7 +170,8 @@ namespace PlexRequests.UI.Modules
|
|||
var users = Api.GetUsers(authToken);
|
||||
Log.Debug("Plex Users: ");
|
||||
Log.Debug(users.DumpJson());
|
||||
return users.User.Any(x => x.Username == username);
|
||||
var allUsers = users.User?.Where(x => !string.IsNullOrEmpty(x.Username));
|
||||
return allUsers != null && allUsers.Any(x => x.Username.Equals(username, StringComparison.CurrentCultureIgnoreCase));
|
||||
}
|
||||
|
||||
private bool IsUserInDeniedList(string username, AuthenticationSettings settings)
|
||||
|
|
|
@ -160,11 +160,13 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Bootstrapper.cs" />
|
||||
<Compile Include="Helpers\TvSender.cs" />
|
||||
<Compile Include="Helpers\ValidationHelper.cs" />
|
||||
<Compile Include="Validators\PushbulletSettingsValidator.cs" />
|
||||
<Compile Include="Validators\EmailNotificationSettingsValidator.cs" />
|
||||
<Compile Include="Validators\CouchPotatoValidator.cs" />
|
||||
<Compile Include="Validators\PlexValidator.cs" />
|
||||
<Compile Include="Validators\SickRageValidator.cs" />
|
||||
<Compile Include="Validators\SonarrValidator.cs" />
|
||||
<Content Include="Content\bootstrap-notify.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
@ -221,6 +223,9 @@
|
|||
<Content Include="Content\jquery-2.2.1.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\jquery.mixitup.js">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\pace.css">
|
||||
<DependentUpon>pace.scss</DependentUpon>
|
||||
</Content>
|
||||
|
@ -320,6 +325,9 @@
|
|||
<Content Include="Views\Admin\PushbulletNotifications.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Views\Admin\Sickrage.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="Web.Debug.config">
|
||||
<DependentUpon>web.config</DependentUpon>
|
||||
</None>
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace PlexRequests.UI
|
|||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var uri = string.Empty;
|
||||
var port = -1;
|
||||
if (args.Length > 0)
|
||||
{
|
||||
Log.Info("We are going to use port {0} that was passed in", args[0]);
|
||||
|
@ -59,7 +59,7 @@ namespace PlexRequests.UI
|
|||
Console.ReadLine();
|
||||
Environment.Exit(1);
|
||||
}
|
||||
uri = $"http://*:{portResult}";
|
||||
port = portResult;
|
||||
}
|
||||
|
||||
Log.Trace("Getting product version");
|
||||
|
@ -68,10 +68,10 @@ namespace PlexRequests.UI
|
|||
var s = new Setup();
|
||||
s.SetupDb();
|
||||
|
||||
if (string.IsNullOrEmpty(uri))
|
||||
uri = GetStartupUri();
|
||||
if (port == -1)
|
||||
port = GetStartupPort();
|
||||
|
||||
var options = new StartOptions(uri)
|
||||
var options = new StartOptions($"http://+:{port}")
|
||||
{
|
||||
ServerFactory = "Microsoft.Owin.Host.HttpListener"
|
||||
};
|
||||
|
@ -80,7 +80,7 @@ namespace PlexRequests.UI
|
|||
|
||||
using (WebApp.Start<Startup>(options))
|
||||
{
|
||||
Console.WriteLine($"Request Plex is running on {uri}");
|
||||
Console.WriteLine($"Request Plex is running on the following port: {port}");
|
||||
Console.WriteLine("Press any key to exit");
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
@ -100,19 +100,19 @@ namespace PlexRequests.UI
|
|||
Console.WriteLine($"Version: {assemblyVer}");
|
||||
}
|
||||
|
||||
private static string GetStartupUri()
|
||||
private static int GetStartupPort()
|
||||
{
|
||||
Log.Trace("Getting startup URI");
|
||||
var uri = "http://*:3579/";
|
||||
Log.Trace("Getting startup Port");
|
||||
var port = 3579;
|
||||
var service = new SettingsServiceV2<PlexRequestSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider()));
|
||||
var settings = service.GetSettings();
|
||||
Log.Trace("Port: {0}", settings.Port);
|
||||
if (settings.Port != 0)
|
||||
{
|
||||
uri = $"http://*:{settings.Port}";
|
||||
port = settings.Port;
|
||||
}
|
||||
|
||||
return uri;
|
||||
return port;
|
||||
}
|
||||
|
||||
private static void ConfigureTargets(string connectionString)
|
||||
|
|
43
PlexRequests.UI/Validators/SickRageValidator.cs
Normal file
43
PlexRequests.UI/Validators/SickRageValidator.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SonarrValidator.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 FluentValidation;
|
||||
|
||||
using PlexRequests.Core.SettingModels;
|
||||
|
||||
namespace PlexRequests.UI.Validators
|
||||
{
|
||||
public class SickRageValidator : AbstractValidator<SickRageSettings>
|
||||
{
|
||||
public SickRageValidator()
|
||||
{
|
||||
RuleFor(request => request.ApiKey).NotEmpty().WithMessage("You must specify a Api Key.");
|
||||
RuleFor(request => request.Ip).NotEmpty().WithMessage("You must specify a IP/Host name.");
|
||||
RuleFor(request => request.Port).NotEmpty().WithMessage("You must specify a Port.");
|
||||
RuleFor(request => request.QualityProfile).NotEmpty().WithMessage("You must specify a Quality Profile.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,6 +51,26 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="SubDir" class="control-label">CouchPotato SubDirectory</label>
|
||||
<div>
|
||||
<input type="text" class="form-control form-control-custom " id="SubDir" name="SubDir" value="@Model.SubDir">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button type="submit" id="getProfiles" class="btn btn-primary-outline">Get Quality Profiles</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="select" class="control-label">Quality Profiles</label>
|
||||
<div id="profiles">
|
||||
<select class="form-control" id="select"></select>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
|
@ -75,9 +95,58 @@
|
|||
<script>
|
||||
$(function() {
|
||||
|
||||
@if (!string.IsNullOrEmpty(Model.ProfileId))
|
||||
{
|
||||
<text>
|
||||
var qualitySelected = '@Model.ProfileId';
|
||||
var $form = $("#mainForm");
|
||||
$.ajax({
|
||||
type: $form.prop("method"),
|
||||
data: $form.serialize(),
|
||||
url: "cpprofiles",
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
response.list.forEach(function(result) {
|
||||
if (result._id == qualitySelected) {
|
||||
|
||||
$("#select").append("<option selected='selected' value='" + result._id + "'>" + result.label + "</option>");
|
||||
} else {
|
||||
$("#select").append("<option value='" + result._id + "'>" + result.label + "</option>");
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function(e) {
|
||||
console.log(e);
|
||||
generateNotify("Something went wrong!", "danger");
|
||||
}
|
||||
});
|
||||
</text>
|
||||
}
|
||||
|
||||
$('#getProfiles').click(function (e) {
|
||||
e.preventDefault();
|
||||
var $form = $("#mainForm");
|
||||
$.ajax({
|
||||
type: $form.prop("method"),
|
||||
data: $form.serialize(),
|
||||
url: "cpprofiles",
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
response.list.forEach(function (result) {
|
||||
$("#select").append("<option value='" + result._id + "'>" + result.label + "</option>");
|
||||
});
|
||||
},
|
||||
error: function (e) {
|
||||
console.log(e);
|
||||
generateNotify("Something went wrong!", "danger");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#testCp').click(function (e) {
|
||||
e.preventDefault();
|
||||
var $form = $("#mainForm");
|
||||
|
||||
$.ajax({
|
||||
type: $form.prop("method"),
|
||||
url: "/test/cp",
|
||||
|
@ -107,9 +176,13 @@
|
|||
return;
|
||||
}
|
||||
var $form = $("#mainForm");
|
||||
var qualityProfile = $("#profiles option:selected").val();
|
||||
var data = $form.serialize();
|
||||
data = data + "&profileId=" + qualityProfile;
|
||||
|
||||
$.ajax({
|
||||
type: $form.prop("method"),
|
||||
data: $form.serialize(),
|
||||
data: data,
|
||||
url: $form.prop("action"),
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
|
@ -125,6 +198,6 @@
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
</script>
|
|
@ -43,6 +43,12 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="SubDir" class="control-label">Plex SubDirectory</label>
|
||||
<div>
|
||||
<input type="text" class="form-control form-control-custom " id="SubDir" name="SubDir" value="@Model.SubDir">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button id="testPlex" type="submit" class="btn btn-primary-outline">Test Connectivity</button>
|
||||
|
|
179
PlexRequests.UI/Views/Admin/Sickrage.cshtml
Normal file
179
PlexRequests.UI/Views/Admin/Sickrage.cshtml
Normal file
|
@ -0,0 +1,179 @@
|
|||
@Html.Partial("_Sidebar")
|
||||
@{
|
||||
int port;
|
||||
if (Model.Port == 0)
|
||||
{
|
||||
port = 8081;
|
||||
}
|
||||
else
|
||||
{
|
||||
port = Model.Port;
|
||||
}
|
||||
}
|
||||
<div class="col-sm-8 col-sm-push-1">
|
||||
<form class="form-horizontal" method="POST" id="mainForm">
|
||||
<fieldset>
|
||||
<legend>SickRage Settings</legend>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
@if (Model.Enabled)
|
||||
{
|
||||
<input type="checkbox" id="Enabled" name="Enabled" checked="checked"><text>Enabled</text>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="checkbox" id="Enabled" name="Enabled"><text>Enabled</text>
|
||||
}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="Ip" class="control-label">SickRage Hostname or IP</label>
|
||||
<div class="">
|
||||
<input type="text" class="form-control form-control-custom " id="Ip" name="Ip" placeholder="localhost" value="@Model.Ip">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="portNumber" class="control-label">Port</label>
|
||||
|
||||
<div class="">
|
||||
<input type="text" class="form-control form-control-custom " id="portNumber" name="Port" placeholder="Port Number" value="@port">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="ApiKey" class="control-label">SickRage API Key</label>
|
||||
<div>
|
||||
<input type="text" class="form-control form-control-custom " id="ApiKey" name="ApiKey" value="@Model.ApiKey">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
@if (Model.Ssl)
|
||||
{
|
||||
<input type="checkbox" id="Ssl" name="Ssl" checked="checked"><text>SSL</text>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="checkbox" id="Ssl" name="Ssl"><text>SSL</text>
|
||||
}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="SubDir" class="control-label">SickRage SubDirectory</label>
|
||||
<div>
|
||||
<input type="text" class="form-control form-control-custom " id="SubDir" name="SubDir" value="@Model.SubDir">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="profiles" class="control-label">Quality Profiles</label>
|
||||
<div id="profiles">
|
||||
<select class="form-control" value="selected">
|
||||
<option id="default" value="default">Use Deafult</option>
|
||||
<option id="sdtv" value="sdtv">SD TV</option>
|
||||
<option id="sddvd" value="sddvd">SD DVD</option>
|
||||
<option id="hdtv" value="hdtv">HD TV</option>
|
||||
<option id="rawhdtv" value="rawhdtv">Raw HD TV</option>
|
||||
<option id="hdwebdl" value="hdwebdl">HD Web DL</option>
|
||||
<option id="fullhdwebdl" value="fullhdwebdl">Full HD Web DL</option>
|
||||
<option id="hdbluray" value="hdbluray">HD Bluray</option>
|
||||
<option id="fullhdbluray" value="fullhdbluray">Full HD Bluray</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button id="testSickRage" type="submit" class="btn btn-primary-outline">Test Connectivity</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button id="save" type="submit" class="btn btn-primary-outline ">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
|
||||
@if (!string.IsNullOrEmpty(Model.QualityProfile))
|
||||
{
|
||||
<text>
|
||||
var qualitySelected = '@Model.QualityProfile';
|
||||
$('#' + qualitySelected).prop("selected", "selected");
|
||||
</text>
|
||||
}
|
||||
|
||||
$('#save').click(function (e) {
|
||||
e.preventDefault();
|
||||
var port = $('#portNumber').val();
|
||||
if (isNaN(port)) {
|
||||
generateNotify("You must specify a Port.", "warning");
|
||||
return;
|
||||
}
|
||||
var qualityProfile = $("#profiles option:selected").val();
|
||||
|
||||
var $form = $("#mainForm");
|
||||
|
||||
var data = $form.serialize();
|
||||
data = data + "&qualityProfile=" + qualityProfile;
|
||||
|
||||
$.ajax({
|
||||
type: $form.prop("method"),
|
||||
data: data,
|
||||
url: $form.prop("action"),
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
if (response.result === true) {
|
||||
generateNotify("Success!", "success");
|
||||
} else {
|
||||
generateNotify(response.message, "warning");
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
console.log(e);
|
||||
generateNotify("Something went wrong!", "danger");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#testSickRage').click(function (e) {
|
||||
e.preventDefault();
|
||||
var $form = $("#mainForm");
|
||||
$.ajax({
|
||||
type: $form.prop("method"),
|
||||
url: "/test/sickrage",
|
||||
data: $form.serialize(),
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
console.log(response);
|
||||
if (response.result === true) {
|
||||
generateNotify(response.message, "success");
|
||||
} else {
|
||||
generateNotify(response.message, "warning");
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
console.log(e);
|
||||
generateNotify("Something went wrong!", "danger");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
})
|
||||
</script>
|
|
@ -14,7 +14,20 @@
|
|||
<form class="form-horizontal" method="POST" id="mainForm">
|
||||
<fieldset>
|
||||
<legend>Sonarr Settings</legend>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
@if (Model.Enabled)
|
||||
{
|
||||
<input type="checkbox" id="Enabled" name="Enabled" checked="checked"><text>Enabled</text>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="checkbox" id="Enabled" name="Enabled"><text>Enabled</text>
|
||||
}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="Ip" class="control-label">Sonarr Hostname or IP</label>
|
||||
<div class="">
|
||||
|
@ -51,6 +64,12 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="SubDir" class="control-label">Sonarr SubDirectory</label>
|
||||
<div>
|
||||
<input type="text" class="form-control form-control-custom " id="SubDir" name="SubDir" value="@Model.SubDir">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button type="submit" id="getProfiles" class="btn btn-primary-outline">Get Quality Profiles</button>
|
||||
|
@ -121,7 +140,7 @@
|
|||
success: function(response) {
|
||||
response.forEach(function(result) {
|
||||
if (result.id == qualitySelected) {
|
||||
|
||||
|
||||
$("#select").append("<option selected='selected' value='" + result.id + "'>" + result.name + "</option>");
|
||||
} else {
|
||||
$("#select").append("<option value='" + result.id + "'>" + result.name + "</option>");
|
||||
|
@ -133,11 +152,6 @@
|
|||
generateNotify("Something went wrong!", "danger");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</text>
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,14 @@
|
|||
{
|
||||
<a class="list-group-item" href="/admin/sonarr">Sonarr</a>
|
||||
}
|
||||
@*<a class="list-group-item" href="/admin/sickbeard">Sickbeard Settings</a>*@
|
||||
@if (Context.Request.Path == "/admin/sickrage")
|
||||
{
|
||||
<a class="list-group-item active" href="/admin/sickrage">SickRage</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a class="list-group-item" href="/admin/sickrage">SickRage</a>
|
||||
}
|
||||
|
||||
@if (Context.Request.Path == "/admin/emailnotification")
|
||||
{
|
||||
|
|
|
@ -22,13 +22,38 @@
|
|||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div class="tab-content contentList">
|
||||
<div class="btn-group col-sm-push-10">
|
||||
<a href="#" class="btn btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
Filter
|
||||
<i class="fa fa-filter"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" class="filter" data-filter="all">All</a></li>
|
||||
<li><a href="#" class="filter" data-filter=".approved-true">Approved</a></li>
|
||||
<li><a href="#" class="filter" data-filter=".approved-false">Not Approved</a></li>
|
||||
<li><a href="#" class="filter" data-filter=".available-true">Available</a></li>
|
||||
<li><a href="#" class="filter" data-filter=".available-false">Not Available</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group col-sm-push-10">
|
||||
<a href="#" class="btn btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
Order
|
||||
<i class="fa fa-sort"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" class="sort" data-sort="default">Default</a></li>
|
||||
<li><a href="#" class="sort" data-sort="requestorder:asc">Requested Date</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@if (Model.SearchForMovies)
|
||||
{
|
||||
<!-- Movie tab -->
|
||||
|
||||
<!-- Movie tab -->
|
||||
<div role="tabpanel" class="tab-pane active" id="MoviesTab">
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<!-- Movie content -->
|
||||
<div id="movieList">
|
||||
</div>
|
||||
|
@ -37,10 +62,11 @@
|
|||
|
||||
@if (Model.SearchForTvShows)
|
||||
{
|
||||
<!-- TV tab -->
|
||||
<!-- TV tab -->
|
||||
<div role="tabpanel" class="tab-pane" id="TvShowTab">
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<!-- TV content -->
|
||||
<div id="tvList">
|
||||
</div>
|
||||
|
@ -52,7 +78,7 @@
|
|||
|
||||
|
||||
<script id="search-template" type="text/x-handlebars-template">
|
||||
<div id="{{requestId}}Template">
|
||||
<div id="{{requestId}}Template" class="mix available-{{available}} approved-{{approved}}">
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
{{#if_eq type "movie"}}
|
||||
|
@ -95,7 +121,7 @@
|
|||
</div>
|
||||
<div>Requested By: {{requestedBy}}</div>
|
||||
<div>Requested Date: {{requestedDate}}</div>
|
||||
<div id="issueArea">
|
||||
<div id="issueArea{{requestId}}">
|
||||
{{#if otherMessage}}
|
||||
<div>Message: {{otherMessage}}</div>
|
||||
{{else}}
|
||||
|
@ -118,7 +144,7 @@
|
|||
{{/if_eq}}
|
||||
<form method="POST" action="/requests/delete" id="delete{{requestId}}">
|
||||
<input name="Id" type="text" value="{{requestId}}" hidden="hidden" />
|
||||
<button id="{{requestId}}" style="text-align: right" class="btn btn-sm btn-danger-outline delete" type="submit"><i class="fa fa-plus"></i> Remove</button>
|
||||
<button id="{{requestId}}" style="text-align: right" class="btn btn-sm btn-danger-outline delete" type="submit"><i class="fa fa-minus"></i> Remove</button>
|
||||
</form>
|
||||
|
||||
<form method="POST" action="/requests/clearissues" id="clear{{requestId}}">
|
||||
|
@ -129,9 +155,9 @@
|
|||
<form method="POST" action="/requests/changeavailability" id="change{{requestId}}">
|
||||
<input name="Id" type="text" value="{{requestId}}" hidden="hidden" />
|
||||
{{#if_eq available true}}
|
||||
<button id="{{requestId}}" custom-availibility="{{requestId}}" style="text-align: right" value="false" class="btn btn-sm btn-info-outline change" type="submit">Mark Unavailable</button>
|
||||
<button id="{{requestId}}" custom-availibility="{{requestId}}" style="text-align: right" value="false" class="btn btn-sm btn-info-outline change" type="submit"><i class="fa fa-minus"></i> Mark Unavailable</button>
|
||||
{{else}}
|
||||
<button id="{{requestId}}" custom-availibility="{{requestId}}" style="text-align: right" value="true" class="btn btn-sm btn-success-outline change" type="submit">Mark Available</button>
|
||||
<button id="{{requestId}}" custom-availibility="{{requestId}}" style="text-align: right" value="true" class="btn btn-sm btn-success-outline change" type="submit"><i class="fa fa-plus"></i> Mark Available</button>
|
||||
{{/if_eq}}
|
||||
</form>
|
||||
|
||||
|
@ -150,16 +176,15 @@
|
|||
<li><a id="{{requestId}}" issue-select="2" class="dropdownIssue" href="#">Wrong Content</a></li>
|
||||
<li><a id="{{requestId}}" issue-select="3" class="dropdownIssue" href="#">Playback Issues</a></li>
|
||||
<li><a id="{{requestId}}" issue-select="4" class="dropdownIssue" data-identifier="{{requestId}}" href="#" data-toggle="modal" data-target="#myModal">Other</a></li>
|
||||
{{#if_eq admin true}}
|
||||
<li><a id="{{requestId}}" issue-select="4" class="note" data-identifier="{{requestId}}" href="#" data-toggle="modal" data-target="#noteModal">Add Note</a></li>
|
||||
|
||||
{{#if_eq admin true}}
|
||||
<li><a id="{{requestId}}" issue-select="4" class="note" data-identifier="{{requestId}}" href="#" data-toggle="modal" data-target="#noteModal">Add Note</a></li>
|
||||
{{/if_eq}}
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@* // TODO add Issues to the view *@
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
|
@ -208,3 +233,5 @@
|
|||
</div>
|
||||
|
||||
<script src="/Content/requests.js" type="text/javascript"></script>
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<script src="/Content/bootstrap-notify.min.js"></script>
|
||||
<script src="/Content/site.js"></script>
|
||||
<script src="/Content/pace.min.js"></script>
|
||||
<script src="/Content/jquery.mixitup.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
10
README.md
10
README.md
|
@ -21,7 +21,7 @@ I wanted to write a similar application in .Net!
|
|||
|
||||
#Preview
|
||||
|
||||

|
||||

|
||||
|
||||
#Installation
|
||||
Download the latest [Release](https://github.com/tidusjar/PlexRequests.Net/releases).
|
||||
|
@ -33,6 +33,8 @@ Just run `PlexRequests.exe`! (Mono compatible `mono PlexRequests.exe`)
|
|||
To configure PlexRequests you need to register an admin user by clicking on Admin (top right) and press the Register link.
|
||||
You will then have a admin menu option once registered where you can setup Sonarr, Couchpotato and any other settings.
|
||||
|
||||
Looking for a Docker Image? Well [rogueosb](https://github.com/rogueosb/) has created a docker image for us, You can find it [here](https://github.com/rogueosb/docker-plexrequestsnet) :smile:
|
||||
|
||||
# Contributors
|
||||
|
||||
We are looking for any contributions to the project! Just pick up a task, if you have any questions ask and i'll get straight on it!
|
||||
|
@ -40,7 +42,11 @@ We are looking for any contributions to the project! Just pick up a task, if you
|
|||
Please feed free to submit a pull request!
|
||||
|
||||
# Donation
|
||||
If you feel like donating you can [here!](paypal.me/PlexRequestsNet)
|
||||
If you feel like donating you can [here!](https://paypal.me/PlexRequestsNet)
|
||||
|
||||
###### A massive thanks to everyone below!
|
||||
|
||||
[heartisall](https://github.com/heartisall)
|
||||
|
||||
|
||||
# Sponsors
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
version: 1.3.{build}
|
||||
version: 1.4.{build}
|
||||
configuration: Release
|
||||
assembly_info:
|
||||
patch: true
|
||||
file: '**\AssemblyInfo.*'
|
||||
assembly_version: '1.3.0'
|
||||
assembly_version: '1.4.1'
|
||||
assembly_file_version: '{version}'
|
||||
assembly_informational_version: '1.3.0'
|
||||
assembly_informational_version: '1.4.1'
|
||||
before_build:
|
||||
- cmd: appveyor-retry nuget restore
|
||||
build:
|
||||
|
@ -18,7 +18,7 @@ after_build:
|
|||
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
release: PlexRequests $(appveyor_build_version)
|
||||
release: PlexRequests v$(appveyor_build_version)
|
||||
auth_token:
|
||||
secure: jDpp1/WUQl3uN41fNI3VeZoRZbDiDfs3GPQ1v+C5ZNE3cWdnUvuJfCCfUbYUV1Rp
|
||||
draft: true
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue