1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-23 22:25:14 -04:00
Indexes are created with the same uniqueness when copying a table

New: Non-English episode support
New: Renamed Quality Profiles to Profiles and made them more powerful
New: Configurable wait time before grabbing a release to wait for a better quality
This commit is contained in:
Mark McDowall
2014-06-08 01:22:55 -07:00
parent b72678a9ad
commit 74a38415cf
182 changed files with 2493 additions and 2433 deletions
@@ -25,7 +25,7 @@ define(
},
initialize: function (options) {
this.qualityProfileCollection = options.qualityProfiles;
this.profileCollection = options.profiles;
this.filesize = fileSize;
},
@@ -1,23 +0,0 @@
'use strict';
define(
[
'handlebars',
'underscore'
], function (Handlebars, _) {
Handlebars.registerHelper('allowedLabeler', function () {
var ret = '';
var cutoff = this.cutoff;
_.each(this.items, function (item) {
if (item.allowed) {
if (item.quality.id === cutoff.id) {
ret += '<li><span class="label label-info" title="Cutoff">' + item.quality.name + '</span></li>';
}
else {
ret += '<li><span class="label label-default">' + item.quality.name + '</span></li>';
}
}
});
return new Handlebars.SafeString(ret);
});
});
@@ -1,24 +0,0 @@
'use strict';
define(
[
'vent',
'marionette'
], function (vent, Marionette) {
return Marionette.ItemView.extend({
template: 'Settings/Quality/Profile/DeleteQualityProfileViewTemplate',
events: {
'click .x-confirm-delete': '_removeProfile'
},
_removeProfile: function () {
this.model.destroy({
wait: true
}).done(function () {
vent.trigger(vent.Commands.CloseModalCommand);
});
}
});
});
@@ -1,15 +0,0 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>Delete: {{name}}</h3>
</div>
<div class="modal-body">
<p>Are you sure you want to delete '{{name}}'?</p>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal">cancel</button>
<button class="btn btn-danger x-confirm-delete">delete</button>
</div>
</div>
</div>
@@ -1,9 +0,0 @@
'use strict';
define(
[
'marionette'
], function (Marionette) {
return Marionette.ItemView.extend({
template : 'Settings/Quality/Profile/Edit/EditQualityProfileItemViewTemplate'
});
});
@@ -1,3 +0,0 @@
<i class="select-handle pull-left x-select" />
<span class="quality-label">{{quality.name}}</span>
<i class="drag-handle pull-right icon-reorder advanced-setting x-drag-handle" />
@@ -1,150 +0,0 @@
'use strict';
define(
[
'underscore',
'vent',
'AppLayout',
'marionette',
'backbone',
'Settings/Quality/Profile/Edit/EditQualityProfileItemView',
'Settings/Quality/Profile/Edit/QualitySortableCollectionView',
'Settings/Quality/Profile/Edit/EditQualityProfileView',
'Settings/Quality/Profile/DeleteQualityProfileView',
'Series/SeriesCollection',
'Config'
], function (_,
vent,
AppLayout,
Marionette,
Backbone,
EditQualityProfileItemView,
QualitySortableCollectionView,
EditQualityProfileView,
DeleteView,
SeriesCollection,
Config) {
return Marionette.Layout.extend({
template: 'Settings/Quality/Profile/Edit/EditQualityProfileLayoutTemplate',
regions: {
fields : '#x-fields',
qualities: '#x-qualities'
},
ui: {
deleteButton: '.x-delete'
},
events: {
'click .x-save' : '_saveQualityProfile',
'click .x-cancel' : '_cancelQualityProfile',
'click .x-delete' : '_delete'
},
initialize: function (options) {
this.profileCollection = options.profileCollection;
this.itemsCollection = new Backbone.Collection(_.toArray(this.model.get('items')).reverse());
this.listenTo(SeriesCollection, 'all', this._updateDisableStatus);
},
onRender: function () {
this._updateDisableStatus();
},
onShow: function () {
this.fieldsView = new EditQualityProfileView({ model: this.model });
this._showFieldsView();
this.sortableListView = new QualitySortableCollectionView({
selectable : true,
selectMultiple : true,
clickToSelect : true,
clickToToggle : true,
sortable : Config.getValueBoolean(Config.Keys.AdvancedSettings, false),
sortableOptions : {
handle: '.x-drag-handle'
},
collection: this.itemsCollection,
model : this.model
});
this.sortableListView.setSelectedModels(this.itemsCollection.filter(function(item) { return item.get('allowed') === true; }));
this.qualities.show(this.sortableListView);
this.listenTo(this.sortableListView, 'selectionChanged', this._selectionChanged);
this.listenTo(this.sortableListView, 'sortStop', this._updateModel);
},
_selectionChanged: function(newSelectedModels, oldSelectedModels) {
var addedModels = _.difference(newSelectedModels, oldSelectedModels);
var removeModels = _.difference(oldSelectedModels, newSelectedModels);
_.each(removeModels, function(item) { item.set('allowed', false); });
_.each(addedModels, function(item) { item.set('allowed', true); });
this._updateModel();
},
_updateModel: function() {
this.model.set('items', this.itemsCollection.toJSON().reverse());
this._showFieldsView();
},
_saveQualityProfile: function () {
var self = this;
var cutoff = this.fieldsView.getCutoff();
this.model.set('cutoff', cutoff);
var promise = this.model.save();
if (promise) {
promise.done(function () {
self.profileCollection.add(self.model, { merge: true });
vent.trigger(vent.Commands.CloseModalCommand);
});
}
},
_cancelQualityProfile: function () {
if (!this.model.has('id')) {
vent.trigger(vent.Commands.CloseModalCommand);
return;
}
var promise = this.model.fetch();
if (promise) {
promise.done(function () {
vent.trigger(vent.Commands.CloseModalCommand);
});
}
},
_showFieldsView: function () {
this.fields.show(this.fieldsView);
},
_delete: function () {
var view = new DeleteView({ model: this.model });
AppLayout.modalRegion.show(view);
},
_updateDisableStatus: function () {
if (this._isQualityInUse()) {
this.ui.deleteButton.addClass('disabled');
this.ui.deleteButton.attr('title', 'Can\'t delete quality profiles attached to a series.');
}
else {
this.ui.deleteButton.removeClass('disabled');
}
},
_isQualityInUse: function () {
return SeriesCollection.where({'qualityProfileId': this.model.id}).length !== 0;
}
});
});
@@ -1,37 +0,0 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close x-cancel" aria-hidden="true">&times;</button>
{{#if id}}
<h3>Edit</h3>
{{else}}
<h3>Add</h3>
{{/if}}
</div>
<div class="modal-body">
<div class="form-horizontal">
<div id="x-fields"></div>
<div class="form-group">
<label class="col-sm-3 control-label">Qualities</label>
<div class="col-sm-5">
<div class="controls qualities-controls">
<span id="x-qualities"></span>
</div>
</div>
<div class="col-sm-1 help-inline">
<i class="icon-nd-form-info" title="Qualities higher in the list are more preferred. Only checked qualities will be wanted."/>
</div>
</div>
</div>
</div>
<div class="modal-footer">
{{#if id}}
<button class="btn btn-danger pull-left x-delete">delete</button>
{{/if}}
<button class="btn x-cancel">cancel</button>
<button class="btn btn-primary x-save">save</button>
</div>
</div>
</div>
@@ -1,26 +0,0 @@
'use strict';
define(
[
'underscore',
'marionette',
'Mixins/AsModelBoundView',
'Mixins/AsValidatedView'
], function (_, Marionette, AsModelBoundView, AsValidatedView) {
var view = Marionette.ItemView.extend({
template: 'Settings/Quality/Profile/Edit/EditQualityProfileViewTemplate',
ui: {
cutoff : '.x-cutoff'
},
getCutoff: function () {
var self = this;
return _.findWhere(_.pluck(this.model.get('items'), 'quality'), { id: parseInt(self.ui.cutoff.val(), 10)});
}
});
AsValidatedView.call(view);
return AsModelBoundView.call(view);
});
@@ -1,23 +0,0 @@
<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">Cutoff</label>
<div class="col-sm-5">
<select class="form-control x-cutoff" name="cutoff.id" validation-name="cutoff">
{{#eachReverse items}}
{{#if allowed}}
<option value="{{quality.id}}">{{quality.name}}</option>
{{/if}}
{{/eachReverse}}
</select>
</div>
<div class="col-sm-1 help-inline">
<i class="icon-nd-form-info" title="Once this quality is reached NzbDrone will no longer download episodes"/>
</div>
</div>
@@ -1,22 +0,0 @@
'use strict';
define(
[
'backbone.collectionview',
'Settings/Quality/Profile/Edit/EditQualityProfileItemView'
], function (BackboneSortableCollectionView, EditQualityProfileItemView) {
return BackboneSortableCollectionView.extend({
className: 'qualities',
modelView: EditQualityProfileItemView,
attributes: {
'validation-name': 'items'
},
events: {
'click li, td' : '_listItem_onMousedown',
'dblclick li, td' : '_listItem_onDoubleClick',
'keydown' : '_onKeydown'
}
});
});
@@ -1,16 +0,0 @@
<fieldset>
<legend>Quality Profiles</legend>
<div class="row">
<div class="col-md-12">
<ul class="quality-profiles thingies">
<li>
<div class="quality-profile-item thingy add-card x-add-card">
<span class="center well">
<i class="icon-plus" title="Add Profile"/>
</span>
</div>
</li>
</ul>
</div>
</div>
</fieldset>
@@ -1,44 +0,0 @@
'use strict';
define(['AppLayout',
'marionette',
'Settings/Quality/Profile/QualityProfileView',
'Settings/Quality/Profile/Edit/EditQualityProfileLayout',
'Settings/Quality/Profile/QualityProfileSchemaCollection',
'underscore'
], function (AppLayout, Marionette, QualityProfileView, EditProfileView, ProfileCollection, _) {
return Marionette.CompositeView.extend({
itemView : QualityProfileView,
itemViewContainer: '.quality-profiles',
template : 'Settings/Quality/Profile/QualityProfileCollectionTemplate',
ui: {
'addCard': '.x-add-card'
},
events: {
'click .x-add-card': '_addProfile'
},
appendHtml: function(collectionView, itemView, index){
collectionView.ui.addCard.parent('li').before(itemView.el);
},
_addProfile: function () {
var self = this;
var schemaCollection = new ProfileCollection();
schemaCollection.fetch({
success: function (collection) {
var model = _.first(collection.models);
model.set('id', undefined);
model.set('name', '');
model.collection = self.collection;
var view = new EditProfileView({ model: model, profileCollection: self.collection});
AppLayout.modalRegion.show(view);
}
});
}
});
});
@@ -1,13 +0,0 @@
'use strict';
define(
[
'backbone',
'Quality/QualityProfileModel'
], function (Backbone, QualityProfileModel) {
return Backbone.Collection.extend({
model: QualityProfileModel,
url : window.NzbDrone.ApiRoot + '/qualityprofile/schema'
});
});
@@ -1,37 +0,0 @@
'use strict';
define(
[
'AppLayout',
'marionette',
'Settings/Quality/Profile/Edit/EditQualityProfileLayout',
'Mixins/AsModelBoundView',
'Settings/Quality/Profile/AllowedLabeler',
'bootstrap'
], function (AppLayout, Marionette, EditProfileView, AsModelBoundView) {
var view = Marionette.ItemView.extend({
template: 'Settings/Quality/Profile/QualityProfileViewTemplate',
tagName : 'li',
ui: {
'progressbar' : '.progress .bar',
'deleteButton': '.x-delete'
},
events: {
'click' : '_editProfile'
},
initialize: function () {
this.listenTo(this.model, 'sync', this.render);
},
_editProfile: function () {
var view = new EditProfileView({ model: this.model, profileCollection: this.model.collection });
AppLayout.modalRegion.show(view);
}
});
return AsModelBoundView.call(view);
});
@@ -1,9 +0,0 @@
<div class="quality-profile-item thingy" title="Click to edit">
<div>
<h3 name="name"></h3>
</div>
<ul class="allowed-qualities">
{{allowedLabeler}}
</ul>
</div>
+1 -6
View File
@@ -3,28 +3,23 @@
define(
[
'marionette',
'Quality/QualityProfileCollection',
'Settings/Quality/Profile/QualityProfileCollectionView',
'Quality/QualityDefinitionCollection',
'Settings/Quality/Definition/QualityDefinitionCollectionView'
], function (Marionette, QualityProfileCollection, QualityProfileCollectionView, QualityDefinitionCollection, QualityDefinitionCollectionView) {
], function (Marionette, QualityDefinitionCollection, QualityDefinitionCollectionView) {
return Marionette.Layout.extend({
template: 'Settings/Quality/QualityLayoutTemplate',
regions: {
qualityProfile : '#quality-profile',
qualityDefinition : '#quality-definition'
},
initialize: function (options) {
this.settings = options.settings;
QualityProfileCollection.fetch();
this.qualityDefinitionCollection = new QualityDefinitionCollection();
this.qualityDefinitionCollection.fetch();
},
onShow: function () {
this.qualityProfile.show(new QualityProfileCollectionView({collection: QualityProfileCollection}));
this.qualityDefinition.show(new QualityDefinitionCollectionView({collection: this.qualityDefinitionCollection}));
}
});
@@ -1,9 +1,3 @@
<div class="row">
<div class="col-md-12" id="quality-profile"/>
</div>
<br/>
<div class="row advanced-setting">
<div class="col-md-12" id="quality-definition"/>
</div>
-24
View File
@@ -2,30 +2,6 @@
@import "../../Content/FontAwesome/font-awesome";
@import "../../Shared/Styles/clickable.less";
.quality-profile-item {
.clickable;
width: 300px;
height: 120px;
padding: 10px 15px;
&.add-card {
.center {
margin-top: 10px;
}
}
.allowed-qualities {
padding-left: 0px;
li {
list-style-type : none;
margin: 1px;
}
}
}
ul.qualities {
.user-select(none);