mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-04 10:02:40 +01:00
Merge branch 'feature/better-import-exclusions' into develop
This commit is contained in:
commit
b49f0e70ed
45
src/NzbDrone.Api/NetImport/ImportExclusionsModule.cs
Normal file
45
src/NzbDrone.Api/NetImport/ImportExclusionsModule.cs
Normal 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 });
|
||||
}
|
||||
}
|
||||
}
|
46
src/NzbDrone.Api/NetImport/ImportExclusionsResource.cs
Normal file
46
src/NzbDrone.Api/NetImport/ImportExclusionsResource.cs
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -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" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@ -80,5 +80,30 @@ public static List<TResult> SelectList<TSource, TResult>(this IEnumerable<TSourc
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@
|
||||
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 @@ public static void Map()
|
||||
.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")
|
||||
|
@ -16,6 +16,7 @@
|
||||
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 @@ public class SkyHookProxy : IProvideSeriesInfo, ISearchForNewSeries, IProvideMov
|
||||
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 @@ public SkyHookProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBu
|
||||
_configService = configService;
|
||||
_movieService = movieService;
|
||||
_predbService = predbService;
|
||||
_exclusionService = exclusionService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@ -351,7 +355,10 @@ public Movie GetMovieInfo(string imdbId)
|
||||
|
||||
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 @@ public List<Movie> DiscoverNewMovies(string action)
|
||||
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 @@ public List<Movie> DiscoverNewMovies(string action)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
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 @@ public class NetImportSearchService : IFetchNetImport, IExecute<NetImportSyncCom
|
||||
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 @@ public NetImportSearchService(INetImportFactory netImportFactory, IMovieService
|
||||
_nzbSearchService = nzbSearchService;
|
||||
_processDownloadDecisions = processDownloadDecisions;
|
||||
_rootFolder = rootFolder;
|
||||
_exclusionService = exclusionService;
|
||||
_logger = logger;
|
||||
_configService = configService;
|
||||
}
|
||||
@ -119,18 +124,12 @@ public void Execute(NetImportSyncCommand message)
|
||||
|
||||
|
||||
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};
|
||||
|
@ -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>
|
||||
|
@ -14,6 +14,7 @@
|
||||
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 @@ public class MovieService : IMovieService, IHandle<MovieFileAddedEvent>,
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IBuildFileNames _fileNameBuilder;
|
||||
private readonly IImportExclusionsService _exclusionService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
|
||||
@ -60,12 +62,14 @@ public MovieService(IMovieRepository movieRepository,
|
||||
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 @@ public void DeleteMovie(int movieId, bool deleteFiles, bool addExclusion = false
|
||||
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));
|
||||
|
@ -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() {
|
||||
|
5
src/UI/AddMovies/DiscoverEmptyView.js
Normal file
5
src/UI/AddMovies/DiscoverEmptyView.js
Normal file
@ -0,0 +1,5 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.CompositeView.extend({
|
||||
template : 'AddMovies/DiscoverEmptyViewTemplate'
|
||||
});
|
6
src/UI/AddMovies/DiscoverEmptyViewTemplate.hbs
Normal file
6
src/UI/AddMovies/DiscoverEmptyViewTemplate.hbs
Normal 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>
|
@ -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();
|
||||
|
@ -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}}
|
||||
|
@ -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);
|
||||
}
|
||||
|
24
src/UI/Settings/NetImport/DeleteExclusionCell.js
Normal file
24
src/UI/Settings/NetImport/DeleteExclusionCell.js
Normal 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();
|
||||
|
||||
}
|
||||
});
|
18
src/UI/Settings/NetImport/ExclusionTitleCell.js
Normal file
18
src/UI/Settings/NetImport/ExclusionTitleCell.js
Normal 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;
|
||||
}
|
||||
});
|
7
src/UI/Settings/NetImport/ImportExclusionModel.js
Normal file
7
src/UI/Settings/NetImport/ImportExclusionModel.js
Normal file
@ -0,0 +1,7 @@
|
||||
var Backbone = require('backbone');
|
||||
var _ = require('underscore');
|
||||
|
||||
module.exports = Backbone.Model.extend({
|
||||
urlRoot : window.NzbDrone.ApiRoot + '/exclusions',
|
||||
|
||||
});
|
9
src/UI/Settings/NetImport/ImportExclusionsCollection.js
Normal file
9
src/UI/Settings/NetImport/ImportExclusionsCollection.js
Normal 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();
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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>
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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');
|
||||
|
Loading…
Reference in New Issue
Block a user