Added option to specify preferred words in quality profile. (#462)

* UI Done

* Should theoretically work.

* Preferred tags works now correctly :)
This commit is contained in:
Leonardo Galli 2017-01-27 20:01:28 +01:00 committed by GitHub
parent 00541e6cc1
commit cbc70a8ff3
9 changed files with 146 additions and 72 deletions

View File

@ -11,6 +11,7 @@ namespace NzbDrone.Api.Profiles
{
public string Name { get; set; }
public Quality Cutoff { get; set; }
public string PreferredTags { get; set; }
public List<ProfileQualityItemResource> Items { get; set; }
public Language Language { get; set; }
}
@ -33,6 +34,7 @@ namespace NzbDrone.Api.Profiles
Name = model.Name,
Cutoff = model.Cutoff,
PreferredTags = model.PreferredTags != null ? string.Join(",", model.PreferredTags) : "",
Items = model.Items.ConvertAll(ToResource),
Language = model.Language
};
@ -59,6 +61,7 @@ namespace NzbDrone.Api.Profiles
Name = resource.Name,
Cutoff = (Quality)resource.Cutoff.Id,
PreferredTags = resource.PreferredTags.Split(',').ToList(),
Items = resource.Items.ConvertAll(ToModel),
Language = resource.Language
};

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
using System.Data;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(124)]
public class add_preferred_tags_to_profile : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Profiles").AddColumn("PreferredTags").AsString().Nullable();
}
}
}

View File

@ -23,6 +23,7 @@ namespace NzbDrone.Core.DecisionEngine
var comparers = new List<CompareDelegate>
{
CompareQuality,
ComparePreferredWords,
CompareProtocol,
ComparePeersIfTorrent,
CompareAgeIfUsenet,
@ -65,6 +66,26 @@ namespace NzbDrone.Core.DecisionEngine
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Version));
}
private int ComparePreferredWords(DownloadDecision x, DownloadDecision y)
{
return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteMovie =>
{
var title = remoteMovie.Release.Title;
remoteMovie.Movie.Profile.LazyLoad();
var preferredWords = remoteMovie.Movie.Profile.Value.PreferredTags;
if (preferredWords == null)
{
return 0;
}
var num = preferredWords.AsEnumerable().Count(w => title.ToLower().Contains(w.ToLower()));
return num;
});
; }
private int CompareProtocol(DownloadDecision x, DownloadDecision y)
{

View File

@ -183,6 +183,7 @@
<Compile Include="Datastore\Migration\002_remove_tvrage_imdb_unique_constraint.cs" />
<Compile Include="Datastore\Migration\003_remove_clean_title_from_scene_mapping.cs" />
<Compile Include="Datastore\Migration\004_updated_history.cs" />
<Compile Include="Datastore\Migration\124_add_preferred_tags_to_profile.cs" />
<Compile Include="Datastore\Migration\122_add_movieid_to_blacklist.cs" />
<Compile Include="Datastore\Migration\121_update_filedate_config.cs" />
<Compile Include="Datastore\Migration\120_add_studio_to_table.cs" />

View File

@ -11,6 +11,7 @@ namespace NzbDrone.Core.Profiles
public string Name { get; set; }
public Quality Cutoff { get; set; }
public List<ProfileQualityItem> Items { get; set; }
public List<string> PreferredTags { get; set; }
public Language Language { get; set; }
public Quality LastAllowedQuality()

View File

@ -4,25 +4,37 @@ var LanguageCollection = require('../Language/LanguageCollection');
var Config = require('../../../Config');
var AsModelBoundView = require('../../../Mixins/AsModelBoundView');
var AsValidatedView = require('../../../Mixins/AsValidatedView');
require('../../../Mixins/TagInput');
require('bootstrap');
require('bootstrap.tagsinput');
var view = Marionette.ItemView.extend({
template : 'Settings/Profile/Edit/EditProfileViewTemplate',
template : 'Settings/Profile/Edit/EditProfileViewTemplate',
ui : { cutoff : '.x-cutoff' },
ui : { cutoff : '.x-cutoff',
preferred : '.x-preferred',
},
templateHelpers : function() {
return {
languages : LanguageCollection.toJSON()
};
},
onRender : function() {
this.ui.preferred.tagsinput({
trimValue : true,
tagClass : 'label label-success'
});
},
getCutoff : function() {
var self = this;
templateHelpers : function() {
return {
languages : LanguageCollection.toJSON()
};
},
return _.findWhere(_.pluck(this.model.get('items'), 'quality'), { id : parseInt(self.ui.cutoff.val(), 10) });
}
getCutoff : function() {
var self = this;
return _.findWhere(_.pluck(this.model.get('items'), 'quality'), { id : parseInt(self.ui.cutoff.val(), 10) });
}
});
AsValidatedView.call(view);
module.exports = AsModelBoundView.call(view);
module.exports = AsModelBoundView.call(view);

View File

@ -1,45 +1,59 @@
<div class="form-group">
<label class="col-sm-3 control-label">Name</label>
<label class="col-sm-3 control-label">Name</label>
<div class="col-sm-5">
<input type="text" name="name" class="form-control">
</div>
<div class="col-sm-5">
<input type="text" name="name" class="form-control">
</div>
</div>
<hr>
<div class="form-group">
<label class="col-sm-3 control-label">Language</label>
<label class="col-sm-3 control-label">Language</label>
<div class="col-sm-5">
<select class="form-control" name="language">
{{#each languages}}
{{#unless_eq nameLower compare="unknown"}}
<option value="{{nameLower}}">{{name}}</option>
{{/unless_eq}}
{{/each}}
</select>
</div>
<div class="col-sm-5">
<select class="form-control" name="language">
{{#each languages}}
{{#unless_eq nameLower compare="unknown"}}
<option value="{{nameLower}}">{{name}}</option>
{{/unless_eq}}
{{/each}}
</select>
</div>
<div class="col-sm-1 help-inline">
<i class="icon-sonarr-form-info" title="Series assigned this profile will be look for episodes with the selected language"/>
</div>
<div class="col-sm-1 help-inline">
<i class="icon-sonarr-form-info" title="Series assigned this profile will be look for episodes with the selected language"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Preferred Tags</label>
<div class="col-sm-1 col-sm-push-5 help-inline">
<i class="icon-sonarr-form-info" title="When the release contains these tags it will be preferred." />
</div>
<div class="col-sm-5 col-sm-pull-1">
<input type="text" name="preferredTags" class="form-control x-preferred"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Cutoff</label>
<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-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-sonarr-form-info" title="Once this quality is reached Radarr will no longer download episodes"/>
</div>
<div class="col-sm-1 help-inline">
<i class="icon-sonarr-form-info" title="Once this quality is reached Radarr will no longer download episodes"/>
</div>
</div>

View File

@ -6,30 +6,32 @@ require('./AllowedLabeler');
require('./LanguageLabel');
require('bootstrap');
var view = Marionette.ItemView.extend({
template : 'Settings/Profile/ProfileViewTemplate',
tagName : 'li',
template : 'Settings/Profile/ProfileViewTemplate',
tagName : 'li',
ui : {
"progressbar" : '.progress .bar',
"deleteButton" : '.x-delete'
},
ui : {
"progressbar" : '.progress .bar',
"deleteButton" : '.x-delete',
events : {
'click' : '_editProfile'
},
},
initialize : function() {
this.listenTo(this.model, 'sync', this.render);
},
events : {
'click' : '_editProfile'
},
_editProfile : function() {
var view = new EditProfileView({
model : this.model,
profileCollection : this.model.collection
});
AppLayout.modalRegion.show(view);
}
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);
}
});
module.exports = AsModelBoundView.call(view);
module.exports = AsModelBoundView.call(view);

View File

@ -1,13 +1,13 @@
<div class="profile-item thingy">
<div>
<h3 name="name"></h3>
</div>
<div>
<h3 name="name"></h3>
</div>
<div class="language">
{{languageLabel}}
</div>
<div class="language">
{{languageLabel}}
</div>
<ul class="allowed-qualities">
{{allowedLabeler}}
</ul>
</div>
<ul class="allowed-qualities">
{{allowedLabeler}}
</ul>
</div>