mirror of https://github.com/Jackett/Jackett
Web UI development started
This commit is contained in:
parent
7b4e6f97d5
commit
a4f18471a8
|
@ -1,6 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
|
||||
</startup>
|
||||
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
|
|
|
@ -4,21 +4,16 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Jackett
|
||||
{
|
||||
public class DataUrl
|
||||
{
|
||||
static Dictionary<string, string> ImageMimeTypes = new Dictionary<string, string>{
|
||||
{ ".jpg", "data:image/jpeg" },
|
||||
{ ".jpeg", "data:image/jpeg" },
|
||||
{ ".png", "data:image/png" },
|
||||
{ ".gif", "data:image/gif" }
|
||||
};
|
||||
|
||||
public static string ReadFileToDataUrl(string file)
|
||||
{
|
||||
string mime = ImageMimeTypes[Path.GetExtension(file)];
|
||||
string mime = MimeMapping.GetMimeMapping(file);
|
||||
return "data:" + mime + ";base64," + Convert.ToBase64String(File.ReadAllBytes(file));
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,7 @@ namespace Jackett
|
|||
{
|
||||
string DisplayName { get; }
|
||||
string DisplayDescription { get; }
|
||||
Uri SitLink { get; }
|
||||
|
||||
Uri SiteLink { get; }
|
||||
|
||||
// Retrieved for starting setup for the indexer via web API
|
||||
Task<ConfigurationData> GetConfigurationForSetup();
|
||||
|
|
|
@ -13,30 +13,26 @@ namespace Jackett
|
|||
static string AppConfigDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
static string IndexerConfigDirectory = Path.Combine(AppConfigDirectory, "Indexers");
|
||||
|
||||
Dictionary<string, IndexerInterface> loadedIndexers;
|
||||
|
||||
Dictionary<string, Type> implementedIndexerTypes;
|
||||
public Dictionary<string, IndexerInterface> Indexers { get; private set; }
|
||||
|
||||
public IndexerManager()
|
||||
{
|
||||
loadedIndexers = new Dictionary<string, IndexerInterface>();
|
||||
Indexers = new Dictionary<string, IndexerInterface>();
|
||||
|
||||
implementedIndexerTypes = (AppDomain.CurrentDomain.GetAssemblies()
|
||||
var implementedIndexerTypes = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(s => s.GetTypes())
|
||||
.Where(p => typeof(IndexerInterface).IsAssignableFrom(p)))
|
||||
.ToDictionary(t => t.Name.ToLower());
|
||||
.Where(p => typeof(IndexerInterface).IsAssignableFrom(p) && !p.IsInterface)
|
||||
.ToArray();
|
||||
|
||||
|
||||
// TODO: initialize all indexers at start, read all saved config json files then fill their indexers
|
||||
foreach (var t in implementedIndexerTypes)
|
||||
{
|
||||
LoadIndexer(t);
|
||||
}
|
||||
}
|
||||
|
||||
IndexerInterface LoadIndexer(string name)
|
||||
IndexerInterface LoadIndexer(Type indexerType)
|
||||
{
|
||||
name = name.Trim().ToLower();
|
||||
|
||||
Type indexerType;
|
||||
if (!implementedIndexerTypes.TryGetValue(name, out indexerType))
|
||||
throw new Exception(string.Format("No indexer of type '{0}'", name));
|
||||
var name = indexerType.Name.Trim().ToLower();
|
||||
|
||||
IndexerInterface newIndexer = (IndexerInterface)Activator.CreateInstance(indexerType);
|
||||
|
||||
|
@ -47,15 +43,15 @@ namespace Jackett
|
|||
newIndexer.LoadFromSavedConfiguration(jsonString);
|
||||
}
|
||||
|
||||
loadedIndexers.Add(name, newIndexer);
|
||||
Indexers.Add(name, newIndexer);
|
||||
return newIndexer;
|
||||
}
|
||||
|
||||
public IndexerInterface GetIndexer(string name)
|
||||
{
|
||||
IndexerInterface indexer;
|
||||
if (!loadedIndexers.TryGetValue(name, out indexer))
|
||||
indexer = LoadIndexer(name);
|
||||
if (!Indexers.TryGetValue(name, out indexer))
|
||||
throw new Exception(string.Format("No indexer with ID '{0}'", name));
|
||||
return indexer;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace Jackett
|
|||
|
||||
public string DisplayName { get { return "BitMeTV.org"; } }
|
||||
public string DisplayDescription { get { return "TV Episode specialty tracker"; } }
|
||||
public Uri SitLink { get { return new Uri("https://bitmetv.org"); } }
|
||||
public Uri SiteLink { get { return new Uri("https://bitmetv.org"); } }
|
||||
|
||||
public bool IsConfigured { get; private set; }
|
||||
|
||||
|
@ -81,7 +81,7 @@ namespace Jackett
|
|||
return Task.Run(async () =>
|
||||
{
|
||||
var config = new BmtvConfig();
|
||||
config.LoadValuesFromJson(configJson["config"]);
|
||||
config.LoadValuesFromJson(configJson);
|
||||
|
||||
var pairs = new Dictionary<string, string>
|
||||
{
|
||||
|
|
|
@ -11,8 +11,20 @@ namespace Jackett
|
|||
public class Freshon : IndexerInterface
|
||||
{
|
||||
|
||||
public string DisplayName { get; private set; }
|
||||
public string DisplayName
|
||||
{
|
||||
get { return "FreshOnTV"; }
|
||||
}
|
||||
|
||||
public string DisplayDescription
|
||||
{
|
||||
get { return "Our goal is to provide the latest stuff in the TV show domain"; }
|
||||
}
|
||||
|
||||
public Uri SiteLink
|
||||
{
|
||||
get { return new Uri("https://freshon.tv/"); }
|
||||
}
|
||||
|
||||
public Task<ConfigurationData> GetConfigurationForSetup()
|
||||
{
|
||||
|
@ -33,23 +45,12 @@ namespace Jackett
|
|||
|
||||
public bool IsConfigured
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public void LoadFromSavedConfiguration(JToken jsonConfig)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public string DisplayDescription
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public Uri SitLink
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,8 @@
|
|||
<Reference Include="CsQuery">
|
||||
<HintPath>..\packages\CsQuery.1.3.4\lib\net40\CsQuery.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
|
@ -85,10 +86,14 @@
|
|||
<Compile Include="ResultPage.cs" />
|
||||
<Compile Include="Server.cs" />
|
||||
<Compile Include="TorznabQuery.cs" />
|
||||
<Compile Include="WebApi.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="WebContent\bootstrap\glyphicons-halflings-regular.woff">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\test.xml" />
|
||||
|
@ -100,20 +105,32 @@
|
|||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="WebContent\handlebars-v3.0.1.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WebContent\logos\bitmetv.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WebContent\logos\freshon.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WebContent\bootstrap\bootstrap.min.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WebContent\bootstrap\bootstrap.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WebContent\common.js">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WebContent\index.html">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WebContent\jquery-2.1.3.min.js">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WebContent\setup_indexer.html">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="WebContent\IndexerImages\bitmetv.jpg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Resources\validator_reply.xml" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -14,23 +14,12 @@ namespace Jackett
|
|||
{
|
||||
HttpListener listener;
|
||||
IndexerManager indexerManager;
|
||||
|
||||
static string[] StaticFiles = Directory.EnumerateFiles("WebContent", "*", SearchOption.AllDirectories).Select(Path.GetFileName).ToArray();
|
||||
|
||||
enum WebApiMethod
|
||||
{
|
||||
GetConfigForm,
|
||||
ConfigureIndexer
|
||||
}
|
||||
static Dictionary<string, WebApiMethod> WebApiMethods = new Dictionary<string, WebApiMethod>
|
||||
{
|
||||
{ "get_config_form", WebApiMethod.GetConfigForm },
|
||||
{ "configure_indexer", WebApiMethod.ConfigureIndexer }
|
||||
};
|
||||
WebApi webApi;
|
||||
|
||||
public Server()
|
||||
{
|
||||
indexerManager = new IndexerManager();
|
||||
webApi = new WebApi(indexerManager);
|
||||
|
||||
listener = new HttpListener();
|
||||
listener.Prefixes.Add("http://*:9117/");
|
||||
|
@ -42,7 +31,7 @@ namespace Jackett
|
|||
while (true)
|
||||
{
|
||||
var context = await listener.GetContextAsync();
|
||||
ProcessContext(context);
|
||||
ProcessHttpRequest(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,114 +41,10 @@ namespace Jackett
|
|||
listener.Abort();
|
||||
}
|
||||
|
||||
static Dictionary<string, string> MimeMapping = new Dictionary<string, string> {
|
||||
{ ".html", "text/html" },
|
||||
{ ".js", "application/javascript" }
|
||||
};
|
||||
|
||||
async void ServeStaticFile(HttpListenerContext context, string file)
|
||||
async void ProcessHttpRequest(HttpListenerContext context)
|
||||
{
|
||||
var contentFile = File.ReadAllBytes(Path.Combine("WebContent", file));
|
||||
|
||||
string contentType;
|
||||
MimeMapping.TryGetValue(Path.GetExtension(file), out contentType);
|
||||
|
||||
context.Response.ContentType = contentType;
|
||||
context.Response.StatusCode = (int)HttpStatusCode.OK;
|
||||
await context.Response.OutputStream.WriteAsync(contentFile, 0, contentFile.Length);
|
||||
context.Response.OutputStream.Close();
|
||||
}
|
||||
|
||||
async void ProcessWebApiRequest(HttpListenerContext context, WebApiMethod method)
|
||||
{
|
||||
var query = HttpUtility.ParseQueryString(context.Request.Url.Query);
|
||||
|
||||
string postData = await new StreamReader(context.Request.InputStream).ReadToEndAsync();
|
||||
JToken dataJson = JObject.Parse(postData);
|
||||
JToken jsonReply = new JObject();
|
||||
var indexerString = (string)dataJson["indexer"];
|
||||
IndexerInterface indexer;
|
||||
|
||||
try
|
||||
if (webApi.HandleRequest(context))
|
||||
{
|
||||
indexer = indexerManager.GetIndexer(indexerString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
jsonReply["result"] = "error";
|
||||
jsonReply["error"] = ex.Message;
|
||||
ReplyWithJson(context, jsonReply);
|
||||
return;
|
||||
}
|
||||
|
||||
context.Response.ContentType = "text/json";
|
||||
context.Response.StatusCode = (int)HttpStatusCode.OK;
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case WebApiMethod.GetConfigForm:
|
||||
try
|
||||
{
|
||||
var config = await indexer.GetConfigurationForSetup();
|
||||
jsonReply = config.ToJson();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
jsonReply["result"] = "error";
|
||||
jsonReply["error"] = ex.Message;
|
||||
}
|
||||
break;
|
||||
case WebApiMethod.ConfigureIndexer:
|
||||
try
|
||||
{
|
||||
await indexer.ApplyConfiguration(dataJson);
|
||||
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();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
jsonReply["result"] = "error";
|
||||
jsonReply["error"] = "Invalid API method";
|
||||
break;
|
||||
}
|
||||
|
||||
ReplyWithJson(context, jsonReply);
|
||||
}
|
||||
|
||||
async void ReplyWithJson(HttpListenerContext context, JToken json)
|
||||
{
|
||||
byte[] jsonBytes = Encoding.UTF8.GetBytes(json.ToString());
|
||||
await context.Response.OutputStream.WriteAsync(jsonBytes, 0, jsonBytes.Length);
|
||||
context.Response.OutputStream.Close();
|
||||
}
|
||||
|
||||
async void ProcessContext(HttpListenerContext context)
|
||||
{
|
||||
Console.WriteLine(context.Request.Url.Query);
|
||||
|
||||
string path = context.Request.Url.AbsolutePath.TrimStart('/');
|
||||
if (path == "")
|
||||
path = "index.html";
|
||||
|
||||
if (Array.IndexOf(StaticFiles, path) > -1)
|
||||
{
|
||||
ServeStaticFile(context, path);
|
||||
return;
|
||||
}
|
||||
|
||||
WebApiMethod apiMethod;
|
||||
if (WebApiMethods.TryGetValue(path, out apiMethod))
|
||||
{
|
||||
ProcessWebApiRequest(context, apiMethod);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Jackett
|
||||
{
|
||||
public class WebApi
|
||||
{
|
||||
static string WebContentFolder = "WebContent";
|
||||
static string[] StaticFiles = Directory.EnumerateFiles(WebContentFolder, "*", SearchOption.AllDirectories).ToArray();
|
||||
|
||||
public enum WebApiMethod
|
||||
{
|
||||
GetConfigForm,
|
||||
ConfigureIndexer,
|
||||
GetIndexers
|
||||
}
|
||||
static Dictionary<string, WebApiMethod> WebApiMethods = new Dictionary<string, WebApiMethod>
|
||||
{
|
||||
{ "get_config_form", WebApiMethod.GetConfigForm },
|
||||
{ "configure_indexer", WebApiMethod.ConfigureIndexer },
|
||||
{ "get_indexers", WebApiMethod.GetIndexers }
|
||||
};
|
||||
|
||||
IndexerManager indexerManager;
|
||||
|
||||
public WebApi(IndexerManager indexerManager)
|
||||
{
|
||||
this.indexerManager = indexerManager;
|
||||
}
|
||||
|
||||
public bool HandleRequest(HttpListenerContext context)
|
||||
{
|
||||
string path = context.Request.Url.AbsolutePath.TrimStart('/');
|
||||
if (path == "")
|
||||
path = "index.html";
|
||||
|
||||
var sysPath = Path.Combine(WebContentFolder, path.Replace("/", Path.DirectorySeparatorChar.ToString()));
|
||||
if (Array.IndexOf(StaticFiles, sysPath) > -1)
|
||||
{
|
||||
ServeStaticFile(context, path);
|
||||
return true;
|
||||
}
|
||||
|
||||
WebApi.WebApiMethod apiMethod;
|
||||
if (WebApi.WebApiMethods.TryGetValue(path, out apiMethod))
|
||||
{
|
||||
ProcessWebApiRequest(context, apiMethod);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async void ServeStaticFile(HttpListenerContext context, string file)
|
||||
{
|
||||
var contentFile = File.ReadAllBytes(Path.Combine(WebContentFolder, file));
|
||||
context.Response.ContentType = MimeMapping.GetMimeMapping(file);
|
||||
context.Response.StatusCode = (int)HttpStatusCode.OK;
|
||||
await context.Response.OutputStream.WriteAsync(contentFile, 0, contentFile.Length);
|
||||
context.Response.OutputStream.Close();
|
||||
}
|
||||
|
||||
async Task<JToken> ReadPostDataJson(Stream stream)
|
||||
{
|
||||
string postData = await new StreamReader(stream).ReadToEndAsync();
|
||||
return JObject.Parse(postData);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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["result"] = "success";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
jsonReply["result"] = "error";
|
||||
jsonReply["error"] = ex.Message;
|
||||
}
|
||||
break;
|
||||
case WebApiMethod.ConfigureIndexer:
|
||||
try
|
||||
{
|
||||
var postData = await ReadPostDataJson(context.Request.InputStream);
|
||||
string indexerString = (string)postData["indexer"];
|
||||
var indexer = indexerManager.GetIndexer(indexerString);
|
||||
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();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WebApiMethod.GetIndexers:
|
||||
try
|
||||
{
|
||||
jsonReply["result"] = "success";
|
||||
JArray items = new JArray();
|
||||
foreach (var i in indexerManager.Indexers)
|
||||
{
|
||||
var indexer = i.Value;
|
||||
var item = new JObject();
|
||||
item["id"] = i.Key;
|
||||
item["display_name"] = indexer.DisplayName;
|
||||
item["display_description"] = indexer.DisplayDescription;
|
||||
item["is_configured"] = indexer.IsConfigured;
|
||||
item["site_link"] = indexer.SiteLink;
|
||||
items.Add(item);
|
||||
}
|
||||
jsonReply["items"] = items;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
jsonReply["result"] = "error";
|
||||
jsonReply["error"] = ex.Message;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
jsonReply["result"] = "error";
|
||||
jsonReply["error"] = "Invalid API method";
|
||||
break;
|
||||
}
|
||||
|
||||
ReplyWithJson(context, jsonReply);
|
||||
}
|
||||
|
||||
async void ReplyWithJson(HttpListenerContext context, JToken json)
|
||||
{
|
||||
byte[] jsonBytes = Encoding.UTF8.GetBytes(json.ToString());
|
||||
await context.Response.OutputStream.WriteAsync(jsonBytes, 0, jsonBytes.Length);
|
||||
context.Response.OutputStream.Close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 56 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -3,9 +3,42 @@
|
|||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title></title>
|
||||
<script src="jquery-2.1.3.min.js"></script>
|
||||
<script src="handlebars-v3.0.1.js"></script>
|
||||
<script src="bootstrap/bootstrap.min.js"></script>
|
||||
<link href="bootstrap/bootstrap.min.css" rel="stylesheet">
|
||||
<title>Jackett</title>
|
||||
<style>
|
||||
#templates {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
home
|
||||
<div class="container-fluid">
|
||||
<div id="indexers"></div>
|
||||
</div>
|
||||
|
||||
<div id="templates">
|
||||
<div class="indexer">
|
||||
<div class="indexer-name">{{name}}</div>
|
||||
<div class="indexer-description">{{description}}</div>
|
||||
<div class="indexer-link"><a href="{{link}}">{{link}}</a></div>
|
||||
<div class="indexer-configured">
|
||||
{{#if configured}}
|
||||
<span>Configred</span>
|
||||
{{else}}
|
||||
<span>Not configured</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
var indexerTemplate = Handlebars.compile($("#templates > .indexer").html());
|
||||
$('#indexers').append(indexerTemplate({ name: "n", description: "desc", link: "http://google.com", configured: true }));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
|
@ -20,7 +20,7 @@
|
|||
var urlParams = getUrlParams();
|
||||
|
||||
var jqxhr = $.post("get_config_form", JSON.stringify({ indexer: urlParams.indexer }), function (data) {
|
||||
populateForm(data);
|
||||
populateForm(data.config);
|
||||
})
|
||||
.fail(function () {
|
||||
alert("error");
|
||||
|
|
Loading…
Reference in New Issue