mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-23 06:45:19 -07:00
Merge branch 'develop' into rename-existing-folder
This commit is contained in:
commit
4bcb0e17f8
18 changed files with 289 additions and 77 deletions
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
|||
environmentVariables.Add("Radarr_EventType", "Download");
|
||||
environmentVariables.Add("Radarr_Movie_Id", movie.Id.ToString());
|
||||
environmentVariables.Add("Radarr_Movie_Title", movie.Title);
|
||||
environmentVariables.Add("Radarr_Movie_Path", movie.Path);
|
||||
environmentVariables.Add("Radarr_Movie_ImdbId", movie.ImdbId.ToString());
|
||||
environmentVariables.Add("Radarr_MovieFile_Id", movieFile.Id.ToString());
|
||||
environmentVariables.Add("Radarr_MovieFile_RelativePath", movieFile.RelativePath);
|
||||
|
|
|
@ -37,12 +37,16 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
|
|||
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
_mediaBrowserService.Update(Settings, message.Series);
|
||||
_mediaBrowserService.UpdateMovies(Settings, message.Movie);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
_mediaBrowserService.UpdateMovies(Settings, movie);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
|
|
|
@ -40,6 +40,16 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
|
|||
ProcessRequest(request, settings);
|
||||
}
|
||||
|
||||
|
||||
public void UpdateMovies(MediaBrowserSettings settings, string imdbid)
|
||||
{
|
||||
var path = string.Format("/Library/Movies/Updated?ImdbId={0}", imdbid);
|
||||
var request = BuildRequest(path, settings);
|
||||
request.Headers.Add("Content-Length", "0");
|
||||
|
||||
ProcessRequest(request, settings);
|
||||
}
|
||||
|
||||
private string ProcessRequest(HttpRequest request, MediaBrowserSettings settings)
|
||||
{
|
||||
request.Headers.Add("X-MediaBrowser-Token", settings.ApiKey);
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
|
|||
{
|
||||
void Notify(MediaBrowserSettings settings, string title, string message);
|
||||
void Update(MediaBrowserSettings settings, Series series);
|
||||
void UpdateMovies(MediaBrowserSettings settings, Movie movie);
|
||||
ValidationFailure Test(MediaBrowserSettings settings);
|
||||
}
|
||||
|
||||
|
@ -35,6 +36,13 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
|
|||
_proxy.Update(settings, series.TvdbId);
|
||||
}
|
||||
|
||||
|
||||
public void UpdateMovies(MediaBrowserSettings settings, Movie movie)
|
||||
{
|
||||
_proxy.UpdateMovies(settings, movie.ImdbId);
|
||||
}
|
||||
|
||||
|
||||
public ValidationFailure Test(MediaBrowserSettings settings)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -51,6 +51,24 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
UpdateLibrary(settings, series);
|
||||
}
|
||||
|
||||
public void UpdateMovie(XbmcSettings settings, Movie movie)
|
||||
{
|
||||
if (!settings.AlwaysUpdate)
|
||||
{
|
||||
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
|
||||
var activePlayers = GetActivePlayers(settings);
|
||||
|
||||
if (activePlayers.Any(a => a.Type.Equals("video")))
|
||||
{
|
||||
_logger.Debug("Video is currently playing, skipping library update");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMovieLibrary(settings, movie);
|
||||
}
|
||||
|
||||
|
||||
public void Clean(XbmcSettings settings)
|
||||
{
|
||||
const string cleanVideoLibrary = "CleanLibrary(video)";
|
||||
|
@ -167,6 +185,37 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
}
|
||||
}
|
||||
|
||||
private void UpdateMovieLibrary(XbmcSettings settings, Movie movie)
|
||||
{
|
||||
try
|
||||
{
|
||||
//_logger.Debug("Sending Update DB Request to XBMC Host: {0}", settings.Address);
|
||||
//var xbmcSeriesPath = GetSeriesPath(settings, series);
|
||||
|
||||
////If the path is found update it, else update the whole library
|
||||
//if (!string.IsNullOrEmpty(xbmcSeriesPath))
|
||||
//{
|
||||
// _logger.Debug("Updating series [{0}] on XBMC host: {1}", series, settings.Address);
|
||||
// var command = BuildExecBuiltInCommand(string.Format("UpdateLibrary(video,{0})", xbmcSeriesPath));
|
||||
// SendCommand(settings, command);
|
||||
//}
|
||||
|
||||
//else
|
||||
//{
|
||||
//Update the entire library
|
||||
_logger.Debug("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", movie, settings.Address);
|
||||
var command = BuildExecBuiltInCommand("UpdateLibrary(video)");
|
||||
SendCommand(settings, command);
|
||||
//}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Debug(ex, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string SendCommand(XbmcSettings settings, string command)
|
||||
{
|
||||
var url = string.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", settings.Address, command);
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
{
|
||||
void Notify(XbmcSettings settings, string title, string message);
|
||||
void Update(XbmcSettings settings, Series series);
|
||||
void UpdateMovie(XbmcSettings settings, Movie movie);
|
||||
void Clean(XbmcSettings settings);
|
||||
bool CanHandle(XbmcVersion version);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,24 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
UpdateLibrary(settings, series);
|
||||
}
|
||||
|
||||
public void UpdateMovie(XbmcSettings settings, Movie movie)
|
||||
{
|
||||
if (!settings.AlwaysUpdate)
|
||||
{
|
||||
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
|
||||
var activePlayers = _proxy.GetActivePlayers(settings);
|
||||
|
||||
if (activePlayers.Any(a => a.Type.Equals("video")))
|
||||
{
|
||||
_logger.Debug("Video is currently playing, skipping library update");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMovieLibrary(settings, movie);
|
||||
}
|
||||
|
||||
|
||||
public void Clean(XbmcSettings settings)
|
||||
{
|
||||
_proxy.CleanLibrary(settings);
|
||||
|
@ -108,5 +126,23 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
_logger.Debug(ex, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMovieLibrary(XbmcSettings settings, Movie movie)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = _proxy.UpdateLibrary(settings, null);
|
||||
|
||||
if (!response.Equals("OK", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.Debug("Failed to update library for: {0}", settings.Address);
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Debug(ex, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,11 +33,12 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
const string header = "Radarr - Downloaded";
|
||||
|
||||
Notify(Settings, header, message.Message);
|
||||
UpdateAndClean(message.Series, message.OldFiles.Any());
|
||||
UpdateAndCleanMovie(message.Movie, message.OldMovieFiles.Any());
|
||||
}
|
||||
|
||||
public override void OnMovieRename(Movie movie)
|
||||
{
|
||||
UpdateAndCleanMovie(movie);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
|
@ -92,5 +93,26 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
_logger.Debug(ex, logMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAndCleanMovie(Movie movie, bool clean = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Settings.UpdateLibrary)
|
||||
{
|
||||
_xbmcService.UpdateMovie(Settings, movie);
|
||||
}
|
||||
|
||||
if (clean && Settings.CleanLibrary)
|
||||
{
|
||||
_xbmcService.Clean(Settings);
|
||||
}
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
var logMessage = string.Format("Unable to connect to XBMC Host: {0}:{1}", Settings.Host, Settings.Port);
|
||||
_logger.Debug(ex, logMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
{
|
||||
void Notify(XbmcSettings settings, string title, string message);
|
||||
void Update(XbmcSettings settings, Series series);
|
||||
void UpdateMovie(XbmcSettings settings, Movie movie);
|
||||
void Clean(XbmcSettings settings);
|
||||
ValidationFailure Test(XbmcSettings settings, string message);
|
||||
}
|
||||
|
@ -51,6 +52,12 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||
provider.Update(settings, series);
|
||||
}
|
||||
|
||||
public void UpdateMovie(XbmcSettings settings, Movie movie)
|
||||
{
|
||||
var provider = GetApiProvider(settings);
|
||||
provider.UpdateMovie(settings, movie);
|
||||
}
|
||||
|
||||
public void Clean(XbmcSettings settings)
|
||||
{
|
||||
var provider = GetApiProvider(settings);
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -4,23 +4,35 @@ 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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
|
@ -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>
|
||||
<ul class="allowed-qualities">
|
||||
{{allowedLabeler}}
|
||||
</ul>
|
||||
</div>
|
Loading…
Add table
Add a link
Reference in a new issue