Merge branch 'feature/better-import-exclusions' into develop

This commit is contained in:
Leonardo Galli 2017-05-09 20:44:17 +02:00
commit b49f0e70ed
28 changed files with 526 additions and 107 deletions

View File

@ -0,0 +1,45 @@
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Api.ClientSchema;
using NzbDrone.Core.NetImport;
using NzbDrone.Core.NetImport.ImportExclusions;
using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Api.NetImport
{
public class ImportExclusionsModule : NzbDroneRestModule<ImportExclusionsResource>
{
private readonly IImportExclusionsService _exclusionService;
public ImportExclusionsModule(NetImportFactory netImportFactory, IImportExclusionsService exclusionService) : base("exclusions")
{
_exclusionService = exclusionService;
GetResourceAll = GetAll;
CreateResource = AddExclusion;
DeleteResource = RemoveExclusion;
GetResourceById = GetById;
}
public List<ImportExclusionsResource> GetAll()
{
return _exclusionService.GetAllExclusions().ToResource();
}
public ImportExclusionsResource GetById(int id)
{
return _exclusionService.GetById(id).ToResource();
}
public int AddExclusion(ImportExclusionsResource exclusionResource)
{
var model = exclusionResource.ToModel();
return _exclusionService.AddExclusion(model).Id;
}
public void RemoveExclusion (int id)
{
_exclusionService.RemoveExclusion(new ImportExclusion { Id = id });
}
}
}

View File

@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.NetImport;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.NetImport
{
public class ImportExclusionsResource : ProviderResource
{
//public int Id { get; set; }
public int TmdbId { get; set; }
public string MovieTitle { get; set; }
public int MovieYear { get; set; }
}
public static class ImportExclusionsResourceMapper
{
public static ImportExclusionsResource ToResource(this Core.NetImport.ImportExclusions.ImportExclusion model)
{
if (model == null) return null;
return new ImportExclusionsResource
{
Id = model.Id,
TmdbId = model.TmdbId,
MovieTitle = model.MovieTitle,
MovieYear = model.MovieYear
};
}
public static List<ImportExclusionsResource> ToResource(this IEnumerable<Core.NetImport.ImportExclusions.ImportExclusion> exclusions)
{
return exclusions.Select(ToResource).ToList();
}
public static Core.NetImport.ImportExclusions.ImportExclusion ToModel(this ImportExclusionsResource resource)
{
return new Core.NetImport.ImportExclusions.ImportExclusion
{
TmdbId = resource.TmdbId,
MovieTitle = resource.MovieTitle,
MovieYear = resource.MovieYear
};
}
}
}

View File

@ -271,6 +271,8 @@
<Compile Include="Wanted\MovieCutoffModule.cs" />
<Compile Include="Wanted\MovieMissingModule.cs" />
<Compile Include="Series\MovieDiscoverModule.cs" />
<Compile Include="NetImport\ImportExclusionsModule.cs" />
<Compile Include="NetImport\ImportExclusionsResource.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
@ -80,5 +80,30 @@ namespace NzbDrone.Common.Extensions
{
return source.Select(predicate).ToList();
}
public static IEnumerable<T> DropLast<T>(this IEnumerable<T> source, int n)
{
if (source == null)
throw new ArgumentNullException("source");
if (n < 0)
throw new ArgumentOutOfRangeException("n",
"Argument n should be non-negative.");
return InternalDropLast(source, n);
}
private static IEnumerable<T> InternalDropLast<T>(IEnumerable<T> source, int n)
{
Queue<T> buffer = new Queue<T>(n + 1);
foreach (T x in source)
{
buffer.Enqueue(x);
if (buffer.Count == n + 1)
yield return buffer.Dequeue();
}
}
}
}

View File

@ -0,0 +1,60 @@
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
using System.Text;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text.RegularExpressions;
using System.Globalization;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(137)]
public class add_import_exclusions_table : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
if (!this.Schema.Schema("dbo").Table("ImportExclusions").Exists())
{
Create.TableForModel("ImportExclusions")
.WithColumn("TmdbId").AsInt64().NotNullable().Unique().PrimaryKey()
.WithColumn("MovieTitle").AsString().Nullable()
.WithColumn("MovieYear").AsInt64().Nullable().WithDefault(0);
}
Execute.WithConnection(AddExisting);
}
private void AddExisting(IDbConnection conn, IDbTransaction tran)
{
using (IDbCommand getSeriesCmd = conn.CreateCommand())
{
getSeriesCmd.Transaction = tran;
getSeriesCmd.CommandText = @"SELECT Key, Value FROM Config WHERE Key = 'importexclusions'";
TextInfo textInfo = new CultureInfo("en-US", false).TextInfo;
using (IDataReader seriesReader = getSeriesCmd.ExecuteReader())
{
while (seriesReader.Read())
{
var Key = seriesReader.GetString(0);
var Value = seriesReader.GetString(1);
var importExclusions = Value.Split(',').Select(x => {
return string.Format("(\"{0}\", \"{1}\")", Regex.Replace(x, @"^.*\-(.*)$", "$1"),
textInfo.ToTitleCase(string.Join(" ", x.Split('-').DropLast(1))));
}).ToList();
using (IDbCommand updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "INSERT INTO ImportExclusions (tmdbid, MovieTitle) VALUES " + string.Join(", ", importExclusions);
updateCmd.ExecuteNonQuery();
}
}
}
}
}
}
}

View File

@ -35,6 +35,7 @@ using NzbDrone.Core.Extras.Others;
using NzbDrone.Core.Extras.Subtitles;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.NetImport;
using NzbDrone.Core.NetImport.ImportExclusions;
namespace NzbDrone.Core.Datastore
{
@ -105,6 +106,8 @@ namespace NzbDrone.Core.Datastore
.Relationship()
.HasOne(s => s.Profile, s => s.ProfileId)
.HasOne(m => m.MovieFile, m => m.MovieFileId);
Mapper.Entity<ImportExclusion>().RegisterModel("ImportExclusions");
Mapper.Entity<Episode>().RegisterModel("Episodes")

View File

@ -16,6 +16,7 @@ using System.Threading;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Profiles;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.NetImport.ImportExclusions;
namespace NzbDrone.Core.MetadataSource.SkyHook
{
@ -29,8 +30,10 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
private readonly ITmdbConfigService _configService;
private readonly IMovieService _movieService;
private readonly IPreDBService _predbService;
private readonly IImportExclusionsService _exclusionService;
public SkyHookProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, ITmdbConfigService configService, IMovieService movieService, IPreDBService predbService, Logger logger)
public SkyHookProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, ITmdbConfigService configService, IMovieService movieService,
IPreDBService predbService, IImportExclusionsService exclusionService, Logger logger)
{
_httpClient = httpClient;
_requestBuilder = requestBuilder.SkyHookTvdb;
@ -38,6 +41,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
_configService = configService;
_movieService = movieService;
_predbService = predbService;
_exclusionService = exclusionService;
_logger = logger;
}
@ -351,7 +355,10 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
public List<Movie> DiscoverNewMovies(string action)
{
string allIds = string.Join(",", _movieService.GetAllMovies().Select(m => m.TmdbId));
var allMovies = _movieService.GetAllMovies();
var allExclusions = _exclusionService.GetAllExclusions();
string allIds = string.Join(",", allMovies.Select(m => m.TmdbId));
string ignoredIds = string.Join(",", allExclusions.Select(ex => ex.TmdbId));
HttpRequest request;
List<MovieResult> results;
@ -387,7 +394,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
request.AllowAutoRedirect = true;
request.Method = HttpMethod.POST;
request.Headers.ContentType = "application/x-www-form-urlencoded";
request.SetContent($"tmdbids={allIds}");
request.SetContent($"tmdbids={allIds}&ignoredIds={ignoredIds}");
var response = _httpClient.Post<List<MovieResult>>(request);
@ -399,6 +406,8 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
results = response.Resource;
}
results = results.Where(m => allMovies.None(mo => mo.TmdbId == m.id) && allExclusions.None(ex => ex.TmdbId == m.id)).ToList();
return results.SelectList(MapMovie);
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using Marr.Data;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Profiles;
using NzbDrone.Core.MediaFiles;
using System.IO;
namespace NzbDrone.Core.NetImport.ImportExclusions
{
public class ImportExclusion : ModelBase
{
public int TmdbId { get; set; }
public string MovieTitle { get; set; }
public int MovieYear { get; set; }
new public string ToString()
{
return string.Format("Excluded Movie: [{0}][{1} {2}]", TmdbId, MovieTitle, MovieYear);
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Linq;
using System.Collections.Generic;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Datastore.Extensions;
using Marr.Data.QGen;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Parser.RomanNumerals;
using NzbDrone.Core.Qualities;
using CoreParser = NzbDrone.Core.Parser.Parser;
namespace NzbDrone.Core.NetImport.ImportExclusions
{
public interface IImportExclusionsRepository : IBasicRepository<ImportExclusion>
{
bool IsMovieExcluded(int tmdbid);
}
public class ImportExclusionsRepository : BasicRepository<ImportExclusion>, IImportExclusionsRepository
{
protected IMainDatabase _database;
public ImportExclusionsRepository(IMainDatabase database, IEventAggregator eventAggregator)
: base(database, eventAggregator)
{
_database = database;
}
public bool IsMovieExcluded(int tmdbid)
{
return Query.Where(ex => ex.TmdbId == tmdbid).Any();
}
}
}

View File

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Tv.Events;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Core.NetImport.ImportExclusions
{
public interface IImportExclusionsService
{
List<ImportExclusion> GetAllExclusions();
bool IsMovieExcluded(int tmdbid);
ImportExclusion AddExclusion(ImportExclusion exclusion);
void RemoveExclusion(ImportExclusion exclusion);
ImportExclusion GetById(int id);
}
public class ImportExclusionsService : IImportExclusionsService
{
private readonly IImportExclusionsRepository _exclusionRepository;
private readonly IConfigService _configService;
private readonly IEventAggregator _eventAggregator;
private readonly Logger _logger;
public ImportExclusionsService(IImportExclusionsRepository exclusionRepository,
IEventAggregator eventAggregator,
IConfigService configService,
Logger logger)
{
_exclusionRepository = exclusionRepository;
_eventAggregator = eventAggregator;
_configService = configService;
_logger = logger;
}
public ImportExclusion AddExclusion(ImportExclusion exclusion)
{
return _exclusionRepository.Insert(exclusion);
}
public List<ImportExclusion> GetAllExclusions()
{
return _exclusionRepository.All().ToList();
}
public bool IsMovieExcluded(int tmdbid)
{
return _exclusionRepository.IsMovieExcluded(tmdbid);
}
public void RemoveExclusion(ImportExclusion exclusion)
{
_exclusionRepository.Delete(exclusion);
}
public ImportExclusion GetById(int id)
{
return _exclusionRepository.Get(id);
}
}
}

View File

@ -13,6 +13,7 @@ using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.IndexerSearch;
using NzbDrone.Core.NetImport.ImportExclusions;
namespace NzbDrone.Core.NetImport
{
@ -32,11 +33,14 @@ namespace NzbDrone.Core.NetImport
private readonly IConfigService _configService;
private readonly ISearchForNzb _nzbSearchService;
private readonly IProcessDownloadDecisions _processDownloadDecisions;
private readonly IImportExclusionsService _exclusionService;
public NetImportSearchService(INetImportFactory netImportFactory, IMovieService movieService,
ISearchForNewMovie movieSearch, IRootFolderService rootFolder, ISearchForNzb nzbSearchService,
IProcessDownloadDecisions processDownloadDecisions, IConfigService configService, Logger logger)
IProcessDownloadDecisions processDownloadDecisions, IConfigService configService,
IImportExclusionsService exclusionService,
Logger logger)
{
_netImportFactory = netImportFactory;
_movieService = movieService;
@ -44,6 +48,7 @@ namespace NzbDrone.Core.NetImport
_nzbSearchService = nzbSearchService;
_processDownloadDecisions = processDownloadDecisions;
_rootFolder = rootFolder;
_exclusionService = exclusionService;
_logger = logger;
_configService = configService;
}
@ -119,18 +124,12 @@ namespace NzbDrone.Core.NetImport
var importExclusions = new List<string>();
if (_configService.ImportExclusions != null)
{
// Replace `movie-title-tmdbid` with just tmdbid in exclusions
importExclusions = _configService.ImportExclusions.Split(',').Select(x => Regex.Replace(x, @"^.*\-(.*)$", "$1")).ToList();
// listedMovies = listedMovies.Where(ah => importExclusions.Any(h => ah.TmdbId.ToString() != h)).ToList();
}
//var downloadedCount = 0;
foreach (var movie in listedMovies)
{
var mapped = _movieSearch.MapMovieToTmdbMovie(movie);
if (mapped != null && !importExclusions.Any(x => x == mapped.TmdbId.ToString()))
if (mapped != null && !_exclusionService.IsMovieExcluded(mapped.TmdbId))
{
//List<DownloadDecision> decisions;
mapped.AddOptions = new AddMovieOptions {SearchForMovie = true};

View File

@ -1280,6 +1280,10 @@
<Compile Include="Tv\QueryExtensions.cs" />
<Compile Include="Datastore\Migration\136_add_pathstate_to_movies.cs" />
<Compile Include="MetadataSource\IDiscoverNewMovies.cs" />
<Compile Include="Datastore\Migration\137_add_import_exclusions_table.cs" />
<Compile Include="NetImport\ImportExclusions\ImportExclusion.cs" />
<Compile Include="NetImport\ImportExclusions\ImportExclusionsRepository.cs" />
<Compile Include="NetImport\ImportExclusions\ImportExclusionsService.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
@ -1349,6 +1353,9 @@
<Compile Include="Notifications\Telegram\TelegramError.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="NetImport\ImportExclusions\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>

View File

@ -14,6 +14,7 @@ using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.NetImport.ImportExclusions;
namespace NzbDrone.Core.Tv
{
@ -51,6 +52,7 @@ namespace NzbDrone.Core.Tv
private readonly IConfigService _configService;
private readonly IEventAggregator _eventAggregator;
private readonly IBuildFileNames _fileNameBuilder;
private readonly IImportExclusionsService _exclusionService;
private readonly Logger _logger;
@ -60,12 +62,14 @@ namespace NzbDrone.Core.Tv
IEpisodeService episodeService,
IBuildFileNames fileNameBuilder,
IConfigService configService,
IImportExclusionsService exclusionService,
Logger logger)
{
_movieRepository = movieRepository;
_eventAggregator = eventAggregator;
_fileNameBuilder = fileNameBuilder;
_configService = configService;
_exclusionService = exclusionService;
_logger = logger;
}
@ -286,14 +290,7 @@ namespace NzbDrone.Core.Tv
var movie = _movieRepository.Get(movieId);
if (addExclusion)
{
if (_configService.ImportExclusions.Empty())
{
_configService.ImportExclusions = movie.TitleSlug;
}
else if (!_configService.ImportExclusions.Contains(movie.TitleSlug))
{
_configService.ImportExclusions += ',' + movie.TitleSlug;
}
_exclusionService.AddExclusion(new ImportExclusion {TmdbId = movie.TmdbId, MovieTitle = movie.Title, MovieYear = movie.Year } );
}
_movieRepository.Delete(movieId);
_eventAggregator.PublishEvent(new MovieDeletedEvent(movie, deleteFiles));

View File

@ -6,6 +6,7 @@ var AddMoviesCollection = require('./AddMoviesCollection');
var SearchResultCollectionView = require('./SearchResultCollectionView');
var EmptyView = require('./EmptyView');
var NotFoundView = require('./NotFoundView');
var DiscoverEmptyView = require('./DiscoverEmptyView');
var ErrorView = require('./ErrorView');
var LoadingView = require('../Shared/LoadingView');
var FullMovieCollection = require("../Movies/FullMovieCollection");
@ -112,14 +113,10 @@ module.exports = Marionette.Layout.extend({
if (this.isDiscover) {
this.ui.searchBar.hide();
if (FullMovieCollection.length > 0) {
this._discoverRecos();
} else {
this.listenTo(FullMovieCollection, "sync", this._discover);
}
if (this.collection.length == 0) {
this._discoverRecos();
/*if (this.collection.length == 0) {
this.searchResult.show(new LoadingView());
}
}*/
}
},
@ -192,8 +189,13 @@ module.exports = Marionette.Layout.extend({
_showResults : function() {
if (!this.isClosed) {
if (this.collection.length === 0) {
this.ui.searchBar.show();
this.searchResult.show(new NotFoundView({ term : this.collection.term }));
if (this.isDiscover) {
this.searchResult.show(new DiscoverEmptyView());
} else {
this.ui.searchBar.show();
this.searchResult.show(new NotFoundView({ term : this.collection.term }));
}
} else {
this.searchResult.show(this.resultCollectionView);
if (!this.showingAll) {
@ -224,11 +226,10 @@ module.exports = Marionette.Layout.extend({
if (this.collection.action === action) {
return
}
this.collection.reset();
this.searchResult.show(new LoadingView());
this.collection.action = action;
this.collection.fetch({
data : { action : action }
});
this.currentSearchPromise = this.collection.fetch();
},
_discoverRecos : function() {

View File

@ -0,0 +1,5 @@
var Marionette = require('marionette');
module.exports = Marionette.CompositeView.extend({
template : 'AddMovies/DiscoverEmptyViewTemplate'
});

View File

@ -0,0 +1,6 @@
<div class="text-center col-md-12">
<h3>
No movies left to discover. Come back at another time :)
</h3>
</div>

View File

@ -7,6 +7,7 @@ var Profiles = require('../Profile/ProfileCollection');
var RootFolders = require('./RootFolders/RootFolderCollection');
var RootFolderLayout = require('./RootFolders/RootFolderLayout');
var FullMovieCollection = require('../Movies/FullMovieCollection');
var ImportExclusionModel = require("../Settings/NetImport/ImportExclusionModel");
var Config = require('../Config');
var Messenger = require('../Shared/Messenger');
var AsValidatedView = require('../Mixins/AsValidatedView');
@ -33,6 +34,7 @@ var view = Marionette.ItemView.extend({
events : {
'click .x-add' : '_addWithoutSearch',
'click .x-add-search' : '_addAndSearch',
"click .x-ignore" : "_ignoreMovie",
'change .x-profile' : '_profileChanged',
'change .x-root-folder' : '_rootFolderChanged',
'change .x-season-folder' : '_seasonFolderChanged',
@ -239,6 +241,13 @@ var view = Marionette.ItemView.extend({
});
},
_ignoreMovie : function() {
var exclusion = new ImportExclusionModel({tmdbId : this.model.get("tmdbId"),
movieTitle : this.model.get("title"), movieYear : this.model.get("year")});
exclusion.save();
this.remove();
},
_rootFoldersUpdated : function() {
this._configureTemplateHelpers();
this.render();

View File

@ -106,6 +106,10 @@
<button class="btn btn-success add x-add-search" title="Add and Search for movie">
<i class="icon-sonarr-search"></i>
</button>
<button class="btn btn-warning ignore x-ignore" title="Ignore this movie, so it does not show up anymore">
<i class="icon-sonarr-ignore"></i>
</button>
</div>
</div>
{{else}}

View File

@ -304,6 +304,10 @@
.fa-icon-color(@brand-danger);
}
.icon-sonarr-ignore {
.fa-icon-content(@fa-var-eye-slash);
}
.icon-sonarr-deleted {
.fa-icon-content(@fa-var-trash);
}

View File

@ -0,0 +1,24 @@
var vent = require('vent');
var Backgrid = require('backgrid');
module.exports = Backgrid.Cell.extend({
className : 'delete-episode-file-cell',
events : {
'click' : '_onClick'
},
render : function() {
this.$el.empty();
this.$el.html('<i class="icon-sonarr-delete" title="Delete exclusion."></i>');
return this;
},
_onClick : function() {
var self = this;
this.model.destroy();
}
});

View File

@ -0,0 +1,18 @@
var NzbDroneCell = require('../../Cells/NzbDroneCell');
module.exports = NzbDroneCell.extend({
className : 'exclusion-title-cell',
render : function() {
this.$el.empty();
var title = this.model.get("movieTitle");
var year = this.model.get("movieYear");
var str = title;
if (year > 1800) {
str += " ("+year+")";
}
this.$el.html(str);
return this;
}
});

View File

@ -0,0 +1,7 @@
var Backbone = require('backbone');
var _ = require('underscore');
module.exports = Backbone.Model.extend({
urlRoot : window.NzbDrone.ApiRoot + '/exclusions',
});

View File

@ -0,0 +1,9 @@
var Backbone = require('backbone');
var NetImportModel = require('./ImportExclusionModel');
var ImportExclusionsCollection = Backbone.Collection.extend({
model : NetImportModel,
url : window.NzbDrone.ApiRoot + '/exclusions',
});
module.exports = new ImportExclusionsCollection();

View File

@ -3,6 +3,14 @@ var NetImportCollection = require('./NetImportCollection');
var CollectionView = require('./NetImportCollectionView');
var OptionsView = require('./Options/NetImportOptionsView');
var RootFolderCollection = require('../../AddMovies/RootFolders/RootFolderCollection');
var ImportExclusionsCollection = require('./ImportExclusionsCollection');
var SelectAllCell = require('../../Cells/SelectAllCell');
var DeleteExclusionCell = require('./DeleteExclusionCell');
var ExclusionTitleCell = require("./ExclusionTitleCell");
var _ = require('underscore');
var vent = require('vent');
var Backgrid = require('backgrid');
var $ = require('jquery');
module.exports = Marionette.Layout.extend({
template : 'Settings/NetImport/NetImportLayoutTemplate',
@ -10,18 +18,58 @@ module.exports = Marionette.Layout.extend({
regions : {
lists : '#x-lists-region',
listOption : '#x-list-options-region',
importExclusions : "#exclusions"
},
columns: [{
name: '',
cell: SelectAllCell,
headerCell: 'select-all',
sortable: false
}, {
name: 'tmdbId',
label: 'TMDBID',
cell: Backgrid.StringCell,
sortable: false,
}, {
name: 'movieTitle',
label: 'Title',
cell: ExclusionTitleCell,
cellValue: 'this',
}, {
name: 'this',
label: '',
cell: DeleteExclusionCell,
sortable: false,
}],
initialize : function() {
this.indexersCollection = new NetImportCollection();
this.indexersCollection.fetch();
RootFolderCollection.fetch().done(function() {
RootFolderCollection.synced = true;
});
ImportExclusionsCollection.fetch().done(function() {
ImportExclusionsCollection.synced = true;
});
},
onShow : function() {
this.listenTo(ImportExclusionsCollection, "sync", this._showExclusions);
if (ImportExclusionsCollection.synced === true) {
this._showExclusions();
}
this.lists.show(new CollectionView({ collection : this.indexersCollection }));
this.listOption.show(new OptionsView({ model : this.model }));
},
_showExclusions : function() {
this.exclusionGrid = new Backgrid.Grid({
collection: ImportExclusionsCollection,
columns: this.columns,
className: 'table table-hover'
});
this.importExclusions.show(this.exclusionGrid);
}
});

View File

@ -1,4 +1,9 @@
<div id="x-lists-region"></div>
<div class="form-horizontal">
<div id="x-list-options-region"></div>
<fieldset>
<legend>Import Exclusions</legend>
<div id="exclusions">
</div>
</fieldset>
</div>

View File

@ -1,6 +1,11 @@
var Marionette = require('marionette');
var AsModelBoundView = require('../../../Mixins/AsModelBoundView');
var AsValidatedView = require('../../../Mixins/AsValidatedView');
var ImportExclusionsCollection = require('./../ImportExclusionsCollection');
var SelectAllCell = require('../../../Cells/SelectAllCell');
var _ = require('underscore');
var vent = require('vent');
var Backgrid = require('backgrid');
var $ = require('jquery');
require('../../../Mixins/TagInput');
require('bootstrap');
@ -22,10 +27,10 @@ var view = Marionette.ItemView.extend({
'click .x-revoke-trakt-tokens' : '_revokeTraktTokens'
},
initialize : function() {
initialize : function() {
},
onShow : function() {
var params = new URLSearchParams(window.location.search);
var oauth = params.get('access');
@ -39,78 +44,25 @@ var view = Marionette.ItemView.extend({
//Config.setValue("traktRefreshToken", refresh);
var tokenExpiry = Math.floor(Date.now() / 1000) + 4838400;
this.ui.tokenExpiry.val(tokenExpiry).trigger('change'); // this means the token will expire in 8 weeks (4838400 seconds)
//Config.setValue("traktTokenExpiry",tokenExpiry);
//Config.setValue("traktTokenExpiry",tokenExpiry);
//this.model.isSaved = false;
//window.alert("Trakt Authentication Complete - Click Save to make the change take effect");
}
if (this.ui.authToken.val() && this.ui.refreshToken.val()){
this.ui.resetTokensButton.hide();
this.ui.revokeTokensButton.show();
this.ui.resetTokensButton.hide();
this.ui.revokeTokensButton.show();
} else {
this.ui.resetTokensButton.show();
this.ui.revokeTokensButton.hide();
this.ui.resetTokensButton.show();
this.ui.revokeTokensButton.hide();
}
},
onRender : function() {
this.ui.importExclusions.tagsinput({
trimValue : true,
tagClass : 'label label-danger',
/*itemText : function(item) {
var uri;
var text;
if (item.startsWith('tt')) {
uri = window.NzbDrone.ApiRoot + '/movies/lookup/imdb?imdbId='+item;
}
else {
uri = window.NzbDrone.ApiRoot + '/movies/lookup/tmdb?tmdbId='+item;
}
var promise = $.ajax({
url : uri,
type : 'GET',
async : false,
});
promise.success(function(response) {
text=response['title']+' ('+response['year']+')';
});
promise.error(function(request, status, error) {
text=item;
});
return text;
}*/
});
this.ui.importExclusions.on('beforeItemAdd', function(event) {
var uri;
if (event.item.startsWith('tt')) {
uri = window.NzbDrone.ApiRoot + '/movies/lookup/imdb?imdbId='+event.item;
}
else {
uri = window.NzbDrone.ApiRoot + '/movies/lookup/tmdb?tmdbId='+event.item;
}
var promise = $.ajax({
url : uri,
type : 'GET',
async : false,
});
promise.success(function(response) {
event.cancel=false;
//var newText = response['tmdbId']+'-';
//if (event.item.startsWith('tt')) {
// newText = newText+'['+event.item+']';
//}
event.item = response.titleSlug;//+' ('+response['year']+')-'+response['tmdbId'];
});
promise.error(function(request, status, error) {
event.cancel = true;
window.alert(event.item+' is not a valid! Must be valid tt#### IMDB ID or #### TMDB ID');
});
return event;
});
},
},
ui : {
resetTraktTokens : '.x-reset-trakt-tokens',
@ -118,7 +70,7 @@ var view = Marionette.ItemView.extend({
refreshToken : '.x-trakt-refresh-token',
resetTokensButton : '.x-reset-trakt-tokens',
revokeTokensButton : '.x-revoke-trakt-tokens',
tokenExpiry : '.x-trakt-token-expiry',
tokenExpiry : '.x-trakt-token-expiry',
importExclusions : '.x-import-exclusions'
},
@ -131,15 +83,16 @@ var view = Marionette.ItemView.extend({
_revokeTraktTokens : function() {
if (window.confirm("Log out of trakt.tv?")){
//TODO: need to implement this: http://docs.trakt.apiary.io/#reference/authentication-oauth/revoke-token/revoke-an-access_token
//TODO: need to implement this: http://docs.trakt.apiary.io/#reference/authentication-oauth/revoke-token/revoke-an-access_token
this.ui.authToken.val('').trigger('change');
this.ui.refreshToken.val('').trigger('change');
this.ui.tokenExpiry.val(0).trigger('change');
this.ui.refreshToken.val('').trigger('change');
this.ui.tokenExpiry.val(0).trigger('change');
this.ui.resetTokensButton.show();
this.ui.revokeTokensButton.hide();
window.alert("Logged out of Trakt.tv - Click Save to make the change take effect");
this.ui.revokeTokensButton.hide();
window.alert("Logged out of Trakt.tv - Click Save to make the change take effect");
}
}
},
});

View File

@ -30,17 +30,17 @@
</select>
</div>
</div>
<div class="form-group">
<!--<div class="form-group">
<label class="col-sm-3 control-label">Import Exclusions</label>
<div class="col-sm-1 col-sm-push-4 help-inline">
<i class="icon-sonarr-form-warning" title="Movies in this field will not be imported even if they exist on your lists."/>
<i class="icon-sonarr-form-info" title="Comma separated imdbid or tmdbid: tt0120915,216138,tt0121765"/>
</div>
<div class="col-sm-4 col-sm-pull-1">
<input type="text" name="importExclusions" class="form-control x-import-exclusions"/>
</div>
</div>
</div>-->
<legend>Trakt Authentication</legend>
<div class="form-group">
<label class="col-sm-1 control-label">Auth Token</label>
@ -58,5 +58,6 @@
<button class="btn btn-danger btn-icon-only x-reset-trakt-tokens" title="Reset Trakt Tokens"><i class="icon-sonarr-refresh"></i></button>
<button class="btn btn-danger btn-icon-only x-revoke-trakt-tokens" title="Revoke Trakt Tokens"><i class="icon-sonarr-logout"></i></button>
</div >
</div>
</div>
</fieldset>

View File

@ -14,6 +14,7 @@ var IndexerCollection = require('./Indexers/IndexerCollection');
var IndexerSettingsModel = require('./Indexers/IndexerSettingsModel');
var NetImportSettingsModel = require("./NetImport/NetImportSettingsModel");
var NetImportCollection = require('./NetImport/NetImportCollection');
var ImportExclusionsCollection = require('./NetImport/ImportExclusionsCollection');
var NetImportLayout = require('./NetImport/NetImportLayout');
var DownloadClientLayout = require('./DownloadClient/DownloadClientLayout');
var DownloadClientSettingsModel = require('./DownloadClient/DownloadClientSettingsModel');