mirror of
https://github.com/Jackett/Jackett.git
synced 2025-09-17 17:34:09 +02:00
Web UI working
This commit is contained in:
28
src/Jackett/ApiKey.cs
Normal file
28
src/Jackett/ApiKey.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Jackett
|
||||||
|
{
|
||||||
|
public class ApiKey
|
||||||
|
{
|
||||||
|
const string chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
|
||||||
|
public static string Generate()
|
||||||
|
{
|
||||||
|
var randBytes = new byte[32];
|
||||||
|
var rngCsp = new RNGCryptoServiceProvider();
|
||||||
|
rngCsp.GetBytes(randBytes);
|
||||||
|
var key = "";
|
||||||
|
foreach (var b in randBytes)
|
||||||
|
{
|
||||||
|
key += chars[b % chars.Length];
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -58,7 +58,7 @@ namespace Jackett
|
|||||||
client = new HttpClient(handler);
|
client = new HttpClient(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string DisplayName { get { return "BitMeTV.org"; } }
|
public string DisplayName { get { return "BitMeTV"; } }
|
||||||
public string DisplayDescription { get { return "TV Episode specialty tracker"; } }
|
public string DisplayDescription { get { return "TV Episode specialty tracker"; } }
|
||||||
public Uri SiteLink { get { return new Uri("https://bitmetv.org"); } }
|
public Uri SiteLink { get { return new Uri("https://bitmetv.org"); } }
|
||||||
|
|
||||||
@@ -102,6 +102,7 @@ namespace Jackett
|
|||||||
var errorMessage = messageEl.Text();
|
var errorMessage = messageEl.Text();
|
||||||
var captchaImage = await client.GetByteArrayAsync(CaptchaUrl);
|
var captchaImage = await client.GetByteArrayAsync(CaptchaUrl);
|
||||||
config.CaptchaImage.Value = captchaImage;
|
config.CaptchaImage.Value = captchaImage;
|
||||||
|
config.CaptchaText.Value = "";
|
||||||
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
|
throw new ExceptionWithConfigData(errorMessage, (ConfigurationData)config);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -114,6 +115,8 @@ namespace Jackett
|
|||||||
|
|
||||||
if (OnSaveConfigurationRequested != null)
|
if (OnSaveConfigurationRequested != null)
|
||||||
OnSaveConfigurationRequested(configSaveData);
|
OnSaveConfigurationRequested(configSaveData);
|
||||||
|
|
||||||
|
IsConfigured = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -123,6 +126,8 @@ namespace Jackett
|
|||||||
return Task.Run(async () =>
|
return Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var result = await client.GetStringAsync(new Uri(SearchUrl));
|
var result = await client.GetStringAsync(new Uri(SearchUrl));
|
||||||
|
if (result.Contains("<h1>Not logged in!</h1>"))
|
||||||
|
throw new Exception("Detected as not logged in");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -67,6 +67,7 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="ApiKey.cs" />
|
||||||
<Compile Include="ChannelInfo.cs" />
|
<Compile Include="ChannelInfo.cs" />
|
||||||
<Compile Include="ConfigurationData.cs" />
|
<Compile Include="ConfigurationData.cs" />
|
||||||
<Compile Include="DataUrl.cs" />
|
<Compile Include="DataUrl.cs" />
|
||||||
@@ -91,7 +92,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="App.config" />
|
<None Include="App.config" />
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
<None Include="WebContent\bootstrap\glyphicons-halflings-regular.woff">
|
<None Include="WebContent\fonts\glyphicons-halflings-regular.woff">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -105,15 +106,15 @@
|
|||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Content Include="WebContent\congruent_outline.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="WebContent\handlebars-v3.0.1.js">
|
<Content Include="WebContent\handlebars-v3.0.1.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="WebContent\logos\bitmetv.png">
|
<Content Include="WebContent\logos\bitmetv.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="WebContent\logos\freshon.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="WebContent\bootstrap\bootstrap.min.css">
|
<Content Include="WebContent\bootstrap\bootstrap.min.css">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@@ -129,6 +130,9 @@
|
|||||||
<Content Include="WebContent\jquery-2.1.3.min.js">
|
<Content Include="WebContent\jquery-2.1.3.min.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="WebContent\logos\freshon.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="WebContent\setup_indexer.html">
|
<Content Include="WebContent\setup_indexer.html">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
@@ -19,13 +20,15 @@ namespace Jackett
|
|||||||
{
|
{
|
||||||
GetConfigForm,
|
GetConfigForm,
|
||||||
ConfigureIndexer,
|
ConfigureIndexer,
|
||||||
GetIndexers
|
GetIndexers,
|
||||||
|
TestIndexer
|
||||||
}
|
}
|
||||||
static Dictionary<string, WebApiMethod> WebApiMethods = new Dictionary<string, WebApiMethod>
|
static Dictionary<string, WebApiMethod> WebApiMethods = new Dictionary<string, WebApiMethod>
|
||||||
{
|
{
|
||||||
{ "get_config_form", WebApiMethod.GetConfigForm },
|
{ "get_config_form", WebApiMethod.GetConfigForm },
|
||||||
{ "configure_indexer", WebApiMethod.ConfigureIndexer },
|
{ "configure_indexer", WebApiMethod.ConfigureIndexer },
|
||||||
{ "get_indexers", WebApiMethod.GetIndexers }
|
{ "get_indexers", WebApiMethod.GetIndexers },
|
||||||
|
{ "test_indexer", WebApiMethod.TestIndexer}
|
||||||
};
|
};
|
||||||
|
|
||||||
IndexerManager indexerManager;
|
IndexerManager indexerManager;
|
||||||
@@ -63,8 +66,12 @@ namespace Jackett
|
|||||||
var contentFile = File.ReadAllBytes(Path.Combine(WebContentFolder, file));
|
var contentFile = File.ReadAllBytes(Path.Combine(WebContentFolder, file));
|
||||||
context.Response.ContentType = MimeMapping.GetMimeMapping(file);
|
context.Response.ContentType = MimeMapping.GetMimeMapping(file);
|
||||||
context.Response.StatusCode = (int)HttpStatusCode.OK;
|
context.Response.StatusCode = (int)HttpStatusCode.OK;
|
||||||
await context.Response.OutputStream.WriteAsync(contentFile, 0, contentFile.Length);
|
try
|
||||||
context.Response.OutputStream.Close();
|
{
|
||||||
|
await context.Response.OutputStream.WriteAsync(contentFile, 0, contentFile.Length);
|
||||||
|
context.Response.OutputStream.Close();
|
||||||
|
}
|
||||||
|
catch (HttpListenerException) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<JToken> ReadPostDataJson(Stream stream)
|
async Task<JToken> ReadPostDataJson(Stream stream)
|
||||||
@@ -92,6 +99,7 @@ namespace Jackett
|
|||||||
var indexer = indexerManager.GetIndexer(indexerString);
|
var indexer = indexerManager.GetIndexer(indexerString);
|
||||||
var config = await indexer.GetConfigurationForSetup();
|
var config = await indexer.GetConfigurationForSetup();
|
||||||
jsonReply["config"] = config.ToJson();
|
jsonReply["config"] = config.ToJson();
|
||||||
|
jsonReply["name"] = indexer.DisplayName;
|
||||||
jsonReply["result"] = "success";
|
jsonReply["result"] = "success";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -106,6 +114,7 @@ namespace Jackett
|
|||||||
var postData = await ReadPostDataJson(context.Request.InputStream);
|
var postData = await ReadPostDataJson(context.Request.InputStream);
|
||||||
string indexerString = (string)postData["indexer"];
|
string indexerString = (string)postData["indexer"];
|
||||||
var indexer = indexerManager.GetIndexer(indexerString);
|
var indexer = indexerManager.GetIndexer(indexerString);
|
||||||
|
jsonReply["name"] = indexer.DisplayName;
|
||||||
await indexer.ApplyConfiguration(postData["config"]);
|
await indexer.ApplyConfiguration(postData["config"]);
|
||||||
await indexer.VerifyConnection();
|
await indexer.VerifyConnection();
|
||||||
jsonReply["result"] = "success";
|
jsonReply["result"] = "success";
|
||||||
@@ -124,15 +133,16 @@ namespace Jackett
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
jsonReply["result"] = "success";
|
jsonReply["result"] = "success";
|
||||||
|
jsonReply["api_key"] = ApiKey.Generate();
|
||||||
JArray items = new JArray();
|
JArray items = new JArray();
|
||||||
foreach (var i in indexerManager.Indexers)
|
foreach (var i in indexerManager.Indexers)
|
||||||
{
|
{
|
||||||
var indexer = i.Value;
|
var indexer = i.Value;
|
||||||
var item = new JObject();
|
var item = new JObject();
|
||||||
item["id"] = i.Key;
|
item["id"] = i.Key;
|
||||||
item["display_name"] = indexer.DisplayName;
|
item["name"] = indexer.DisplayName;
|
||||||
item["display_description"] = indexer.DisplayDescription;
|
item["description"] = indexer.DisplayDescription;
|
||||||
item["is_configured"] = indexer.IsConfigured;
|
item["configured"] = indexer.IsConfigured;
|
||||||
item["site_link"] = indexer.SiteLink;
|
item["site_link"] = indexer.SiteLink;
|
||||||
items.Add(item);
|
items.Add(item);
|
||||||
}
|
}
|
||||||
@@ -144,6 +154,22 @@ namespace Jackett
|
|||||||
jsonReply["error"] = ex.Message;
|
jsonReply["error"] = ex.Message;
|
||||||
}
|
}
|
||||||
break;
|
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;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
jsonReply["result"] = "error";
|
jsonReply["result"] = "error";
|
||||||
jsonReply["error"] = "Invalid API method";
|
jsonReply["error"] = "Invalid API method";
|
||||||
|
BIN
src/Jackett/WebContent/congruent_outline.png
Normal file
BIN
src/Jackett/WebContent/congruent_outline.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
@@ -9,36 +9,353 @@
|
|||||||
<link href="bootstrap/bootstrap.min.css" rel="stylesheet">
|
<link href="bootstrap/bootstrap.min.css" rel="stylesheet">
|
||||||
<title>Jackett</title>
|
<title>Jackett</title>
|
||||||
<style>
|
<style>
|
||||||
|
body {
|
||||||
|
background-image: url("congruent_outline.png");
|
||||||
|
background-repeat: repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page {
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: white;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-top: 30px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-fluid {
|
||||||
|
}
|
||||||
|
|
||||||
#templates {
|
#templates {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#api-key-input {
|
||||||
|
width: 300px;
|
||||||
|
display: inline-block;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
#api-key-header {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 1px 1px 5px 2px #cdcdcd;
|
||||||
|
padding: 10px;
|
||||||
|
width: 225px;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 30px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unconfigured-indexer {
|
||||||
|
height: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indexer {
|
||||||
|
height: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#add-indexer {
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indexer-logo {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indexer-logo > img {
|
||||||
|
border: 1px solid #828282;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indexer-name > h3 {
|
||||||
|
margin-top: 13px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indexer-buttons {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indexer-add-content {
|
||||||
|
color: gray;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indexer-add-content > .glyphicon {
|
||||||
|
font-size: 50px;
|
||||||
|
margin-top: 35%;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indexer-add-content > .light-text {
|
||||||
|
margin-top: 11px;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-left: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indexer-host {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indexer-host > input {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-item-inputstring {
|
||||||
|
max-width: 260px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container-fluid">
|
<div id="page">
|
||||||
<div id="indexers"></div>
|
|
||||||
|
<div id="api-key">
|
||||||
|
<span id="api-key-header">API Key: </span>
|
||||||
|
<input id="api-key-input" class="form-control" type="text" value="" placeholder="API Key" readonly="">
|
||||||
|
<span>(Same key works for all indexers)</span>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<h3>Configured Indexers</h3>
|
||||||
|
<div id="indexers">
|
||||||
|
|
||||||
|
<a class="indexer card" id="add-indexer" href="#" data-toggle="modal" data-target="#select-indexer-modal">
|
||||||
|
<div class="indexer-add-content">
|
||||||
|
<span class="glyphicon glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||||
|
<div class="light-text">Add</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="templates">
|
<div id="select-indexer-modal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
<div class="indexer">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="indexer-name">{{name}}</div>
|
<div class="modal-content">
|
||||||
<div class="indexer-description">{{description}}</div>
|
<div class="modal-header">
|
||||||
<div class="indexer-link"><a href="{{link}}">{{link}}</a></div>
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
<div class="indexer-configured">
|
<h4 class="modal-title">Select an indexer to setup</h4>
|
||||||
{{#if configured}}
|
</div>
|
||||||
<span>Configred</span>
|
<div class="modal-body">
|
||||||
{{else}}
|
<div id="unconfigured-indexers">
|
||||||
<span>Not configured</span>
|
</div>
|
||||||
{{/if}}
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="setup-indexer-modal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-sm">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title">Setup indexer</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="indexer-setup-form"></form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="setup-indexer-go">Okay</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="templates">
|
||||||
|
|
||||||
|
<div class="indexer card">
|
||||||
|
<div class="indexer-logo"><img src="logos/{{id}}.png" /></div>
|
||||||
|
<div class="indexer-name"><h3>{{name}}</h3></div>
|
||||||
|
<div class="indexer-buttons">
|
||||||
|
<a class="btn btn-info btn-sm" target="_blank" href="{{site_link}}">Visit <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span></a>
|
||||||
|
<a class="btn btn-danger btn-sm" href="#">Delete <span class="glyphicon glyphicon-trash" aria-hidden="true"></span></a>
|
||||||
|
<a class="btn btn-primary btn-sm indexer-button-test" href="#" data-id="{{id}}">Test <span class="glyphicon glyphicon-screenshot" aria-hidden="true"></span></a>
|
||||||
|
</div>
|
||||||
|
<div class="indexer-host">
|
||||||
|
<b>Torznab Host:</b>
|
||||||
|
<input class="form-control" type="text" value="{{torznab_host}}" placeholder="Torznab Host" readonly="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="unconfigured-indexer card">
|
||||||
|
<div class="indexer-logo"><img src="logos/{{id}}.png" /></div>
|
||||||
|
<div class="indexer-name"><h3>{{name}}</h3></div>
|
||||||
|
<div class="indexer-buttons">
|
||||||
|
<a class="btn btn-info" target="_blank" href="{{site_link}}">Visit <span class="glyphicon glyphicon-new-window" aria-hidden="true"></span></a>
|
||||||
|
<button class="indexer-setup btn btn-success" data-id="{{id}}">Setup <span class="glyphicon glyphicon-ok" aria-hidden="true"></span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="setup-item form-group" data-id="{{id}}" data-value="{{value}}" data-type="{{type}}">
|
||||||
|
<div class="setup-item-label">{{name}}</div>
|
||||||
|
<div class="setup-item-value">{{{value_element}}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4 class="setup-item-header" data-type="indexer" data-name="{{name}}" data-indexer="{{indexer}}">{{name}}</h4>
|
||||||
|
<input class="setup-item-inputstring form-control" type="text" value="{{{value}}}"></input>
|
||||||
|
<div class="setup-item-checkbox">
|
||||||
|
{{#if value}}
|
||||||
|
<input type="checkbox" class="form-control" checked></input>
|
||||||
|
{{else}}
|
||||||
|
<input type="checkbox" class="form-control"></input>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<img class="setup-item-displayimage" src="{{{value}}}" />
|
||||||
|
<span class="setup-item-displayinfo">{{{value}}}</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
|
||||||
var indexerTemplate = Handlebars.compile($("#templates > .indexer").html());
|
function reloadIndexers() {
|
||||||
$('#indexers').append(indexerTemplate({ name: "n", description: "desc", link: "http://google.com", configured: true }));
|
$('#indexers').hide();
|
||||||
|
$('#indexers > div.indexer').remove();
|
||||||
|
$('#unconfigured-indexers').empty();
|
||||||
|
var jqxhr = $.get("get_indexers", function (data) {
|
||||||
|
$("#api-key-input").val(data.api_key);
|
||||||
|
displayIndexers(data.items);
|
||||||
|
}).fail(function () {
|
||||||
|
alert("error");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayIndexers(items) {
|
||||||
|
var indexerTemplate = Handlebars.compile($("#templates > .indexer")[0].outerHTML);
|
||||||
|
var unconfiguredIndexerTemplate = Handlebars.compile($("#templates > .unconfigured-indexer")[0].outerHTML);
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
var item = items[i];
|
||||||
|
item.torznab_host = resolveUrl("/torznab/" + item.id);
|
||||||
|
if (item.configured)
|
||||||
|
$('#indexers').prepend(indexerTemplate(item));
|
||||||
|
else
|
||||||
|
$('#unconfigured-indexers').prepend($(unconfiguredIndexerTemplate(item)));
|
||||||
|
}
|
||||||
|
$('#indexers').fadeIn();
|
||||||
|
prepareSetupButtons();
|
||||||
|
prepareTestButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareSetupButtons() {
|
||||||
|
$('.indexer-setup').each(function (i, btn) {
|
||||||
|
var $btn = $(btn);
|
||||||
|
var id = $btn.data("id");
|
||||||
|
$btn.click(function () {
|
||||||
|
displayIndexerSetup(id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareTestButtons() {
|
||||||
|
$(".indexer-button-test").each(function (i, btn) {
|
||||||
|
var $btn = $(btn);
|
||||||
|
var id = $btn.data("id");
|
||||||
|
$btn.click(function () {
|
||||||
|
var jqxhr = $.post("test_indexer", JSON.stringify({ indexer: id }), function (data) {
|
||||||
|
if (data.result == "error") {
|
||||||
|
alert("Test failed for " + data.name + "\n" + data.error);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert("Test successful for " + data.name);
|
||||||
|
}
|
||||||
|
}).fail(function () {
|
||||||
|
alert("error");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayIndexerSetup(id) {
|
||||||
|
|
||||||
|
var jqxhr = $.post("get_config_form", JSON.stringify({ indexer: id }), function (data) {
|
||||||
|
if (data.result == "error") {
|
||||||
|
alert(data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
populateSetupForm(id, data.name, data.config);
|
||||||
|
$("#setup-indexer-modal").modal("show");
|
||||||
|
}).fail(function () {
|
||||||
|
alert("error");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#select-indexer-modal").modal("hide");
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateSetupForm(indexerId, name, config) {
|
||||||
|
$("#indexer-setup-form").empty();
|
||||||
|
var setupItemHeader = Handlebars.compile($("#templates > .setup-item-header")[0].outerHTML);
|
||||||
|
$("#indexer-setup-form").append(setupItemHeader({ indexer: indexerId, name: name }));
|
||||||
|
var setupItemTemplate = Handlebars.compile($("#templates > .setup-item")[0].outerHTML);
|
||||||
|
for (var i = 0; i < config.length; i++) {
|
||||||
|
var item = config[i];
|
||||||
|
var setupValueTemplate = Handlebars.compile($("#templates > .setup-item-" + item.type)[0].outerHTML);
|
||||||
|
item.value_element = setupValueTemplate(item);
|
||||||
|
$("#indexer-setup-form").append(setupItemTemplate(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveUrl(url) {
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
url = a.href;
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#setup-indexer-go").click(function () {
|
||||||
|
var data = { config: {} };
|
||||||
|
$("#indexer-setup-form").children().each(function (i, el) {
|
||||||
|
$el = $(el);
|
||||||
|
var type = $el.data("type");
|
||||||
|
var id = $el.data("id");
|
||||||
|
switch (type) {
|
||||||
|
case "indexer":
|
||||||
|
data.indexer = $el.data("indexer");
|
||||||
|
data.name = $el.data("name")
|
||||||
|
return;
|
||||||
|
case "inputstring":
|
||||||
|
data.config[id] = $el.find(".setup-item-inputstring").val();
|
||||||
|
break;
|
||||||
|
case "inputbool":
|
||||||
|
data.config[id] = $el.find(".setup-item-checkbox").val();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sendSetupData(data.indexer, data.name, data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function sendSetupData(indexerId, name, data) {
|
||||||
|
var jqxhr = $.post("configure_indexer", JSON.stringify(data), function (data) {
|
||||||
|
if (data.result == "error") {
|
||||||
|
if (data.config) {
|
||||||
|
populateSetupForm(indexerId, name, data.config);
|
||||||
|
}
|
||||||
|
alert(data.error);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#setup-indexer-modal").modal("hide");
|
||||||
|
reloadIndexers();
|
||||||
|
alert("success");
|
||||||
|
}
|
||||||
|
}).fail(function () {
|
||||||
|
alert("error");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadIndexers();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Binary file not shown.
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 28 KiB |
Reference in New Issue
Block a user