diff --git a/.idea/Sonarr.iml b/.idea/Sonarr.iml
index aeec84bf6..fdd47ecb3 100644
--- a/.idea/Sonarr.iml
+++ b/.idea/Sonarr.iml
@@ -20,6 +20,5 @@
-
\ No newline at end of file
diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml
index b8387eb1b..8ca9d74b6 100644
--- a/.idea/jsLibraryMappings.xml
+++ b/.idea/jsLibraryMappings.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/libraries/Sonarr_node_modules.xml b/.idea/libraries/Sonarr_node_modules.xml
deleted file mode 100644
index 4eeebc5cc..000000000
--- a/.idea/libraries/Sonarr_node_modules.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/.idea/.idea.NzbDrone/.idea/.name b/src/.idea/.idea.NzbDrone/.idea/.name
new file mode 100644
index 000000000..37baec0ab
--- /dev/null
+++ b/src/.idea/.idea.NzbDrone/.idea/.name
@@ -0,0 +1 @@
+NzbDrone
\ No newline at end of file
diff --git a/src/.idea/.idea.NzbDrone/.idea/contentModel.xml b/src/.idea/.idea.NzbDrone/.idea/contentModel.xml
new file mode 100644
index 000000000..02cf7ea47
--- /dev/null
+++ b/src/.idea/.idea.NzbDrone/.idea/contentModel.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/.idea/.idea.NzbDrone/.idea/modules.xml b/src/.idea/.idea.NzbDrone/.idea/modules.xml
new file mode 100644
index 000000000..364561fe7
--- /dev/null
+++ b/src/.idea/.idea.NzbDrone/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/.idea/.idea.NzbDrone/riderModule.iml b/src/.idea/.idea.NzbDrone/riderModule.iml
new file mode 100644
index 000000000..c84a9c732
--- /dev/null
+++ b/src/.idea/.idea.NzbDrone/riderModule.iml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NzbDrone.Api/Config/IndexerConfigResource.cs b/src/NzbDrone.Api/Config/IndexerConfigResource.cs
index 39bb43b74..884e2e839 100644
--- a/src/NzbDrone.Api/Config/IndexerConfigResource.cs
+++ b/src/NzbDrone.Api/Config/IndexerConfigResource.cs
@@ -1,5 +1,6 @@
using NzbDrone.Api.REST;
using NzbDrone.Core.Configuration;
+using NzbDrone.Core.Parser;
namespace NzbDrone.Api.Config
{
@@ -12,6 +13,7 @@ namespace NzbDrone.Api.Config
public int AvailabilityDelay { get; set; }
public bool AllowHardcodedSubs { get; set; }
public string WhitelistedHardcodedSubs { get; set; }
+ public ParsingLeniencyType ParsingLeniency { get; set; }
}
public static class IndexerConfigResourceMapper
@@ -27,7 +29,7 @@ namespace NzbDrone.Api.Config
AvailabilityDelay = model.AvailabilityDelay,
AllowHardcodedSubs = model.AllowHardcodedSubs,
WhitelistedHardcodedSubs = model.WhitelistedHardcodedSubs,
-
+ ParsingLeniency = model.ParsingLeniency,
};
}
}
diff --git a/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs b/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs
index 7157c4399..94985738b 100644
--- a/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs
+++ b/src/NzbDrone.Api/Movies/MovieBulkImportModule.cs
@@ -90,7 +90,7 @@ namespace NzbDrone.Api.Movie
return mappedMovie;
}
- var parsedTitle = Parser.ParseMoviePath(f.Name);
+ var parsedTitle = Parser.ParseMoviePath(f.Name, false);
if (parsedTitle == null)
{
m = new Core.Tv.Movie
diff --git a/src/NzbDrone.Core.Test/ParserTests/LanguageParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/LanguageParserFixture.cs
index e9624b153..9c0e75a1a 100644
--- a/src/NzbDrone.Core.Test/ParserTests/LanguageParserFixture.cs
+++ b/src/NzbDrone.Core.Test/ParserTests/LanguageParserFixture.cs
@@ -51,9 +51,12 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Castle.2009.S01E14.HDTV.XviD.HUN-LOL", Language.Hungarian)]
[TestCase("The Danish Girl 2015", Language.English)]
[TestCase("Passengers.2016.German.DL.AC3.Dubbed.1080p.WebHD.h264.iNTERNAL-PsO", Language.German)]
+ [TestCase("Der.Soldat.James.German.Bluray.FuckYou.Pso.Why.cant.you.follow.scene.rules.1998", Language.German)]
+ [TestCase("Passengers.German.DL.AC3.Dubbed..BluRay.x264-PsO", Language.German)]
+ [TestCase("Valana la Legende FRENCH BluRay 720p 2016 kjhlj", Language.French)]
public void should_parse_language(string postTitle, Language language)
{
- var result = Parser.Parser.ParseMovieTitle(postTitle);
+ var result = Parser.Parser.ParseMovieTitle(postTitle, true);
if (result == null)
{
Parser.Parser.ParseTitle(postTitle).Language.Should().Be(language);
diff --git a/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs
index 1feea9f4d..77736d7c5 100644
--- a/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs
+++ b/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs
@@ -63,6 +63,7 @@ namespace NzbDrone.Core.Test.ParserTests
Parser.Parser.ParseTitle(postTitle).SeriesTitle.Should().Be(title);
}
+ //Note: This assumes extended language parser is activated
[TestCase("The.Man.from.U.N.C.L.E.2015.1080p.BluRay.x264-SPARKS", "The Man from U.N.C.L.E.")]
[TestCase("1941.1979.EXTENDED.720p.BluRay.X264-AMIABLE", "1941")]
[TestCase("MY MOVIE (2016) [R][Action, Horror][720p.WEB-DL.AVC.8Bit.6ch.AC3].mkv", "MY MOVIE")]
@@ -76,22 +77,29 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("A.Movie.Name.(1998)", "A Movie Name")]
[TestCase("Thor: The Dark World 2013", "Thor The Dark World")]
[TestCase("Resident.Evil.The.Final.Chapter.2016", "Resident Evil The Final Chapter")]
+ [TestCase("Der.Soldat.James.German.Bluray.FuckYou.Pso.Why.cant.you.follow.scene.rules.1998", "Der Soldat James")]
+ [TestCase("Passengers.German.DL.AC3.Dubbed..BluRay.x264-PsO", "Passengers")]
+ [TestCase("Valana la Legende FRENCH BluRay 720p 2016 kjhlj", "Valana la Legende")]
+ [TestCase("Valana la Legende TRUEFRENCH BluRay 720p 2016 kjhlj", "Valana la Legende")]
+ [TestCase("Mission Impossible: Rogue Nation (2015)�[XviD - Ita Ac3 - SoftSub Ita]azione, spionaggio, thriller *Prima Visione* Team mulnic Tom Cruise", "Mission Impossible Rogue Nation")]
public void should_parse_movie_title(string postTitle, string title)
{
- Parser.Parser.ParseMovieTitle(postTitle).MovieTitle.Should().Be(title);
+ Parser.Parser.ParseMovieTitle(postTitle, true).MovieTitle.Should().Be(title);
}
[TestCase("1941.1979.EXTENDED.720p.BluRay.X264-AMIABLE", 1979)]
+ [TestCase("Valana la Legende FRENCH BluRay 720p 2016 kjhlj", 2016)]
+ [TestCase("Der.Soldat.James.German.Bluray.FuckYou.Pso.Why.cant.you.follow.scene.rules.1998", 1998)]
public void should_parse_movie_year(string postTitle, int year)
{
- Parser.Parser.ParseMovieTitle(postTitle).Year.Should().Be(year);
+ Parser.Parser.ParseMovieTitle(postTitle, false).Year.Should().Be(year);
}
[TestCase("The Danish Girl 2015")]
[TestCase("The.Danish.Girl.2015.1080p.BluRay.x264.DTS-HD.MA.5.1-RARBG")]
public void should_not_parse_language_in_movie_title(string postTitle)
{
- Parser.Parser.ParseMovieTitle(postTitle).Language.Should().Be(Language.English);
+ Parser.Parser.ParseMovieTitle(postTitle, false).Language.Should().Be(Language.English);
}
[TestCase("Prometheus 2012 Directors Cut", "Directors Cut")]
@@ -117,9 +125,9 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Prometheus Extended Directors Cut Fan Edit 2012", "Extended Directors Cut Fan Edit")]
[TestCase("Prometheus Director's Cut 2012", "Director's Cut")]
[TestCase("Prometheus Directors Cut 2012", "Directors Cut")]
- [TestCase("Prometheus.(Extended.Theatrical.Version.IMAX).BluRay.1080p.2012.asdf", "Extended Theatrical Version IMAX")]
+ [TestCase("Prometheus.(Extended.Theatrical.Version.IMAX).2012.BluRay.1080p.asdf", "Extended Theatrical Version IMAX")]
[TestCase("2001 A Space Odyssey Director's Cut (1968).mkv", "Director's Cut")]
- [TestCase("2001: A Space Odyssey (Extended Directors Cut FanEdit) Bluray 1080p 1968", "Extended Directors Cut FanEdit")]
+ [TestCase("2001: A Space Odyssey (Extended Directors Cut FanEdit) 1968 Bluray 1080p", "Extended Directors Cut FanEdit")]
[TestCase("A Fake Movie 2035 Directors 2012.mkv", "Directors")]
[TestCase("Blade Runner Director's Cut 2049.mkv", "Director's Cut")]
[TestCase("Prometheus 50th Anniversary Edition 2012.mkv", "50th Anniversary Edition")]
@@ -129,7 +137,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Fake Movie 2016 Final Cut ", "Final Cut")]
public void should_parse_edition(string postTitle, string edition)
{
- Parser.Parser.ParseMovieTitle(postTitle).Edition.Should().Be(edition);
+ Parser.Parser.ParseMovieTitle(postTitle, false).Edition.Should().Be(edition);
}
}
}
diff --git a/src/NzbDrone.Core.Test/ParserTests/RomanNumeralTests/RomanNumeralConversionFixture.cs b/src/NzbDrone.Core.Test/ParserTests/RomanNumeralTests/RomanNumeralConversionFixture.cs
index 348ec221f..9b86f6811 100644
--- a/src/NzbDrone.Core.Test/ParserTests/RomanNumeralTests/RomanNumeralConversionFixture.cs
+++ b/src/NzbDrone.Core.Test/ParserTests/RomanNumeralTests/RomanNumeralConversionFixture.cs
@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Test.ParserTests.RomanNumeralTests
[Test(Description = "Converts the supported range [1-3999] of Arabic to Roman numerals.")]
[Order(0)]
- public void should_convert_arabic_numeral_to_roman_numeral([Range(1,3999)] int arabicNumeral)
+ public void should_convert_arabic_numeral_to_roman_numeral([Range(1,20)] int arabicNumeral)
{
RomanNumeral romanNumeral = new RomanNumeral(arabicNumeral);
@@ -39,7 +39,7 @@ namespace NzbDrone.Core.Test.ParserTests.RomanNumeralTests
[Test]
[Order(1)]
- public void should_convert_roman_numeral_to_arabic_numeral([Range(1, 3999)] int arabicNumeral)
+ public void should_convert_roman_numeral_to_arabic_numeral([Range(1, 20)] int arabicNumeral)
{
RomanNumeral romanNumeral = new RomanNumeral(_arabicToRomanNumeralsMapping[arabicNumeral]);
diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs
index f25ae165d..ad7e3430a 100644
--- a/src/NzbDrone.Core/Configuration/ConfigService.cs
+++ b/src/NzbDrone.Core/Configuration/ConfigService.cs
@@ -8,6 +8,7 @@ using NzbDrone.Core.Configuration.Events;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Common.Http.Proxy;
+using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Configuration
{
@@ -211,6 +212,12 @@ namespace NzbDrone.Core.Configuration
set { SetValue("WhitelistedHardcodedSubs", value); }
}
+ public ParsingLeniencyType ParsingLeniency
+ {
+ get { return GetValueEnum("ParsingLeniency", ParsingLeniencyType.Strict); }
+ set { SetValue("ParsingLeniency", value); }
+ }
+
public bool RemoveCompletedDownloads
{
get { return GetValueBoolean("RemoveCompletedDownloads", false); }
diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs
index 08a1c0572..4292c0f89 100644
--- a/src/NzbDrone.Core/Configuration/IConfigService.cs
+++ b/src/NzbDrone.Core/Configuration/IConfigService.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Common.Http.Proxy;
+using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Configuration
{
@@ -54,6 +55,7 @@ namespace NzbDrone.Core.Configuration
bool AllowHardcodedSubs { get; set; }
string WhitelistedHardcodedSubs { get; set; }
+ ParsingLeniencyType ParsingLeniency { get; set; }
int NetImportSyncInterval { get; set; }
string ListSyncLevel { get; set; }
diff --git a/src/NzbDrone.Core/Datastore/Migration/117_update_movie_file.cs b/src/NzbDrone.Core/Datastore/Migration/117_update_movie_file.cs
index ee1db828d..b4a1011a7 100644
--- a/src/NzbDrone.Core/Datastore/Migration/117_update_movie_file.cs
+++ b/src/NzbDrone.Core/Datastore/Migration/117_update_movie_file.cs
@@ -26,13 +26,13 @@ namespace NzbDrone.Core.Datastore.Migration
var id = seriesReader.GetInt32(0);
var relativePath = seriesReader.GetString(1);
- var result = Parser.Parser.ParseMovieTitle(relativePath);
+ var result = Parser.Parser.ParseMovieTitle(relativePath, false);
var edition = "";
if (result != null)
{
- edition = Parser.Parser.ParseMovieTitle(relativePath).Edition;
+ edition = Parser.Parser.ParseMovieTitle(relativePath, false).Edition;
}
using (IDbCommand updateCmd = conn.CreateCommand())
diff --git a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs
index 910cad30b..e205e4e61 100644
--- a/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs
+++ b/src/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs
@@ -69,7 +69,7 @@ namespace NzbDrone.Core.DecisionEngine
try
{
- var parsedMovieInfo = Parser.Parser.ParseMovieTitle(report.Title);
+ var parsedMovieInfo = Parser.Parser.ParseMovieTitle(report.Title, _configService.ParsingLeniency > 0);
if (parsedMovieInfo != null && !parsedMovieInfo.MovieTitle.IsNullOrWhiteSpace())
{
diff --git a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs
index 575c3bfbc..ff82b1688 100644
--- a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs
+++ b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs
@@ -3,6 +3,7 @@ using System.Linq;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
+using NzbDrone.Core.Configuration;
using NzbDrone.Core.History;
using NzbDrone.Core.Parser;
@@ -18,17 +19,20 @@ namespace NzbDrone.Core.Download.TrackedDownloads
{
private readonly IParsingService _parsingService;
private readonly IHistoryService _historyService;
+ private readonly IConfigService _config;
private readonly Logger _logger;
private readonly ICached _cache;
public TrackedDownloadService(IParsingService parsingService,
ICacheManager cacheManager,
IHistoryService historyService,
+ IConfigService config,
Logger logger)
{
_parsingService = parsingService;
_historyService = historyService;
_cache = cacheManager.GetCache(GetType());
+ _config = config;
_logger = logger;
}
@@ -56,7 +60,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
try
{
- var parsedMovieInfo = Parser.Parser.ParseMovieTitle(trackedDownload.DownloadItem.Title);
+ var parsedMovieInfo = Parser.Parser.ParseMovieTitle(trackedDownload.DownloadItem.Title, _config.ParsingLeniency > 0);
var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId);
if (parsedMovieInfo != null)
@@ -73,7 +77,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
trackedDownload.RemoteMovie == null ||
trackedDownload.RemoteMovie.Movie == null)
{
- parsedMovieInfo = Parser.Parser.ParseMovieTitle(firstHistoryItem.SourceTitle);
+ parsedMovieInfo = Parser.Parser.ParseMovieTitle(firstHistoryItem.SourceTitle, _config.ParsingLeniency > 0);
if (parsedMovieInfo != null)
{
diff --git a/src/NzbDrone.Core/MediaFiles/DownloadedMovieImportService.cs b/src/NzbDrone.Core/MediaFiles/DownloadedMovieImportService.cs
index 0367dbe19..c75020b77 100644
--- a/src/NzbDrone.Core/MediaFiles/DownloadedMovieImportService.cs
+++ b/src/NzbDrone.Core/MediaFiles/DownloadedMovieImportService.cs
@@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Common.Disk;
+using NzbDrone.Core.Configuration;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Parser;
@@ -29,6 +30,7 @@ namespace NzbDrone.Core.MediaFiles
private readonly IMakeImportDecision _importDecisionMaker;
private readonly IImportApprovedMovie _importApprovedMovie;
private readonly IDetectSample _detectSample;
+ private readonly IConfigService _config;
private readonly Logger _logger;
public DownloadedMovieImportService(IDiskProvider diskProvider,
@@ -38,6 +40,7 @@ namespace NzbDrone.Core.MediaFiles
IMakeImportDecision importDecisionMaker,
IImportApprovedMovie importApprovedMovie,
IDetectSample detectSample,
+ IConfigService config,
Logger logger)
{
_diskProvider = diskProvider;
@@ -47,6 +50,7 @@ namespace NzbDrone.Core.MediaFiles
_importDecisionMaker = importDecisionMaker;
_importApprovedMovie = importApprovedMovie;
_detectSample = detectSample;
+ _config = config;
_logger = logger;
}
@@ -160,7 +164,7 @@ namespace NzbDrone.Core.MediaFiles
}
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
- var folderInfo = Parser.Parser.ParseMovieTitle(directoryInfo.Name);
+ var folderInfo = Parser.Parser.ParseMovieTitle(directoryInfo.Name, _config.ParsingLeniency > 0);
if (folderInfo != null)
{
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedMovie.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedMovie.cs
index d15b8dacf..5187f4017 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedMovie.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedMovie.cs
@@ -154,7 +154,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
{
var title = Parser.Parser.RemoveFileExtension(downloadClientItem.Title);
- var parsedTitle = Parser.Parser.ParseMovieTitle(title);
+ var parsedTitle = Parser.Parser.ParseMovieTitle(title, false);
if (parsedTitle != null)
{
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs
index 1f117b525..d3bf2e99f 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Manual/ManualImportService.cs
@@ -6,6 +6,7 @@ using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation.Extensions;
+using NzbDrone.Core.Configuration;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.TrackedDownloads;
@@ -38,6 +39,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
private readonly ITrackedDownloadService _trackedDownloadService;
private readonly IDownloadedMovieImportService _downloadedMovieImportService;
private readonly IEventAggregator _eventAggregator;
+ private readonly IConfigService _config;
private readonly Logger _logger;
public ManualImportService(IDiskProvider diskProvider,
@@ -53,6 +55,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
ITrackedDownloadService trackedDownloadService,
IDownloadedMovieImportService downloadedMovieImportService,
IEventAggregator eventAggregator,
+ IConfigService config,
Logger logger)
{
_diskProvider = diskProvider;
@@ -68,6 +71,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
_trackedDownloadService = trackedDownloadService;
_downloadedMovieImportService = downloadedMovieImportService;
_eventAggregator = eventAggregator;
+ _config = config;
_logger = logger;
}
@@ -116,7 +120,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
return files.Select(file => ProcessFile(file, downloadId, folder)).Where(i => i != null).ToList();
}
- var folderInfo = Parser.Parser.ParseMovieTitle(directoryInfo.Name);
+ var folderInfo = Parser.Parser.ParseMovieTitle(directoryInfo.Name, _config.ParsingLeniency > 0);
var seriesFiles = _diskScanService.GetVideoFiles(folder).ToList();
var decisions = _importDecisionMaker.GetImportDecisions(seriesFiles, series, folderInfo, SceneSource(series, folder), false);
@@ -282,7 +286,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
var file = message.Files[i];
var movie = _movieService.GetMovie(file.MovieId);
- var parsedMovieInfo = Parser.Parser.ParseMoviePath(file.Path) ?? new ParsedMovieInfo();
+ var parsedMovieInfo = Parser.Parser.ParseMoviePath(file.Path, _config.ParsingLeniency > 0) ?? new ParsedMovieInfo();
var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path);
var existingFile = movie.Path.IsParentPath(file.Path);
diff --git a/src/NzbDrone.Core/MetadataSource/PreDB/PreDBService.cs b/src/NzbDrone.Core/MetadataSource/PreDB/PreDBService.cs
index 68b3b3383..e32294add 100644
--- a/src/NzbDrone.Core/MetadataSource/PreDB/PreDBService.cs
+++ b/src/NzbDrone.Core/MetadataSource/PreDB/PreDBService.cs
@@ -119,7 +119,7 @@ namespace NzbDrone.Core.MetadataSource.PreDB
foreach (PreDBResult result in results)
{
- var parsedInfo = Parser.Parser.ParseMovieTitle(result.Title);
+ var parsedInfo = Parser.Parser.ParseMovieTitle(result.Title, true);
if (parsedInfo != null)
{
@@ -178,7 +178,7 @@ namespace NzbDrone.Core.MetadataSource.PreDB
foreach (PreDBResult result in results)
{
- var parsed = Parser.Parser.ParseMovieTitle(result.Title);
+ var parsed = Parser.Parser.ParseMovieTitle(result.Title, true);
if (parsed == null)
{
parsed = new Parser.Model.ParsedMovieInfo { MovieTitle = result.Title, Year = 0 };
diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs
index f6db9011f..7ad1f82be 100644
--- a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs
+++ b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs
@@ -414,7 +414,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
lowerTitle = lowerTitle.Replace(".", "");
- var parserResult = Parser.Parser.ParseMovieTitle(title, true);
+ var parserResult = Parser.Parser.ParseMovieTitle(title, true, true);
var yearTerm = "";
diff --git a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs b/src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs
index b874fefd5..e6dee4a25 100644
--- a/src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs
+++ b/src/NzbDrone.Core/NetImport/RSSImport/RSSImportParser.cs
@@ -141,7 +141,7 @@ namespace NzbDrone.Core.NetImport.RSSImport
}
releaseInfo.Title = title;
- var result = Parser.Parser.ParseMovieTitle(title);
+ var result = Parser.Parser.ParseMovieTitle(title, false);//Depreciated anyways
if (result != null)
{
diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj
index 49dfc097a..2b4e26eb8 100644
--- a/src/NzbDrone.Core/NzbDrone.Core.csproj
+++ b/src/NzbDrone.Core/NzbDrone.Core.csproj
@@ -997,6 +997,7 @@
+
@@ -1381,4 +1382,4 @@
-->
-
+
\ No newline at end of file
diff --git a/src/NzbDrone.Core/Organizer/FileNameValidationService.cs b/src/NzbDrone.Core/Organizer/FileNameValidationService.cs
index 697f72bbb..ef2230c45 100644
--- a/src/NzbDrone.Core/Organizer/FileNameValidationService.cs
+++ b/src/NzbDrone.Core/Organizer/FileNameValidationService.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using FluentValidation.Results;
+using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
@@ -21,7 +22,7 @@ namespace NzbDrone.Core.Organizer
public ValidationFailure ValidateMovieFilename(SampleResult sampleResult)
{
var validationFailure = new ValidationFailure("MovieFormat", ERROR_MESSAGE);
- var parsedMovieInfo = Parser.Parser.ParseMovieTitle(sampleResult.FileName);
+ var parsedMovieInfo = Parser.Parser.ParseMovieTitle(sampleResult.FileName, false); //We are not lenient when testing naming schemes
if(parsedMovieInfo == null)
{
diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs
index e9504fd96..c23b8441b 100644
--- a/src/NzbDrone.Core/Parser/Parser.cs
+++ b/src/NzbDrone.Core/Parser/Parser.cs
@@ -7,8 +7,10 @@ using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation;
+using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
+using TinyIoC;
namespace NzbDrone.Core.Parser
{
@@ -19,16 +21,16 @@ namespace NzbDrone.Core.Parser
private static readonly Regex[] ReportMovieTitleRegex = new[]
{
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.Special.Edition.2011
- new Regex(@"^(?(?![(\[]).+?)?(?:(?:[-_\W](?(((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final(?=(.(Cut|Edition|Version)))|Extended|Rogue|Special|Despecialized|\d{2,3}(th)?.Anniversary)(.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit|Edition|Restored|((2|3|4)in1))))))\)?.+(?(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
+ new Regex(@"^(?(?![(\[]).+?)?(?:(?:[-_\W](?(((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final(?=(.(Cut|Edition|Version)))|Extended|Rogue|Special|Despecialized|\d{2,3}(th)?.Anniversary)(.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit|Edition|Restored|((2|3|4)in1))))))\)?.{1,3}(?(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.2011.Special.Edition //TODO: Seems to slow down parsing heavily!
new Regex(@"^(?(?![(\[]).+?)?(?:(?:[-_\W](?(19|20)\d{2}(?!p|i|(19|20)\d{2}|\]|\W(19|20)\d{2})))+(\W+|_|$)(?!\\)\(?(?(((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final(?=(.(Cut|Edition|Version)))|Extended|Rogue|Special|Despecialized|\d{2,3}(th)?.Anniversary)(.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit|Edition|Restored|((2|3|4)in1))))))\)?",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
-
+
//Normal movie format, e.g: Mission.Impossible.3.2011
new Regex(@"^(?(?![(\[]).+?)?(?:(?:[-_\W](?(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled),
-
+
//PassThePopcorn Torrent names: Star.Wars[PassThePopcorn]
new Regex(@"^(?.+?)?(?:(?:[-_\W](?(\[\w *\])))+(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled),
@@ -45,6 +47,17 @@ namespace NzbDrone.Core.Parser
//When year comes first.
new Regex(@"^(?:(?:[-_\W](?(19|20)\d{2}(?!p|i|\d+|\W\d+)))+(\W+|_|$)(?.+?)?$")
};
+
+ private static readonly Regex[] ReportMovieTitleLenientRegexBefore = new[]
+ {
+ //Some german or french tracker formats
+ new Regex(@"^(?(?![(\[]).+?)((\W|_))(?:(German|French|TrueFrench))(.+?)(?=((19|20)\d{2}|$))(?(19|20)\d{2}(?!p|i|\d+|\]|\W\d+))?(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled),
+ };
+
+ private static readonly Regex[] ReportMovieTitleLenientRegexAfter = new Regex[]
+ {
+
+ };
private static readonly Regex[] ReportTitleRegex = new[]
{
@@ -338,29 +351,29 @@ namespace NzbDrone.Core.Parser
return result;
}
- public static ParsedMovieInfo ParseMoviePath(string path)
+ public static ParsedMovieInfo ParseMoviePath(string path, bool isLenient)
{
var fileInfo = new FileInfo(path);
- var result = ParseMovieTitle(fileInfo.Name, true);
+ var result = ParseMovieTitle(fileInfo.Name, isLenient, true);
if (result == null)
{
Logger.Debug("Attempting to parse episode info using directory and file names. {0}", fileInfo.Directory.Name);
- result = ParseMovieTitle(fileInfo.Directory.Name + " " + fileInfo.Name);
+ result = ParseMovieTitle(fileInfo.Directory.Name + " " + fileInfo.Name, isLenient);
}
if (result == null)
{
Logger.Debug("Attempting to parse episode info using directory name. {0}", fileInfo.Directory.Name);
- result = ParseMovieTitle(fileInfo.Directory.Name + fileInfo.Extension);
+ result = ParseMovieTitle(fileInfo.Directory.Name + fileInfo.Extension, isLenient);
}
return result;
}
- public static ParsedMovieInfo ParseMovieTitle(string title, bool isDir = false)
+ public static ParsedMovieInfo ParseMovieTitle(string title, bool isLenient, bool isDir = false)
{
ParsedMovieInfo realResult = null;
@@ -368,8 +381,6 @@ namespace NzbDrone.Core.Parser
{
if (!ValidateBeforeParsing(title)) return null;
- //title = title.Replace(" ", "."); //TODO: Determine if this breaks something. However, it shouldn't.
-
Logger.Debug("Parsing string '{0}'", title);
if (ReversedTitleRegex.IsMatch(title))
@@ -398,6 +409,13 @@ namespace NzbDrone.Core.Parser
allRegexes.AddRange(ReportMovieTitleFolderRegex);
}
+ if (isLenient)
+ {
+ allRegexes.InsertRange(0, ReportMovieTitleLenientRegexBefore);
+
+ allRegexes.AddRange(ReportMovieTitleLenientRegexAfter);
+ }
+
foreach (var regex in allRegexes)
{
var match = regex.Matches(simpleTitle);
diff --git a/src/NzbDrone.Core/Parser/ParsingLeniency.cs b/src/NzbDrone.Core/Parser/ParsingLeniency.cs
new file mode 100644
index 000000000..188c6bc47
--- /dev/null
+++ b/src/NzbDrone.Core/Parser/ParsingLeniency.cs
@@ -0,0 +1,9 @@
+namespace NzbDrone.Core.Parser
+{
+ public enum ParsingLeniencyType
+ {
+ Strict = 0,
+ ParsingLenient = 1,
+ MappingLenient = 2,
+ }
+}
diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs
index de9fa4e05..1f27d6a0d 100644
--- a/src/NzbDrone.Core/Parser/ParsingService.cs
+++ b/src/NzbDrone.Core/Parser/ParsingService.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Common.Extensions;
+using NzbDrone.Core.Configuration;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.MediaFiles;
@@ -34,6 +35,7 @@ namespace NzbDrone.Core.Parser
private readonly ISeriesService _seriesService;
private readonly ISceneMappingService _sceneMappingService;
private readonly IMovieService _movieService;
+ private readonly IConfigService _config;
private readonly Logger _logger;
private static HashSet _arabicRomanNumeralMappings;
@@ -42,12 +44,14 @@ namespace NzbDrone.Core.Parser
ISeriesService seriesService,
ISceneMappingService sceneMappingService,
IMovieService movieService,
+ IConfigService configService,
Logger logger)
{
_episodeService = episodeService;
_seriesService = seriesService;
_sceneMappingService = sceneMappingService;
_movieService = movieService;
+ _config = configService;
_logger = logger;
if (_arabicRomanNumeralMappings == null)
@@ -127,7 +131,7 @@ namespace NzbDrone.Core.Parser
else
{
- parsedMovieInfo = Parser.ParseMoviePath(filename);
+ parsedMovieInfo = Parser.ParseMoviePath(filename, _config.ParsingLeniency > 0);
}
if (parsedMovieInfo == null)
@@ -172,7 +176,7 @@ namespace NzbDrone.Core.Parser
public Movie GetMovie(string title)
{
- var parsedMovieInfo = Parser.ParseMovieTitle(title);
+ var parsedMovieInfo = Parser.ParseMovieTitle(title, _config.ParsingLeniency > 0);
if (parsedMovieInfo == null)
{
diff --git a/src/NzbDrone.Core/Parser/SceneChecker.cs b/src/NzbDrone.Core/Parser/SceneChecker.cs
index d53cd8960..9bc7e3890 100644
--- a/src/NzbDrone.Core/Parser/SceneChecker.cs
+++ b/src/NzbDrone.Core/Parser/SceneChecker.cs
@@ -9,7 +9,7 @@
if (!title.Contains(".")) return false;
if (title.Contains(" ")) return false;
- var parsedTitle = Parser.ParseMovieTitle(title);
+ var parsedTitle = Parser.ParseMovieTitle(title, false); //We are not lenient when it comes to scene checking!
if (parsedTitle == null ||
parsedTitle.ReleaseGroup == null ||
diff --git a/src/UI/.idea/runConfigurations/Debug___Chrome.xml b/src/UI/.idea/runConfigurations/Debug___Chrome.xml
index 47bd06dc9..61758c015 100644
--- a/src/UI/.idea/runConfigurations/Debug___Chrome.xml
+++ b/src/UI/.idea/runConfigurations/Debug___Chrome.xml
@@ -1,21 +1,17 @@
-
-
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
diff --git a/src/UI/.idea/runConfigurations/Debug___Firefox.xml b/src/UI/.idea/runConfigurations/Debug___Firefox.xml
deleted file mode 100644
index d9e99acc3..000000000
--- a/src/UI/.idea/runConfigurations/Debug___Firefox.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/UI/Settings/Indexers/Options/IndexerOptionsView.js b/src/UI/Settings/Indexers/Options/IndexerOptionsView.js
index 190920b79..bb859dffe 100644
--- a/src/UI/Settings/Indexers/Options/IndexerOptionsView.js
+++ b/src/UI/Settings/Indexers/Options/IndexerOptionsView.js
@@ -9,7 +9,8 @@ var view = Marionette.ItemView.extend({
template : 'Settings/Indexers/Options/IndexerOptionsViewTemplate',
ui : {
- hcwhitelist : '.x-hcwhitelist',
+ hcwhitelist : '.x-hcwhitelist',
+ leniencyTooltip : '.x-leniency-tooltip',
},
onRender : function() {
@@ -18,6 +19,18 @@ var view = Marionette.ItemView.extend({
allowDuplicates: true,
tagClass : 'label label-success'
});
+
+ this.templateFunction = Marionette.TemplateCache.get('Settings/Indexers/Options/LeniencyTooltipTemplate');
+ var content = this.templateFunction();
+
+ this.ui.leniencyTooltip.popover({
+ content : content,
+ html : true,
+ trigger : 'hover',
+ title : 'Parsing Leniency Notes',
+ placement : 'right',
+ container : this.$el
+ });
},
});
diff --git a/src/UI/Settings/Indexers/Options/IndexerOptionsViewTemplate.hbs b/src/UI/Settings/Indexers/Options/IndexerOptionsViewTemplate.hbs
index 16736cc7d..b43975d1a 100644
--- a/src/UI/Settings/Indexers/Options/IndexerOptionsViewTemplate.hbs
+++ b/src/UI/Settings/Indexers/Options/IndexerOptionsViewTemplate.hbs
@@ -91,6 +91,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/UI/Settings/Indexers/Options/LeniencyTooltipTemplate.hbs b/src/UI/Settings/Indexers/Options/LeniencyTooltipTemplate.hbs
new file mode 100644
index 000000000..5c4b7ffcd
--- /dev/null
+++ b/src/UI/Settings/Indexers/Options/LeniencyTooltipTemplate.hbs
@@ -0,0 +1,7 @@
+How strict the Parser should be. (Note: Strict is strongly recommended!)
+
+Strict: Just as before, year must immediately follow title.
+
+Lenient Parsing: Either year or language tag must immediately follow after title. (Note: May prevent Movies with language tags in title - e.g. The Danish Girl - from being parsed correctly)
+
+Lenient Mapping: Includes Lenient Parsing. When title cannot be found Try mapping just parts of the title. (Useful when no year is present / not after title. NOT IMPLEMENTED YET)
\ No newline at end of file