diff --git a/src/Jackett/ApiKey.cs b/src/Jackett/ApiKey.cs index 9cd8419d9..86848899a 100644 --- a/src/Jackett/ApiKey.cs +++ b/src/Jackett/ApiKey.cs @@ -9,6 +9,9 @@ namespace Jackett { public class ApiKey { + + public static string CurrentKey; + const string chars = "abcdefghijklmnopqrstuvwxyz0123456789"; public static string Generate() diff --git a/src/Jackett/IndexerManager.cs b/src/Jackett/IndexerManager.cs index 1abea0092..520210922 100644 --- a/src/Jackett/IndexerManager.cs +++ b/src/Jackett/IndexerManager.cs @@ -11,15 +11,18 @@ namespace Jackett public class IndexerManager { - static string AppConfigDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Jackett"); - static string IndexerConfigDirectory = Path.Combine(AppConfigDirectory, "Indexers"); + static string IndexerConfigDirectory = Path.Combine(Program.AppConfigDirectory, "Indexers"); public Dictionary Indexers { get; private set; } public IndexerManager() { Indexers = new Dictionary(); + LoadMissingIndexers(); + } + void LoadMissingIndexers() + { var implementedIndexerTypes = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => typeof(IndexerInterface).IsAssignableFrom(p) && !p.IsInterface) @@ -31,10 +34,13 @@ namespace Jackett } } - IndexerInterface LoadIndexer(Type indexerType) + void LoadIndexer(Type indexerType) { var name = indexerType.Name.Trim().ToLower(); + if (Indexers.ContainsKey(name)) + return; + IndexerInterface newIndexer = (IndexerInterface)Activator.CreateInstance(indexerType); newIndexer.OnSaveConfigurationRequested += newIndexer_OnSaveConfigurationRequested; @@ -46,7 +52,6 @@ namespace Jackett } Indexers.Add(name, newIndexer); - return newIndexer; } string GetIndexerConfigFilePath(IndexerInterface indexer) @@ -71,5 +76,14 @@ namespace Jackett return indexer; } + public void DeleteIndexer(string name) + { + var indexer = GetIndexer(name); + var configPath = GetIndexerConfigFilePath(indexer); + File.Delete(configPath); + Indexers.Remove(name); + LoadMissingIndexers(); + } + } } diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index bc984da34..0defb5532 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -117,6 +117,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/Jackett/Program.cs b/src/Jackett/Program.cs index 16097de1f..66fdc9b95 100644 --- a/src/Jackett/Program.cs +++ b/src/Jackett/Program.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading; @@ -9,13 +10,12 @@ namespace Jackett { class Program { - public static ManualResetEvent ExitEvent = new ManualResetEvent(false); + public static string AppConfigDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Jackett"); - static IndexerManager indexerManager; + public static ManualResetEvent ExitEvent = new ManualResetEvent(false); static void Main(string[] args) { - indexerManager = new IndexerManager(); var resultPage = new ResultPage(new ChannelInfo { diff --git a/src/Jackett/Server.cs b/src/Jackett/Server.cs index f6483b6f3..6c797711e 100644 --- a/src/Jackett/Server.cs +++ b/src/Jackett/Server.cs @@ -18,6 +18,8 @@ namespace Jackett public Server() { + LoadApiKey(); + indexerManager = new IndexerManager(); webApi = new WebApi(indexerManager); @@ -25,6 +27,18 @@ namespace Jackett listener.Prefixes.Add("http://*:9117/"); } + void LoadApiKey() + { + var apiKeyFile = Path.Combine(Program.AppConfigDirectory, "api_key.txt"); + if (File.Exists(apiKeyFile)) + ApiKey.CurrentKey = File.ReadAllText(apiKeyFile).Trim(); + else + { + ApiKey.CurrentKey = ApiKey.Generate(); + File.WriteAllText(apiKeyFile, ApiKey.CurrentKey); + } + } + public async void Start() { listener.Start(); diff --git a/src/Jackett/WebApi.cs b/src/Jackett/WebApi.cs index 85a71b59a..921dbc33c 100644 --- a/src/Jackett/WebApi.cs +++ b/src/Jackett/WebApi.cs @@ -21,14 +21,16 @@ namespace Jackett GetConfigForm, ConfigureIndexer, GetIndexers, - TestIndexer + TestIndexer, + DeleteIndexer } static Dictionary WebApiMethods = new Dictionary { { "get_config_form", WebApiMethod.GetConfigForm }, { "configure_indexer", WebApiMethod.ConfigureIndexer }, { "get_indexers", WebApiMethod.GetIndexers }, - { "test_indexer", WebApiMethod.TestIndexer} + { "test_indexer", WebApiMethod.TestIndexer }, + { "delete_indexer", WebApiMethod.DeleteIndexer } }; IndexerManager indexerManager; @@ -80,102 +82,39 @@ namespace Jackett return JObject.Parse(postData); } + delegate Task HandlerTask(HttpListenerContext context); + async void ProcessWebApiRequest(HttpListenerContext context, WebApiMethod method) { var query = HttpUtility.ParseQueryString(context.Request.Url.Query); - JToken jsonReply = new JObject(); - context.Response.ContentType = "text/json"; context.Response.StatusCode = (int)HttpStatusCode.OK; + HandlerTask handlerTask; + switch (method) { case WebApiMethod.GetConfigForm: - try - { - var postData = await ReadPostDataJson(context.Request.InputStream); - string indexerString = (string)postData["indexer"]; - var indexer = indexerManager.GetIndexer(indexerString); - var config = await indexer.GetConfigurationForSetup(); - jsonReply["config"] = config.ToJson(); - jsonReply["name"] = indexer.DisplayName; - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } + handlerTask = HandleConfigForm; break; case WebApiMethod.ConfigureIndexer: - try - { - var postData = await ReadPostDataJson(context.Request.InputStream); - string indexerString = (string)postData["indexer"]; - var indexer = indexerManager.GetIndexer(indexerString); - jsonReply["name"] = indexer.DisplayName; - await indexer.ApplyConfiguration(postData["config"]); - await indexer.VerifyConnection(); - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - if (ex is ExceptionWithConfigData) - { - jsonReply["config"] = ((ExceptionWithConfigData)ex).ConfigData.ToJson(); - } - } + handlerTask = HandleConfigureIndexer; break; case WebApiMethod.GetIndexers: - try - { - jsonReply["result"] = "success"; - jsonReply["api_key"] = ApiKey.Generate(); - JArray items = new JArray(); - foreach (var i in indexerManager.Indexers) - { - var indexer = i.Value; - var item = new JObject(); - item["id"] = i.Key; - item["name"] = indexer.DisplayName; - item["description"] = indexer.DisplayDescription; - item["configured"] = indexer.IsConfigured; - item["site_link"] = indexer.SiteLink; - items.Add(item); - } - jsonReply["items"] = items; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } + handlerTask = HandleGetIndexers; break; case WebApiMethod.TestIndexer: - try - { - var postData = await ReadPostDataJson(context.Request.InputStream); - string indexerString = (string)postData["indexer"]; - var indexer = indexerManager.GetIndexer(indexerString); - jsonReply["name"] = indexer.DisplayName; - await indexer.VerifyConnection(); - jsonReply["result"] = "success"; - } - catch (Exception ex) - { - jsonReply["result"] = "error"; - jsonReply["error"] = ex.Message; - } + handlerTask = HandleTestIndexer; + break; + case WebApiMethod.DeleteIndexer: + handlerTask = HandleDeleteIndexer; break; default: - jsonReply["result"] = "error"; - jsonReply["error"] = "Invalid API method"; + handlerTask = HandleInvalidApiMethod; break; } - + JToken jsonReply = await handlerTask(context); ReplyWithJson(context, jsonReply); } @@ -186,5 +125,131 @@ namespace Jackett context.Response.OutputStream.Close(); } + Task HandleInvalidApiMethod(HttpListenerContext context) + { + return Task.Run(() => + { + JToken jsonReply = new JObject(); + jsonReply["result"] = "error"; + jsonReply["error"] = "Invalid API method"; + return jsonReply; + }); + } + + async Task HandleConfigForm(HttpListenerContext context) + { + JToken jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(context.Request.InputStream); + string indexerString = (string)postData["indexer"]; + var indexer = indexerManager.GetIndexer(indexerString); + var config = await indexer.GetConfigurationForSetup(); + jsonReply["config"] = config.ToJson(); + jsonReply["name"] = indexer.DisplayName; + jsonReply["result"] = "success"; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return jsonReply; + } + + async Task HandleConfigureIndexer(HttpListenerContext context) + { + JToken jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(context.Request.InputStream); + string indexerString = (string)postData["indexer"]; + var indexer = indexerManager.GetIndexer(indexerString); + jsonReply["name"] = indexer.DisplayName; + await indexer.ApplyConfiguration(postData["config"]); + await indexer.VerifyConnection(); + jsonReply["result"] = "success"; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + if (ex is ExceptionWithConfigData) + { + jsonReply["config"] = ((ExceptionWithConfigData)ex).ConfigData.ToJson(); + } + } + return jsonReply; + } + + Task HandleGetIndexers(HttpListenerContext context) + { + return Task.Run(() => + { + JToken jsonReply = new JObject(); + try + { + jsonReply["result"] = "success"; + jsonReply["api_key"] = ApiKey.CurrentKey; + JArray items = new JArray(); + foreach (var i in indexerManager.Indexers) + { + var indexer = i.Value; + var item = new JObject(); + item["id"] = i.Key; + item["name"] = indexer.DisplayName; + item["description"] = indexer.DisplayDescription; + item["configured"] = indexer.IsConfigured; + item["site_link"] = indexer.SiteLink; + items.Add(item); + } + jsonReply["items"] = items; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return jsonReply; + }); + } + + async Task HandleTestIndexer(HttpListenerContext context) + { + JToken jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(context.Request.InputStream); + string indexerString = (string)postData["indexer"]; + var indexer = indexerManager.GetIndexer(indexerString); + jsonReply["name"] = indexer.DisplayName; + await indexer.VerifyConnection(); + jsonReply["result"] = "success"; + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return jsonReply; + } + + async Task HandleDeleteIndexer(HttpListenerContext context) + { + JToken jsonReply = new JObject(); + try + { + var postData = await ReadPostDataJson(context.Request.InputStream); + string indexerString = (string)postData["indexer"]; + indexerManager.DeleteIndexer(indexerString); + } + catch (Exception ex) + { + jsonReply["result"] = "error"; + jsonReply["error"] = ex.Message; + } + return jsonReply; + } + } } diff --git a/src/Jackett/WebContent/crissXcross.png b/src/Jackett/WebContent/crissXcross.png new file mode 100644 index 000000000..c59f0e92f Binary files /dev/null and b/src/Jackett/WebContent/crissXcross.png differ diff --git a/src/Jackett/WebContent/index.html b/src/Jackett/WebContent/index.html index 5c799a5d1..479940b0b 100644 --- a/src/Jackett/WebContent/index.html +++ b/src/Jackett/WebContent/index.html @@ -13,7 +13,7 @@ Jackett