From 59d61b3a0fdfb995c9539451c91f8a0ecee1e4a1 Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Tue, 1 Mar 2016 20:18:02 +0000 Subject: [PATCH 1/5] Plex friends api --- RequestPlex.Api/ApiRequest.cs | 4 +- RequestPlex.Api/Models/PlexFriends.cs | 66 +++++++++++ RequestPlex.Api/PlexApi.cs | 16 ++- RequestPlex.Api/RequestPlex.Api.csproj | 1 + RequestPlex.UI/Modules/AdminModule.cs | 123 ++++++++++++--------- RequestPlex.UI/Views/Admin/Settings.cshtml | 2 +- 6 files changed, 153 insertions(+), 59 deletions(-) create mode 100644 RequestPlex.Api/Models/PlexFriends.cs diff --git a/RequestPlex.Api/ApiRequest.cs b/RequestPlex.Api/ApiRequest.cs index 74837f64c..974e4e9c5 100644 --- a/RequestPlex.Api/ApiRequest.cs +++ b/RequestPlex.Api/ApiRequest.cs @@ -27,9 +27,7 @@ namespace RequestPlex.Api var response = client.Execute(request); if (response.ErrorException != null) - { - - + { var message = "Error retrieving response. Check inner details for more info."; throw new ApplicationException(message, response.ErrorException); } diff --git a/RequestPlex.Api/Models/PlexFriends.cs b/RequestPlex.Api/Models/PlexFriends.cs new file mode 100644 index 000000000..77bafa637 --- /dev/null +++ b/RequestPlex.Api/Models/PlexFriends.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; +using RestSharp.Deserializers; + +namespace RequestPlex.Api.Models +{ + [XmlRoot(ElementName = "Server")] + public class Server + { + [XmlAttribute(AttributeName = "id")] + public string Id { get; set; } + [XmlAttribute(AttributeName = "serverId")] + public string ServerId { get; set; } + [XmlAttribute(AttributeName = "machineIdentifier")] + public string MachineIdentifier { get; set; } + [XmlAttribute(AttributeName = "name")] + public string Name { get; set; } + [XmlAttribute(AttributeName = "lastSeenAt")] + public string LastSeenAt { get; set; } + [XmlAttribute(AttributeName = "numLibraries")] + public string NumLibraries { get; set; } + [XmlAttribute(AttributeName = "owned")] + public string Owned { get; set; } + } + + [XmlRoot(ElementName = "User")] + public class UserFriends + { + [XmlElement(ElementName = "Server")] + public Server Server { get; set; } + [XmlAttribute(AttributeName = "id")] + public string Id { get; set; } + [XmlAttribute(AttributeName = "title")] + public string Title { get; set; } + [XmlAttribute(AttributeName = "username")] + public string Username { get; set; } + [XmlAttribute(AttributeName = "email")] + public string Email { get; set; } + [XmlAttribute(AttributeName = "recommendationsPlaylistId")] + public string RecommendationsPlaylistId { get; set; } + [XmlAttribute(AttributeName = "thumb")] + public string Thumb { get; set; } + } + + [XmlRoot(ElementName = "MediaContainer")] + public class PlexFriends + { + [XmlElement(ElementName = "User")] + public List User { get; set; } + [XmlAttribute(AttributeName = "friendlyName")] + public string FriendlyName { get; set; } + [XmlAttribute(AttributeName = "identifier")] + public string Identifier { get; set; } + [XmlAttribute(AttributeName = "machineIdentifier")] + public string MachineIdentifier { get; set; } + [XmlAttribute(AttributeName = "totalSize")] + public string TotalSize { get; set; } + [XmlAttribute(AttributeName = "size")] + public string Size { get; set; } + } + +} diff --git a/RequestPlex.Api/PlexApi.cs b/RequestPlex.Api/PlexApi.cs index 79690949e..efa7c2727 100644 --- a/RequestPlex.Api/PlexApi.cs +++ b/RequestPlex.Api/PlexApi.cs @@ -1,6 +1,10 @@ using System; +using System.IO; +using System.Runtime.Remoting.Messaging; using RequestPlex.Api.Models; using RestSharp; +using RestSharp.Deserializers; +using RestSharp.Serializers; namespace RequestPlex.Api { @@ -25,26 +29,30 @@ namespace RequestPlex.Api request.AddHeader("X-Plex-Product", "Request Plex"); request.AddHeader("X-Plex-Version", "0.0.1"); request.AddHeader("Content-Type", "application/json"); - + request.AddJsonBody(userModel); var api = new ApiRequest(); return api.Execute(request, new Uri("https://plex.tv/users/sign_in.json")); } - public void GetUsers(string authToken) + public PlexFriends GetUsers(string authToken) { var request = new RestRequest { - Method = Method.POST, + Method = Method.GET, }; request.AddHeader("X-Plex-Client-Identifier", "Test213"); request.AddHeader("X-Plex-Product", "Request Plex"); request.AddHeader("X-Plex-Version", "0.0.1"); request.AddHeader("X-Plex-Token", authToken); - request.AddHeader("Content-Type", "application/json"); + request.AddHeader("Content-Type", "application/xml"); + + var api = new ApiRequest(); + var users = api.Execute(request, new Uri("https://plex.tv/pms/friends/all")); + return users; } } } diff --git a/RequestPlex.Api/RequestPlex.Api.csproj b/RequestPlex.Api/RequestPlex.Api.csproj index c04ba5870..4afe2f00a 100644 --- a/RequestPlex.Api/RequestPlex.Api.csproj +++ b/RequestPlex.Api/RequestPlex.Api.csproj @@ -62,6 +62,7 @@ + diff --git a/RequestPlex.UI/Modules/AdminModule.cs b/RequestPlex.UI/Modules/AdminModule.cs index 1aa0a6392..b94b30a61 100644 --- a/RequestPlex.UI/Modules/AdminModule.cs +++ b/RequestPlex.UI/Modules/AdminModule.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Dynamic; using System.Linq; +using System.Web.UI; using Nancy; using Nancy.Extensions; using Nancy.ModelBinding; @@ -23,73 +24,93 @@ namespace RequestPlex.UI.Modules #if !DEBUG this.RequiresAuthentication(); #endif - Get["admin/"] = _ => - { - dynamic model = new ExpandoObject(); - model.Errored = Request.Query.error.HasValue; - model.Port = null; - var s = new SettingsService(); - var settings = s.GetSettings(); - if (settings != null) - { - model.Port = settings.Port; - model.PlexAuthToken = settings.PlexAuthToken; - } + Get["admin/"] = _ => Admin(); + + Post["admin/"] = _ => SaveAdmin(); + + Post["admin/requestauth"] = _ => RequestAuthToken(); + + Get["admin/getusers"] = _ => GetUsers(); + + Get["admin/couchpotato"] = _ => CouchPotato(); + } - return View["/Admin/Settings", model]; - }; - Post["admin/"] = _ => + private Response Admin() + { + dynamic model = new ExpandoObject(); + model.Errored = Request.Query.error.HasValue; + model.Port = null; + var s = new SettingsService(); + var settings = s.GetSettings(); + if (settings != null) { - var model = this.Bind(); + model.Port = settings.Port; + model.PlexAuthToken = settings.PlexAuthToken; + } + + return View["/Admin/Settings", model]; + } - var s = new SettingsService(); - s.SaveSettings(model); + private Response SaveAdmin() + { + var model = this.Bind(); + + var s = new SettingsService(); + s.SaveSettings(model); - return Context.GetRedirect("~/admin"); - }; + return Context.GetRedirect("~/admin"); + } - Post["admin/requestauth"] = _ => + private Response RequestAuthToken() + { + var user = this.Bind(); + + if (string.IsNullOrEmpty(user.username) || string.IsNullOrEmpty(user.password)) { - var user = this.Bind(); + return Context.GetRedirect("~/admin?error=true"); + } - if (string.IsNullOrEmpty(user.username) || string.IsNullOrEmpty(user.password)) - { - return Context.GetRedirect("~/admin?error=true"); - } - - var plex = new PlexApi(); - var model = plex.GetToken(user.username, user.password); - var s = new SettingsService(); - var oldSettings = s.GetSettings(); - if (oldSettings != null) - { - oldSettings.PlexAuthToken = model.user.authentication_token; - s.SaveSettings(oldSettings); - } - else + var plex = new PlexApi(); + var model = plex.GetToken(user.username, user.password); + var s = new SettingsService(); + var oldSettings = s.GetSettings(); + if (oldSettings != null) + { + oldSettings.PlexAuthToken = model.user.authentication_token; + s.SaveSettings(oldSettings); + } + else + { + var newModel = new SettingsModel { - var newModel = new SettingsModel - { - PlexAuthToken = model.user.authentication_token - }; - s.SaveSettings(newModel); - } + PlexAuthToken = model.user.authentication_token + }; + s.SaveSettings(newModel); + } + + return Context.GetRedirect("~/admin"); + } + private Response GetUsers() + { + var s = new SettingsService(); + var token = s.GetSettings().PlexAuthToken; + var api = new PlexApi(); + var users = api.GetUsers(token); + var usernames = users.User.Select(x => x.Username); + return Response.AsJson(usernames); //TODO usernames are not populated. + } - return Context.GetRedirect("~/admin"); - }; + private Response CouchPotato() + { + dynamic model = new ExpandoObject(); - Get["admin/getusers"] = _ => - { - var api = new PlexApi(); - - return View["/Admin/Settings"]; - }; + return View["/Admin/CouchPotato", model]; } } } \ No newline at end of file diff --git a/RequestPlex.UI/Views/Admin/Settings.cshtml b/RequestPlex.UI/Views/Admin/Settings.cshtml index df14a4ed9..0c38cf5f8 100644 --- a/RequestPlex.UI/Views/Admin/Settings.cshtml +++ b/RequestPlex.UI/Views/Admin/Settings.cshtml @@ -60,7 +60,7 @@ Current users that are allowed to authenticate: -
From 8c9bd4105792648cae6992c08e32d1978de3e01b Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Tue, 1 Mar 2016 21:44:51 +0000 Subject: [PATCH 2/5] upgraded Json.Net and Nancy packages --- RequestPlex.Api/RequestPlex.Api.csproj | 5 +++-- RequestPlex.Api/app.config | 11 +++++++++++ RequestPlex.Api/packages.config | 2 +- RequestPlex.Core/RequestPlex.Core.csproj | 1 + RequestPlex.Core/app.config | 11 +++++++++++ RequestPlex.UI/RequestPlex.UI.csproj | 7 ++++--- RequestPlex.UI/app.config | 8 ++++++++ RequestPlex.UI/packages.config | 2 +- 8 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 RequestPlex.Api/app.config create mode 100644 RequestPlex.Core/app.config diff --git a/RequestPlex.Api/RequestPlex.Api.csproj b/RequestPlex.Api/RequestPlex.Api.csproj index 1b81b40ee..bc26a3015 100644 --- a/RequestPlex.Api/RequestPlex.Api.csproj +++ b/RequestPlex.Api/RequestPlex.Api.csproj @@ -38,8 +38,8 @@ ..\packages\Nancy.1.4.3\lib\net40\Nancy.dll True - - ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll True @@ -70,6 +70,7 @@ + diff --git a/RequestPlex.Api/app.config b/RequestPlex.Api/app.config new file mode 100644 index 000000000..ac2586ac9 --- /dev/null +++ b/RequestPlex.Api/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/RequestPlex.Api/packages.config b/RequestPlex.Api/packages.config index 50b670221..62b36e32c 100644 --- a/RequestPlex.Api/packages.config +++ b/RequestPlex.Api/packages.config @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/RequestPlex.Core/RequestPlex.Core.csproj b/RequestPlex.Core/RequestPlex.Core.csproj index 62122a746..958a2fed9 100644 --- a/RequestPlex.Core/RequestPlex.Core.csproj +++ b/RequestPlex.Core/RequestPlex.Core.csproj @@ -74,6 +74,7 @@ + diff --git a/RequestPlex.Core/app.config b/RequestPlex.Core/app.config new file mode 100644 index 000000000..ac2586ac9 --- /dev/null +++ b/RequestPlex.Core/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/RequestPlex.UI/RequestPlex.UI.csproj b/RequestPlex.UI/RequestPlex.UI.csproj index 48a5d21a8..f2920dd7c 100644 --- a/RequestPlex.UI/RequestPlex.UI.csproj +++ b/RequestPlex.UI/RequestPlex.UI.csproj @@ -38,7 +38,7 @@ DEBUG;TRACE prompt 4 - false + true AnyCPU @@ -70,8 +70,9 @@ False ..\Assemblies\Mono.Data.Sqlite.dll - - ..\packages\Nancy.1.4.1\lib\net40\Nancy.dll + + ..\packages\Nancy.1.4.3\lib\net40\Nancy.dll + True ..\packages\Nancy.Authentication.Basic.1.4.1\lib\net40\Nancy.Authentication.Basic.dll diff --git a/RequestPlex.UI/app.config b/RequestPlex.UI/app.config index 825a85f28..ba2fe0922 100644 --- a/RequestPlex.UI/app.config +++ b/RequestPlex.UI/app.config @@ -28,4 +28,12 @@ + + + + + + + + \ No newline at end of file diff --git a/RequestPlex.UI/packages.config b/RequestPlex.UI/packages.config index 7b054d963..149d4de12 100644 --- a/RequestPlex.UI/packages.config +++ b/RequestPlex.UI/packages.config @@ -4,7 +4,7 @@ - + From a00d5b69f27eb85993e60af399f59b3a9ea2f222 Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Tue, 1 Mar 2016 22:50:41 +0000 Subject: [PATCH 3/5] More work on the settings --- RequestPlex.Core/RequestPlex.Core.csproj | 3 + .../SettingModels/CouchPotatoSettings.cs | 10 ++ .../SettingModels/RequestPlexSettings.cs | 4 + .../SettingModels/SickRageSettings.cs | 10 ++ .../SettingModels/SonarrSettings.cs | 10 ++ RequestPlex.Helpers/AssemblyHelper.cs | 15 +++ .../RequestPlex.Helpers.csproj | 1 + RequestPlex.Store/RequestedModel.cs | 4 + RequestPlex.Store/SqlTables.sql | 7 +- RequestPlex.UI/Modules/AdminModule.cs | 14 +-- RequestPlex.UI/Program.cs | 10 +- RequestPlex.UI/Views/Admin/Settings.cshtml | 98 ++++++++++++++----- RequestPlex.UI/Views/Requests/Index.cshtml | 4 +- RequestPlex.UI/Views/Search/Index.cshtml | 1 + 14 files changed, 152 insertions(+), 39 deletions(-) create mode 100644 RequestPlex.Core/SettingModels/CouchPotatoSettings.cs create mode 100644 RequestPlex.Core/SettingModels/SickRageSettings.cs create mode 100644 RequestPlex.Core/SettingModels/SonarrSettings.cs create mode 100644 RequestPlex.Helpers/AssemblyHelper.cs diff --git a/RequestPlex.Core/RequestPlex.Core.csproj b/RequestPlex.Core/RequestPlex.Core.csproj index 958a2fed9..b105c28e8 100644 --- a/RequestPlex.Core/RequestPlex.Core.csproj +++ b/RequestPlex.Core/RequestPlex.Core.csproj @@ -64,6 +64,9 @@ + + + diff --git a/RequestPlex.Core/SettingModels/CouchPotatoSettings.cs b/RequestPlex.Core/SettingModels/CouchPotatoSettings.cs new file mode 100644 index 000000000..ffa6c5896 --- /dev/null +++ b/RequestPlex.Core/SettingModels/CouchPotatoSettings.cs @@ -0,0 +1,10 @@ +namespace RequestPlex.Core.SettingModels +{ + public class CouchPotatoSettings : Settings + { + public string Ip { get; set; } + public int Port { get; set; } + public string ApiKey { get; set; } + public bool Enabled { get; set; } + } +} \ No newline at end of file diff --git a/RequestPlex.Core/SettingModels/RequestPlexSettings.cs b/RequestPlex.Core/SettingModels/RequestPlexSettings.cs index c28c933f0..0e603b91a 100644 --- a/RequestPlex.Core/SettingModels/RequestPlexSettings.cs +++ b/RequestPlex.Core/SettingModels/RequestPlexSettings.cs @@ -31,5 +31,9 @@ namespace RequestPlex.Core.SettingModels public int Port { get; set; } public bool UserAuthentication { get; set; } public string PlexAuthToken { get; set; } + public bool SearchForMovies { get; set; } + public bool SearchForTvShows { get; set; } + public bool RequireApprovial { get; set; } + public int WeeklyRequestLimit { get; set; } } } diff --git a/RequestPlex.Core/SettingModels/SickRageSettings.cs b/RequestPlex.Core/SettingModels/SickRageSettings.cs new file mode 100644 index 000000000..be1dd6d85 --- /dev/null +++ b/RequestPlex.Core/SettingModels/SickRageSettings.cs @@ -0,0 +1,10 @@ +namespace RequestPlex.Core.SettingModels +{ + public class SickRageSettings : Settings + { + public string Ip { get; set; } + public int Port { get; set; } + public string ApiKey { get; set; } + public bool Enabled { get; set; } + } +} \ No newline at end of file diff --git a/RequestPlex.Core/SettingModels/SonarrSettings.cs b/RequestPlex.Core/SettingModels/SonarrSettings.cs new file mode 100644 index 000000000..fb6f8ecfa --- /dev/null +++ b/RequestPlex.Core/SettingModels/SonarrSettings.cs @@ -0,0 +1,10 @@ +namespace RequestPlex.Core.SettingModels +{ + public class SonarrSettings : Settings + { + public string Ip { get; set; } + public int Port { get; set; } + public string ApiKey { get; set; } + public bool Enabled { get; set; } + } +} \ No newline at end of file diff --git a/RequestPlex.Helpers/AssemblyHelper.cs b/RequestPlex.Helpers/AssemblyHelper.cs new file mode 100644 index 000000000..fe6a281b8 --- /dev/null +++ b/RequestPlex.Helpers/AssemblyHelper.cs @@ -0,0 +1,15 @@ +using System.Diagnostics; +using System.Reflection; + +namespace RequestPlex.Helpers +{ + public class AssemblyHelper + { + public static string GetAssemblyVersion() + { + var assembly = Assembly.GetExecutingAssembly(); + var fvi = FileVersionInfo.GetVersionInfo(assembly.Location); + return fvi.FileVersion; + } + } +} \ No newline at end of file diff --git a/RequestPlex.Helpers/RequestPlex.Helpers.csproj b/RequestPlex.Helpers/RequestPlex.Helpers.csproj index 4fd02c8e9..271cce512 100644 --- a/RequestPlex.Helpers/RequestPlex.Helpers.csproj +++ b/RequestPlex.Helpers/RequestPlex.Helpers.csproj @@ -45,6 +45,7 @@ + diff --git a/RequestPlex.Store/RequestedModel.cs b/RequestPlex.Store/RequestedModel.cs index d62cd9b7c..afadebcd0 100644 --- a/RequestPlex.Store/RequestedModel.cs +++ b/RequestPlex.Store/RequestedModel.cs @@ -16,6 +16,10 @@ namespace RequestPlex.Store public DateTime ReleaseDate { get; set; } public RequestType Type { get; set; } public string Status { get; set; } + public string RequestedStatus { get; set; } + public string RequestedBy { get; set; } + public DateTime RequestedDate { get; set; } + } public enum RequestType diff --git a/RequestPlex.Store/SqlTables.sql b/RequestPlex.Store/SqlTables.sql index 820a090f7..97e1e053e 100644 --- a/RequestPlex.Store/SqlTables.sql +++ b/RequestPlex.Store/SqlTables.sql @@ -26,7 +26,12 @@ CREATE TABLE IF NOT EXISTS Requested Title varchar(50) NOT NULL, PosterPath varchar(50) NOT NULL, ReleaseDate varchar(50) NOT NULL, - Status varchar(50) NOT NULL + Status varchar(50) NOT NULL, + RequestStatus varchar(50) NOT NULL, + RequestedBy varchar(50) NOT NULL, + RequestedDate varchar(50) NOT NULL, + Available varchar(50) NOT NULL + ); CREATE TABLE IF NOT EXISTS GlobalSettings diff --git a/RequestPlex.UI/Modules/AdminModule.cs b/RequestPlex.UI/Modules/AdminModule.cs index ef549580f..7e7709d54 100644 --- a/RequestPlex.UI/Modules/AdminModule.cs +++ b/RequestPlex.UI/Modules/AdminModule.cs @@ -30,6 +30,7 @@ using System.Web.UI; using Nancy; using Nancy.Extensions; using Nancy.ModelBinding; +using Nancy.Responses.Negotiation; using Nancy.Security; using RequestPlex.Api; @@ -60,19 +61,12 @@ namespace RequestPlex.UI.Modules } - private Response Admin() + private Negotiator Admin() { dynamic model = new ExpandoObject(); - model.Errored = Request.Query.error.HasValue; - model.Port = null; - var settings = Service.GetSettings(); - if (settings != null) - { - model.Port = settings.Port; - model.PlexAuthToken = settings.PlexAuthToken; - } + model = settings; return View["/Admin/Settings", model]; } @@ -112,7 +106,7 @@ namespace RequestPlex.UI.Modules Service.SaveSettings(newModel); } - return Context.GetRedirect("~/admin"); + return Response.AsJson(new {Result = true, AuthToken = model.user.authentication_token}); } diff --git a/RequestPlex.UI/Program.cs b/RequestPlex.UI/Program.cs index 1d863eee8..5f24c7767 100644 --- a/RequestPlex.UI/Program.cs +++ b/RequestPlex.UI/Program.cs @@ -1,11 +1,9 @@ using System; - +using System.Diagnostics; using Microsoft.Owin.Hosting; using Mono.Data.Sqlite; -using Nancy.Hosting.Self; - using RequestPlex.Core; using RequestPlex.Core.SettingModels; using RequestPlex.Helpers; @@ -18,6 +16,8 @@ namespace RequestPlex.UI { static void Main(string[] args) { + var assemblyVer = AssemblyHelper.GetAssemblyVersion(); + Console.WriteLine($"Version: {assemblyVer}"); var uri = "http://localhost:3579/"; var s = new Setup(); s.SetupDb(); @@ -32,8 +32,8 @@ namespace RequestPlex.UI using (WebApp.Start(uri)) { - Console.WriteLine("Running on {0}", uri); - Console.WriteLine("Press enter to exit"); + Console.WriteLine($"Request Plex is running on {uri}"); + Console.WriteLine("Press any key to exit"); Console.ReadLine(); } } diff --git a/RequestPlex.UI/Views/Admin/Settings.cshtml b/RequestPlex.UI/Views/Admin/Settings.cshtml index 0661fe84e..d128cc31c 100644 --- a/RequestPlex.UI/Views/Admin/Settings.cshtml +++ b/RequestPlex.UI/Views/Admin/Settings.cshtml @@ -19,6 +19,7 @@ { authToken = Model.PlexAuthToken; } + }
@@ -26,10 +27,52 @@ Request Plex Settings
+
+ You will have to restart after changing the port. +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
@@ -39,7 +82,7 @@
- +
@@ -55,15 +98,30 @@
-
- +
+
- Current users that are allowed to authenticate: - - +
+
+ Current users that are allowed to authenticate: +
+
+ +
+
+
+
@@ -74,7 +132,6 @@

- Please note, you will have to restart after changing these settings.
@@ -87,19 +144,11 @@
-@if (Model.Errored) -{ -
- - Please enter in a correct port number -
-} -