mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-23 06:45:19 -07:00
Second UI Pass, Testing now works and other little things.
This commit is contained in:
parent
ad26e48408
commit
76a42b28f3
22 changed files with 381 additions and 372 deletions
|
@ -34,6 +34,7 @@ using NzbDrone.Core.Extras.Metadata.Files;
|
||||||
using NzbDrone.Core.Extras.Others;
|
using NzbDrone.Core.Extras.Others;
|
||||||
using NzbDrone.Core.Extras.Subtitles;
|
using NzbDrone.Core.Extras.Subtitles;
|
||||||
using NzbDrone.Core.Messaging.Commands;
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
|
using NzbDrone.Core.NetImport;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore
|
namespace NzbDrone.Core.Datastore
|
||||||
{
|
{
|
||||||
|
@ -55,6 +56,10 @@ namespace NzbDrone.Core.Datastore
|
||||||
.Ignore(i => i.SupportsRss)
|
.Ignore(i => i.SupportsRss)
|
||||||
.Ignore(i => i.SupportsSearch);
|
.Ignore(i => i.SupportsSearch);
|
||||||
|
|
||||||
|
Mapper.Entity<NetImportDefinition>().RegisterDefinition("NetImport")
|
||||||
|
.Ignore(i => i.Enable)
|
||||||
|
.Ignore(i => i.ConfigContract);
|
||||||
|
|
||||||
Mapper.Entity<NotificationDefinition>().RegisterDefinition("Notifications")
|
Mapper.Entity<NotificationDefinition>().RegisterDefinition("Notifications")
|
||||||
.Ignore(i => i.SupportsOnGrab)
|
.Ignore(i => i.SupportsOnGrab)
|
||||||
.Ignore(i => i.SupportsOnDownload)
|
.Ignore(i => i.SupportsOnDownload)
|
||||||
|
|
|
@ -10,6 +10,7 @@ using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Http.CloudFlare;
|
using NzbDrone.Core.Http.CloudFlare;
|
||||||
using NzbDrone.Core.Indexers.Exceptions;
|
using NzbDrone.Core.Indexers.Exceptions;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
using NzbDrone.Core.NetImport.Exceptions;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
@ -230,13 +231,65 @@ namespace NzbDrone.Core.NetImport
|
||||||
|
|
||||||
protected override void Test(List<ValidationFailure> failures)
|
protected override void Test(List<ValidationFailure> failures)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
failures.AddIfNotNull(TestConnection());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual ValidationFailure TestConnection()
|
protected virtual ValidationFailure TestConnection()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var parser = GetParser();
|
||||||
|
var generator = GetRequestGenerator();
|
||||||
|
var releases = FetchPage(generator.GetMovies().GetAllTiers().First().First(), parser);
|
||||||
|
|
||||||
|
if (releases.Empty())
|
||||||
|
{
|
||||||
|
return new ValidationFailure(string.Empty, "No results were returned from your list, please check your settings.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ApiKeyException)
|
||||||
|
{
|
||||||
|
_logger.Warn("List returned result for RSS URL, API Key appears to be invalid");
|
||||||
|
|
||||||
|
return new ValidationFailure("ApiKey", "Invalid API Key");
|
||||||
|
}
|
||||||
|
catch (RequestLimitReachedException)
|
||||||
|
{
|
||||||
|
_logger.Warn("Request limit reached");
|
||||||
|
}
|
||||||
|
catch (CloudFlareCaptchaException ex)
|
||||||
|
{
|
||||||
|
if (ex.IsExpired)
|
||||||
|
{
|
||||||
|
return new ValidationFailure("CaptchaToken", "CloudFlare CAPTCHA token expired, please Refresh.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new ValidationFailure("CaptchaToken", "Site protected by CloudFlare CAPTCHA. Valid CAPTCHA token required.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (UnsupportedFeedException ex)
|
||||||
|
{
|
||||||
|
_logger.Warn(ex, "List feed is not supported");
|
||||||
|
|
||||||
|
return new ValidationFailure(string.Empty, "List feed is not supported: " + ex.Message);
|
||||||
|
}
|
||||||
|
catch (NetImportException ex)
|
||||||
|
{
|
||||||
|
_logger.Warn(ex, "Unable to connect to list");
|
||||||
|
|
||||||
|
return new ValidationFailure(string.Empty, "Unable to connect to indexer. " + ex.Message);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Warn(ex, "Unable to connect to list");
|
||||||
|
|
||||||
|
return new ValidationFailure(string.Empty, "Unable to connect to list, check the log for more details");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace NzbDrone.Core.NetImport.RSSImport
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var config = (RSSImportSettings)new RSSImportSettings();
|
var config = (RSSImportSettings)new RSSImportSettings();
|
||||||
config.Link = "https://rss.imdb.com/list/YOURLISTID";
|
config.Link = "http://rss.imdb.com/list/YOURLISTID";
|
||||||
|
|
||||||
yield return new NetImportDefinition
|
yield return new NetImportDefinition
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
var ThingyAddCollectionView = require('../../ThingyAddCollectionView');
|
|
||||||
var ThingyHeaderGroupView = require('../../ThingyHeaderGroupView');
|
|
||||||
var AddItemView = require('./IndexerAddItemView');
|
|
||||||
|
|
||||||
module.exports = ThingyAddCollectionView.extend({
|
|
||||||
itemView : ThingyHeaderGroupView.extend({ itemView : AddItemView }),
|
|
||||||
itemViewContainer : '.add-indexer .items',
|
|
||||||
template : 'Settings/Indexers/Add/IndexerAddCollectionViewTemplate'
|
|
||||||
});
|
|
|
@ -1,18 +0,0 @@
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
||||||
<h3>Add Indexer</h3>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="alert alert-info">
|
|
||||||
Radarr supports any indexer that uses the Newznab standard, as well as other indexers listed below.<br/>
|
|
||||||
For more information on the individual indexers, click on the info buttons.
|
|
||||||
</div>
|
|
||||||
<div class="add-indexer add-thingies">
|
|
||||||
<ul class="items"></ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn" data-dismiss="modal">Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,52 +0,0 @@
|
||||||
var _ = require('underscore');
|
|
||||||
var $ = require('jquery');
|
|
||||||
var AppLayout = require('../../../AppLayout');
|
|
||||||
var Marionette = require('marionette');
|
|
||||||
var EditView = require('../Edit/IndexerEditView');
|
|
||||||
|
|
||||||
module.exports = Marionette.ItemView.extend({
|
|
||||||
template : 'Settings/Indexers/Add/IndexerAddItemViewTemplate',
|
|
||||||
tagName : 'li',
|
|
||||||
className : 'add-thingy-item',
|
|
||||||
|
|
||||||
events : {
|
|
||||||
'click .x-preset' : '_addPreset',
|
|
||||||
'click' : '_add'
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize : function(options) {
|
|
||||||
this.targetCollection = options.targetCollection;
|
|
||||||
},
|
|
||||||
|
|
||||||
_addPreset : function(e) {
|
|
||||||
var presetName = $(e.target).closest('.x-preset').attr('data-id');
|
|
||||||
var presetData = _.where(this.model.get('presets'), { name : presetName })[0];
|
|
||||||
|
|
||||||
this.model.set(presetData);
|
|
||||||
|
|
||||||
this._openEdit();
|
|
||||||
},
|
|
||||||
|
|
||||||
_add : function(e) {
|
|
||||||
if ($(e.target).closest('.btn,.btn-group').length !== 0 && $(e.target).closest('.x-custom').length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._openEdit();
|
|
||||||
},
|
|
||||||
|
|
||||||
_openEdit : function() {
|
|
||||||
this.model.set({
|
|
||||||
id : undefined,
|
|
||||||
enableRss : this.model.get('supportsRss'),
|
|
||||||
enableSearch : this.model.get('supportsSearch')
|
|
||||||
});
|
|
||||||
|
|
||||||
var editView = new EditView({
|
|
||||||
model : this.model,
|
|
||||||
targetCollection : this.targetCollection
|
|
||||||
});
|
|
||||||
|
|
||||||
AppLayout.modalRegion.show(editView);
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,30 +0,0 @@
|
||||||
<div class="add-thingy">
|
|
||||||
<div>
|
|
||||||
{{implementationName}}
|
|
||||||
</div>
|
|
||||||
<div class="pull-right">
|
|
||||||
{{#if_gt presets.length compare=0}}
|
|
||||||
<button class="btn btn-xs btn-default x-custom">
|
|
||||||
Custom
|
|
||||||
</button>
|
|
||||||
<div class="btn-group">
|
|
||||||
<button class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
|
|
||||||
Presets
|
|
||||||
<span class="caret"></span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
{{#each presets}}
|
|
||||||
<li class="x-preset" data-id="{{name}}">
|
|
||||||
<a>{{name}}</a>
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{{/if_gt}}
|
|
||||||
{{#if infoLink}}
|
|
||||||
<a class="btn btn-xs btn-default x-info" href="{{infoLink}}">
|
|
||||||
<i class="icon-sonarr-form-info"/>
|
|
||||||
</a>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
var ThingyAddCollectionView = require('../../ThingyAddCollectionView');
|
||||||
|
var ThingyHeaderGroupView = require('../../ThingyHeaderGroupView');
|
||||||
|
var AddItemView = require('./NetImportAddItemView');
|
||||||
|
|
||||||
|
module.exports = ThingyAddCollectionView.extend({
|
||||||
|
itemView : ThingyHeaderGroupView.extend({ itemView : AddItemView }),
|
||||||
|
itemViewContainer : '.add-indexer .items',
|
||||||
|
template : 'Settings/NetImport/Add/NetImportAddCollectionViewTemplate'
|
||||||
|
});
|
|
@ -0,0 +1,18 @@
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h3>Add List</h3>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-info">
|
||||||
|
Radarr supports any RSS movie lists as well as the one stated below.<br/>
|
||||||
|
For more information on the individual lists, click on the info buttons.
|
||||||
|
</div>
|
||||||
|
<div class="add-indexer add-thingies">
|
||||||
|
<ul class="items"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn" data-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
52
src/UI/Settings/NetImport/Add/NetImportAddItemView.js
Normal file
52
src/UI/Settings/NetImport/Add/NetImportAddItemView.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
var _ = require('underscore');
|
||||||
|
var $ = require('jquery');
|
||||||
|
var AppLayout = require('../../../AppLayout');
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
var EditView = require('../Edit/NetImportEditView');
|
||||||
|
|
||||||
|
module.exports = Marionette.ItemView.extend({
|
||||||
|
template : 'Settings/NetImport/Add/NetImportAddItemViewTemplate',
|
||||||
|
tagName : 'li',
|
||||||
|
className : 'add-thingy-item',
|
||||||
|
|
||||||
|
events : {
|
||||||
|
'click .x-preset' : '_addPreset',
|
||||||
|
'click' : '_add'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize : function(options) {
|
||||||
|
this.targetCollection = options.targetCollection;
|
||||||
|
},
|
||||||
|
|
||||||
|
_addPreset : function(e) {
|
||||||
|
var presetName = $(e.target).closest('.x-preset').attr('data-id');
|
||||||
|
var presetData = _.where(this.model.get('presets'), { name : presetName })[0];
|
||||||
|
|
||||||
|
this.model.set(presetData);
|
||||||
|
|
||||||
|
this._openEdit();
|
||||||
|
},
|
||||||
|
|
||||||
|
_add : function(e) {
|
||||||
|
if ($(e.target).closest('.btn,.btn-group').length !== 0 && $(e.target).closest('.x-custom').length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._openEdit();
|
||||||
|
},
|
||||||
|
|
||||||
|
_openEdit : function() {
|
||||||
|
this.model.set({
|
||||||
|
id : undefined,
|
||||||
|
enableRss : this.model.get('supportsRss'),
|
||||||
|
enableSearch : this.model.get('supportsSearch')
|
||||||
|
});
|
||||||
|
|
||||||
|
var editView = new EditView({
|
||||||
|
model : this.model,
|
||||||
|
targetCollection : this.targetCollection
|
||||||
|
});
|
||||||
|
|
||||||
|
AppLayout.modalRegion.show(editView);
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,30 @@
|
||||||
|
<div class="add-thingy">
|
||||||
|
<div>
|
||||||
|
{{implementationName}}
|
||||||
|
</div>
|
||||||
|
<div class="pull-right">
|
||||||
|
{{#if_gt presets.length compare=0}}
|
||||||
|
<button class="btn btn-xs btn-default x-custom">
|
||||||
|
Custom
|
||||||
|
</button>
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
|
||||||
|
Presets
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
{{#each presets}}
|
||||||
|
<li class="x-preset" data-id="{{name}}">
|
||||||
|
<a>{{name}}</a>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{/if_gt}}
|
||||||
|
{{#if infoLink}}
|
||||||
|
<a class="btn btn-xs btn-default x-info" href="{{infoLink}}">
|
||||||
|
<i class="icon-sonarr-form-info"/>
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -2,7 +2,7 @@ var _ = require('underscore');
|
||||||
var AppLayout = require('../../../AppLayout');
|
var AppLayout = require('../../../AppLayout');
|
||||||
var Backbone = require('backbone');
|
var Backbone = require('backbone');
|
||||||
var SchemaCollection = require('../NetImportCollection');
|
var SchemaCollection = require('../NetImportCollection');
|
||||||
var AddCollectionView = require('./IndexerAddCollectionView');
|
var AddCollectionView = require('./NetImportAddCollectionView');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
open : function(collection) {
|
open : function(collection) {
|
|
@ -1,122 +0,0 @@
|
||||||
var _ = require('underscore');
|
|
||||||
var $ = require('jquery');
|
|
||||||
var vent = require('vent');
|
|
||||||
var Marionette = require('marionette');
|
|
||||||
var DeleteView = require('../Delete/IndexerDeleteView');
|
|
||||||
var AsModelBoundView = require('../../../Mixins/AsModelBoundView');
|
|
||||||
var AsValidatedView = require('../../../Mixins/AsValidatedView');
|
|
||||||
var AsEditModalView = require('../../../Mixins/AsEditModalView');
|
|
||||||
require('../../../Form/FormBuilder');
|
|
||||||
require('../../../Mixins/AutoComplete');
|
|
||||||
require('bootstrap');
|
|
||||||
|
|
||||||
var view = Marionette.ItemView.extend({
|
|
||||||
template : 'Settings/Indexers/Edit/IndexerEditViewTemplate',
|
|
||||||
|
|
||||||
events : {
|
|
||||||
'click .x-back' : '_back',
|
|
||||||
'click .x-captcha-refresh' : '_onRefreshCaptcha'
|
|
||||||
},
|
|
||||||
|
|
||||||
_deleteView : DeleteView,
|
|
||||||
|
|
||||||
initialize : function(options) {
|
|
||||||
this.targetCollection = options.targetCollection;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onAfterSave : function() {
|
|
||||||
this.targetCollection.add(this.model, { merge : true });
|
|
||||||
vent.trigger(vent.Commands.CloseModalCommand);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onAfterSaveAndAdd : function() {
|
|
||||||
this.targetCollection.add(this.model, { merge : true });
|
|
||||||
|
|
||||||
require('../Add/IndexerSchemaModal').open(this.targetCollection);
|
|
||||||
},
|
|
||||||
|
|
||||||
_back : function() {
|
|
||||||
if (this.model.isNew()) {
|
|
||||||
this.model.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
require('../Add/IndexerSchemaModal').open(this.targetCollection);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onRefreshCaptcha : function(event) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var target = $(event.target).parents('.input-group');
|
|
||||||
|
|
||||||
this.ui.indicator.show();
|
|
||||||
|
|
||||||
this.model.requestAction("checkCaptcha")
|
|
||||||
.then(function(result) {
|
|
||||||
if (!result.captchaRequest) {
|
|
||||||
self.model.setFieldValue('CaptchaToken', '');
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self._showCaptcha(target, result.captchaRequest);
|
|
||||||
})
|
|
||||||
.always(function() {
|
|
||||||
self.ui.indicator.hide();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_showCaptcha : function(target, captchaRequest) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var widget = $('<div class="g-recaptcha"></div>').insertAfter(target);
|
|
||||||
|
|
||||||
return this._loadRecaptchaWidget(widget[0], captchaRequest.siteKey, captchaRequest.secretToken)
|
|
||||||
.then(function(captchaResponse) {
|
|
||||||
target.parents('.form-group').removeAllErrors();
|
|
||||||
widget.remove();
|
|
||||||
|
|
||||||
var queryParams = {
|
|
||||||
responseUrl : captchaRequest.responseUrl,
|
|
||||||
ray : captchaRequest.ray,
|
|
||||||
captchaResponse: captchaResponse
|
|
||||||
};
|
|
||||||
|
|
||||||
return self.model.requestAction("getCaptchaCookie", queryParams);
|
|
||||||
})
|
|
||||||
.then(function(response) {
|
|
||||||
self.model.setFieldValue('CaptchaToken', response.captchaToken);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_loadRecaptchaWidget : function(widget, sitekey, stoken) {
|
|
||||||
var promise = $.Deferred();
|
|
||||||
|
|
||||||
var renderWidget = function() {
|
|
||||||
window.grecaptcha.render(widget, {
|
|
||||||
'sitekey' : sitekey,
|
|
||||||
'stoken' : stoken,
|
|
||||||
'callback' : promise.resolve
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (window.grecaptcha) {
|
|
||||||
renderWidget();
|
|
||||||
} else {
|
|
||||||
window.grecaptchaLoadCallback = function() {
|
|
||||||
delete window.grecaptchaLoadCallback;
|
|
||||||
renderWidget();
|
|
||||||
};
|
|
||||||
|
|
||||||
$.getScript('https://www.google.com/recaptcha/api.js?onload=grecaptchaLoadCallback&render=explicit')
|
|
||||||
.fail(function() { promise.reject(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
AsModelBoundView.call(view);
|
|
||||||
AsValidatedView.call(view);
|
|
||||||
AsEditModalView.call(view);
|
|
||||||
|
|
||||||
module.exports = view;
|
|
|
@ -1,92 +0,0 @@
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" aria-hidden="true" data-dismiss="modal">×</button>
|
|
||||||
{{#if id}}
|
|
||||||
<h3>Edit - {{implementationName}}</h3>
|
|
||||||
{{else}}
|
|
||||||
<h3>Add - {{implementationName}}</h3>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
<div class="modal-body indexer-modal">
|
|
||||||
<div class="form-horizontal">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">Name</label>
|
|
||||||
|
|
||||||
<div class="col-sm-5">
|
|
||||||
<input type="text" name="name" class="form-control"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">Enable RSS Sync</label>
|
|
||||||
|
|
||||||
<div class="col-sm-5">
|
|
||||||
<div class="input-group">
|
|
||||||
<label class="checkbox toggle well">
|
|
||||||
<input type="checkbox" name="enableRss" {{#unless supportsRss}}disabled="disabled"{{/unless}}/>
|
|
||||||
<p>
|
|
||||||
<span>Yes</span>
|
|
||||||
<span>No</span>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="btn btn-primary slide-button"/>
|
|
||||||
</label>
|
|
||||||
{{#unless supportsRss}}
|
|
||||||
<span class="help-inline-checkbox">
|
|
||||||
<i class="icon-sonarr-form-warning" title="" data-original-title="RSS is not supported with this indexer"></i>
|
|
||||||
</span>
|
|
||||||
{{/unless}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">Enable Search</label>
|
|
||||||
|
|
||||||
<div class="col-sm-5">
|
|
||||||
<div class="input-group">
|
|
||||||
<label class="checkbox toggle well">
|
|
||||||
|
|
||||||
<input type="checkbox" name="enableSearch" {{#unless supportsSearch}}disabled="disabled"{{/unless}}/>
|
|
||||||
<p>
|
|
||||||
<span>Yes</span>
|
|
||||||
<span>No</span>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="btn btn-primary slide-button"/>
|
|
||||||
</label>
|
|
||||||
{{#unless supportsSearch}}
|
|
||||||
<span class="help-inline-checkbox">
|
|
||||||
<i class="icon-sonarr-form-warning" title="" data-original-title="Search is not supported with this indexer"></i>
|
|
||||||
</span>
|
|
||||||
{{/unless}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{formBuilder}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
{{#if id}}
|
|
||||||
<button class="btn btn-danger pull-left x-delete">Delete</button>
|
|
||||||
{{else}}
|
|
||||||
<button class="btn pull-left x-back">Back</button>
|
|
||||||
{{/if}}
|
|
||||||
<span class="indicator x-indicator"><i class="icon-sonarr-spinner fa-spin"></i></span>
|
|
||||||
<button class="btn x-test">test <i class="x-test-icon icon-sonarr-test"/></button>
|
|
||||||
<button class="btn" data-dismiss="modal">Cancel</button>
|
|
||||||
|
|
||||||
<div class="btn-group">
|
|
||||||
<button class="btn btn-primary x-save">Save</button>
|
|
||||||
<button class="btn btn-icon-only btn-primary dropdown-toggle" data-toggle="dropdown">
|
|
||||||
<span class="caret"></span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li class="save-and-add x-save-and-add">
|
|
||||||
save and add
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
122
src/UI/Settings/NetImport/Edit/NetImportEditView.js
Normal file
122
src/UI/Settings/NetImport/Edit/NetImportEditView.js
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
var _ = require('underscore');
|
||||||
|
var $ = require('jquery');
|
||||||
|
var vent = require('vent');
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
var DeleteView = require('../Delete/IndexerDeleteView');
|
||||||
|
var AsModelBoundView = require('../../../Mixins/AsModelBoundView');
|
||||||
|
var AsValidatedView = require('../../../Mixins/AsValidatedView');
|
||||||
|
var AsEditModalView = require('../../../Mixins/AsEditModalView');
|
||||||
|
require('../../../Form/FormBuilder');
|
||||||
|
require('../../../Mixins/AutoComplete');
|
||||||
|
require('bootstrap');
|
||||||
|
|
||||||
|
var view = Marionette.ItemView.extend({
|
||||||
|
template : 'Settings/NetImport/Edit/NetImportEditViewTemplate',
|
||||||
|
|
||||||
|
events : {
|
||||||
|
'click .x-back' : '_back',
|
||||||
|
'click .x-captcha-refresh' : '_onRefreshCaptcha'
|
||||||
|
},
|
||||||
|
|
||||||
|
_deleteView : DeleteView,
|
||||||
|
|
||||||
|
initialize : function(options) {
|
||||||
|
this.targetCollection = options.targetCollection;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onAfterSave : function() {
|
||||||
|
this.targetCollection.add(this.model, { merge : true });
|
||||||
|
vent.trigger(vent.Commands.CloseModalCommand);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onAfterSaveAndAdd : function() {
|
||||||
|
this.targetCollection.add(this.model, { merge : true });
|
||||||
|
|
||||||
|
require('../Add/NetImportSchemaModal').open(this.targetCollection);
|
||||||
|
},
|
||||||
|
|
||||||
|
_back : function() {
|
||||||
|
if (this.model.isNew()) {
|
||||||
|
this.model.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
require('../Add/NetImportSchemaModal').open(this.targetCollection);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onRefreshCaptcha : function(event) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var target = $(event.target).parents('.input-group');
|
||||||
|
|
||||||
|
this.ui.indicator.show();
|
||||||
|
|
||||||
|
this.model.requestAction("checkCaptcha")
|
||||||
|
.then(function(result) {
|
||||||
|
if (!result.captchaRequest) {
|
||||||
|
self.model.setFieldValue('CaptchaToken', '');
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self._showCaptcha(target, result.captchaRequest);
|
||||||
|
})
|
||||||
|
.always(function() {
|
||||||
|
self.ui.indicator.hide();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_showCaptcha : function(target, captchaRequest) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var widget = $('<div class="g-recaptcha"></div>').insertAfter(target);
|
||||||
|
|
||||||
|
return this._loadRecaptchaWidget(widget[0], captchaRequest.siteKey, captchaRequest.secretToken)
|
||||||
|
.then(function(captchaResponse) {
|
||||||
|
target.parents('.form-group').removeAllErrors();
|
||||||
|
widget.remove();
|
||||||
|
|
||||||
|
var queryParams = {
|
||||||
|
responseUrl : captchaRequest.responseUrl,
|
||||||
|
ray : captchaRequest.ray,
|
||||||
|
captchaResponse: captchaResponse
|
||||||
|
};
|
||||||
|
|
||||||
|
return self.model.requestAction("getCaptchaCookie", queryParams);
|
||||||
|
})
|
||||||
|
.then(function(response) {
|
||||||
|
self.model.setFieldValue('CaptchaToken', response.captchaToken);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_loadRecaptchaWidget : function(widget, sitekey, stoken) {
|
||||||
|
var promise = $.Deferred();
|
||||||
|
|
||||||
|
var renderWidget = function() {
|
||||||
|
window.grecaptcha.render(widget, {
|
||||||
|
'sitekey' : sitekey,
|
||||||
|
'stoken' : stoken,
|
||||||
|
'callback' : promise.resolve
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (window.grecaptcha) {
|
||||||
|
renderWidget();
|
||||||
|
} else {
|
||||||
|
window.grecaptchaLoadCallback = function() {
|
||||||
|
delete window.grecaptchaLoadCallback;
|
||||||
|
renderWidget();
|
||||||
|
};
|
||||||
|
|
||||||
|
$.getScript('https://www.google.com/recaptcha/api.js?onload=grecaptchaLoadCallback&render=explicit')
|
||||||
|
.fail(function() { promise.reject(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AsModelBoundView.call(view);
|
||||||
|
AsValidatedView.call(view);
|
||||||
|
AsEditModalView.call(view);
|
||||||
|
|
||||||
|
module.exports = view;
|
67
src/UI/Settings/NetImport/Edit/NetImportEditViewTemplate.hbs
Normal file
67
src/UI/Settings/NetImport/Edit/NetImportEditViewTemplate.hbs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" aria-hidden="true" data-dismiss="modal">×</button>
|
||||||
|
{{#if id}}
|
||||||
|
<h3>Edit - {{implementationName}}</h3>
|
||||||
|
{{else}}
|
||||||
|
<h3>Add - {{implementationName}}</h3>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="modal-body indexer-modal">
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Name</label>
|
||||||
|
|
||||||
|
<div class="col-sm-5">
|
||||||
|
<input type="text" name="name" class="form-control"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Enable Automatic Sync</label>
|
||||||
|
|
||||||
|
<div class="col-sm-5">
|
||||||
|
<div class="input-group">
|
||||||
|
<label class="checkbox toggle well">
|
||||||
|
<input type="checkbox" name="enableAutomatic" />
|
||||||
|
<p>
|
||||||
|
<span>Yes</span>
|
||||||
|
<span>No</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="btn btn-primary slide-button"/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<span class="help-inline-checkbox">
|
||||||
|
<i class="icon-sonarr-form-warning" title="" data-original-title="New movies found by this list are automatically added to your collection."></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{formBuilder}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
{{#if id}}
|
||||||
|
<button class="btn btn-danger pull-left x-delete">Delete</button>
|
||||||
|
{{else}}
|
||||||
|
<button class="btn pull-left x-back">Back</button>
|
||||||
|
{{/if}}
|
||||||
|
<span class="indicator x-indicator"><i class="icon-sonarr-spinner fa-spin"></i></span>
|
||||||
|
<button class="btn x-test">test <i class="x-test-icon icon-sonarr-test"/></button>
|
||||||
|
<button class="btn" data-dismiss="modal">Cancel</button>
|
||||||
|
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-primary x-save">Save</button>
|
||||||
|
<button class="btn btn-icon-only btn-primary dropdown-toggle" data-toggle="dropdown">
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li class="save-and-add x-save-and-add">
|
||||||
|
save and add
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,6 +1,6 @@
|
||||||
var Marionette = require('marionette');
|
var Marionette = require('marionette');
|
||||||
var ItemView = require('./NetImportItemView');
|
var ItemView = require('./NetImportItemView');
|
||||||
var SchemaModal = require('./Add/IndexerSchemaModal');
|
var SchemaModal = require('./Add/NetImportSchemaModal');
|
||||||
|
|
||||||
module.exports = Marionette.CompositeView.extend({
|
module.exports = Marionette.CompositeView.extend({
|
||||||
itemView : ItemView,
|
itemView : ItemView,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
var AppLayout = require('../../AppLayout');
|
var AppLayout = require('../../AppLayout');
|
||||||
var Marionette = require('marionette');
|
var Marionette = require('marionette');
|
||||||
var EditView = require('./Edit/IndexerEditView');
|
var EditView = require('./Edit/NetImportEditView');
|
||||||
|
|
||||||
module.exports = Marionette.ItemView.extend({
|
module.exports = Marionette.ItemView.extend({
|
||||||
template : 'Settings/NetImport/NetImportItemViewTemplate',
|
template : 'Settings/NetImport/NetImportItemViewTemplate',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
var Marionette = require('marionette');
|
var Marionette = require('marionette');
|
||||||
var NetImportCollection = require('./NetImportCollection');
|
var NetImportCollection = require('./NetImportCollection');
|
||||||
var CollectionView = require('./NetImportCollectionView');
|
var CollectionView = require('./NetImportCollectionView');
|
||||||
var OptionsView = require('./Options/IndexerOptionsView');
|
var OptionsView = require('./Options/NetImportOptionsView');
|
||||||
|
|
||||||
module.exports = Marionette.Layout.extend({
|
module.exports = Marionette.Layout.extend({
|
||||||
template : 'Settings/NetImport/NetImportLayoutTemplate',
|
template : 'Settings/NetImport/NetImportLayoutTemplate',
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
<fieldset>
|
|
||||||
<legend>Options</legend>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">Minimum Age</label>
|
|
||||||
|
|
||||||
<div class="col-sm-1 col-sm-push-2 help-inline">
|
|
||||||
<i class="icon-sonarr-form-info" title="Usenet only: Minimum age in minutes of NZBs before they are grabbed. Use this to give new releases time to propagate to your usenet provider."/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-2 col-sm-pull-1">
|
|
||||||
<input type="number" min="0" name="minimumAge" class="form-control"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">Retention</label>
|
|
||||||
|
|
||||||
<div class="col-sm-1 col-sm-push-2 help-inline">
|
|
||||||
<i class="icon-sonarr-form-info" title="Usenet only: Set to zero to set to unlimited"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-2 col-sm-pull-1">
|
|
||||||
<input type="number" min="0" name="retention" class="form-control"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group advanced-setting">
|
|
||||||
<label class="col-sm-3 control-label">RSS Sync Interval</label>
|
|
||||||
|
|
||||||
<div class="col-sm-1 col-sm-push-2 help-inline">
|
|
||||||
<i class="icon-sonarr-form-warning" title="This will apply to all indexers, please follow the rules set forth by them"/>
|
|
||||||
<i class="icon-sonarr-form-info" title="Interval in minutes. Set to zero to disable (this will stop all automatic release grabbing)"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-2 col-sm-pull-1">
|
|
||||||
<input type="number" name="rssSyncInterval" class="form-control" min="0" max="120"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
|
@ -3,10 +3,10 @@ var AsModelBoundView = require('../../../Mixins/AsModelBoundView');
|
||||||
var AsValidatedView = require('../../../Mixins/AsValidatedView');
|
var AsValidatedView = require('../../../Mixins/AsValidatedView');
|
||||||
|
|
||||||
var view = Marionette.ItemView.extend({
|
var view = Marionette.ItemView.extend({
|
||||||
template : 'Settings/Indexers/Options/IndexerOptionsViewTemplate'
|
template : 'Settings/NetImport/Options/NetImportOptionsViewTemplate'
|
||||||
});
|
});
|
||||||
|
|
||||||
AsModelBoundView.call(view);
|
AsModelBoundView.call(view);
|
||||||
AsValidatedView.call(view);
|
AsValidatedView.call(view);
|
||||||
|
|
||||||
module.exports = view;
|
module.exports = view;
|
|
@ -0,0 +1,16 @@
|
||||||
|
<fieldset>
|
||||||
|
<legend>Options</legend>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">List Update Interval</label>
|
||||||
|
|
||||||
|
<div class="col-sm-1 col-sm-push-2 help-inline">
|
||||||
|
<i class="icon-sonarr-form-warning" title="This will apply to all lists, please follow the rules set forth by them."/>
|
||||||
|
<i class="icon-sonarr-form-info" title="Interval in minutes."/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-2 col-sm-pull-1">
|
||||||
|
<input type="number" name="rssSyncInterval" class="form-control" min="0" max="1440"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
Loading…
Add table
Add a link
Reference in a new issue