Added: Options to make parsing more lenient. (Adds support for some german and french releasegroups) (#1692)

Fixes #1676. Fixes #1632.
pull/2/head
Leonardo Galli 7 years ago committed by GitHub
parent 5238b78813
commit d6cf53e12c

@ -20,6 +20,5 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Sonarr node_modules" level="project" />
</component> </component>
</module> </module>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="JavaScriptLibraryMappings"> <component name="JavaScriptLibraryMappings">
<includedPredefinedLibrary name="ECMAScript 6" /> <excludedPredefinedLibrary name="Radarr/node_modules" />
</component> </component>
</project> </project>

@ -1,14 +0,0 @@
<component name="libraryTable">
<library name="Sonarr node_modules" type="javaScript">
<properties>
<option name="frameworkName" value="node_modules" />
<sourceFilesUrls>
<item url="file://$PROJECT_DIR$/node_modules" />
</sourceFilesUrls>
</properties>
<CLASSES>
<root url="file://$PROJECT_DIR$/node_modules" />
</CLASSES>
<SOURCES />
</library>
</component>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RiderRiderContentModelStore">
<excludedPaths />
</component>
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.NzbDrone/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.NzbDrone/riderModule.iml" />
</modules>
</component>
</project>

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RIDER_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$/../../../Logo/1024.png">
<sourceFolder url="file://$MODULE_DIR$/../../../Logo/1024.png" isTestSource="false" />
</content>
<content url="file://$MODULE_DIR$/../../../Logo/64.png">
<sourceFolder url="file://$MODULE_DIR$/../../../Logo/64.png" isTestSource="false" />
</content>
<content url="file://$MODULE_DIR$/../..">
<sourceFolder url="file://$MODULE_DIR$/../../.nuget/NuGet.exe" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../Common/CommonAssemblyInfo.cs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../Common/CommonVersionInfo.cs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../Common/GlobalSuppressions.cs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../ExternalModules/CurlSharp/CurlSharp" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../Libraries/MediaInfo/libmediainfo.0.dylib" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../Libraries/MediaInfo/MediaInfo.dll" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../Libraries/Sqlite/libsqlite3.0.dylib" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../Libraries/Sqlite/sqlite3.dll" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../LogentriesCore" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../LogentriesNLog" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../Marr.Data" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Core" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Owin" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../MonoTorrent" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Api" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Api.Test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.App.Test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Automation.Test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Common" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Common.Test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Console" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Core" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Core.Test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Host" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Integration.Test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Libraries.Test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Mono" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Mono.Test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.SignalR" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Common" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Dummy" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Update" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Update.Test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Windows" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Windows.Test" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../ServiceHelpers/ServiceInstall" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../ServiceHelpers/ServiceUninstall" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/../../ExternalModules/CurlSharp/CurlSharp/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../ExternalModules/CurlSharp/CurlSharp/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../LogentriesCore/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../LogentriesCore/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../LogentriesNLog/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../LogentriesNLog/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../Marr.Data/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Core/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Core/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Owin/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Owin/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../MonoTorrent/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Api.Test/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Api.Test/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Api/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.App.Test/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.App.Test/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Automation.Test/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Automation.Test/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Common.Test/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Common.Test/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Common/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Console/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Core.Test/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Core.Test/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Core/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Host/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Integration.Test/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Integration.Test/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Libraries.Test/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Libraries.Test/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Mono.Test/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Mono.Test/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Mono/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.SignalR/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Common/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Common/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Dummy/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Dummy/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Update.Test/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Update.Test/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Update/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Windows.Test/bin" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Windows.Test/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Windows/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../ServiceHelpers/ServiceInstall/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../ServiceHelpers/ServiceUninstall/obj" />
<excludeFolder url="file://$MODULE_DIR$/../../_ReSharper.Caches/ReSharperHost8.NzbDrone.00" />
<excludeFolder url="file://$MODULE_DIR$/../../packages" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -1,5 +1,6 @@
using NzbDrone.Api.REST; using NzbDrone.Api.REST;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser;
namespace NzbDrone.Api.Config namespace NzbDrone.Api.Config
{ {
@ -12,6 +13,7 @@ namespace NzbDrone.Api.Config
public int AvailabilityDelay { get; set; } public int AvailabilityDelay { get; set; }
public bool AllowHardcodedSubs { get; set; } public bool AllowHardcodedSubs { get; set; }
public string WhitelistedHardcodedSubs { get; set; } public string WhitelistedHardcodedSubs { get; set; }
public ParsingLeniencyType ParsingLeniency { get; set; }
} }
public static class IndexerConfigResourceMapper public static class IndexerConfigResourceMapper
@ -27,7 +29,7 @@ namespace NzbDrone.Api.Config
AvailabilityDelay = model.AvailabilityDelay, AvailabilityDelay = model.AvailabilityDelay,
AllowHardcodedSubs = model.AllowHardcodedSubs, AllowHardcodedSubs = model.AllowHardcodedSubs,
WhitelistedHardcodedSubs = model.WhitelistedHardcodedSubs, WhitelistedHardcodedSubs = model.WhitelistedHardcodedSubs,
ParsingLeniency = model.ParsingLeniency,
}; };
} }
} }

@ -90,7 +90,7 @@ namespace NzbDrone.Api.Movie
return mappedMovie; return mappedMovie;
} }
var parsedTitle = Parser.ParseMoviePath(f.Name); var parsedTitle = Parser.ParseMoviePath(f.Name, false);
if (parsedTitle == null) if (parsedTitle == null)
{ {
m = new Core.Tv.Movie m = new Core.Tv.Movie

@ -51,9 +51,12 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Castle.2009.S01E14.HDTV.XviD.HUN-LOL", Language.Hungarian)] [TestCase("Castle.2009.S01E14.HDTV.XviD.HUN-LOL", Language.Hungarian)]
[TestCase("The Danish Girl 2015", Language.English)] [TestCase("The Danish Girl 2015", Language.English)]
[TestCase("Passengers.2016.German.DL.AC3.Dubbed.1080p.WebHD.h264.iNTERNAL-PsO", Language.German)] [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) 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) if (result == null)
{ {
Parser.Parser.ParseTitle(postTitle).Language.Should().Be(language); Parser.Parser.ParseTitle(postTitle).Language.Should().Be(language);

@ -63,6 +63,7 @@ namespace NzbDrone.Core.Test.ParserTests
Parser.Parser.ParseTitle(postTitle).SeriesTitle.Should().Be(title); 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("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("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")] [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("A.Movie.Name.(1998)", "A Movie Name")]
[TestCase("Thor: The Dark World 2013", "Thor The Dark World")] [TestCase("Thor: The Dark World 2013", "Thor The Dark World")]
[TestCase("Resident.Evil.The.Final.Chapter.2016", "Resident Evil The Final Chapter")] [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)<29>[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) 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("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) 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")]
[TestCase("The.Danish.Girl.2015.1080p.BluRay.x264.DTS-HD.MA.5.1-RARBG")] [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) 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")] [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 Extended Directors Cut Fan Edit 2012", "Extended Directors Cut Fan Edit")]
[TestCase("Prometheus Director's Cut 2012", "Director's Cut")] [TestCase("Prometheus Director's Cut 2012", "Director's Cut")]
[TestCase("Prometheus Directors Cut 2012", "Directors 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 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("A Fake Movie 2035 Directors 2012.mkv", "Directors")]
[TestCase("Blade Runner Director's Cut 2049.mkv", "Director's Cut")] [TestCase("Blade Runner Director's Cut 2049.mkv", "Director's Cut")]
[TestCase("Prometheus 50th Anniversary Edition 2012.mkv", "50th Anniversary Edition")] [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")] [TestCase("Fake Movie 2016 Final Cut ", "Final Cut")]
public void should_parse_edition(string postTitle, string edition) 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);
} }
} }
} }

@ -28,7 +28,7 @@ namespace NzbDrone.Core.Test.ParserTests.RomanNumeralTests
[Test(Description = "Converts the supported range [1-3999] of Arabic to Roman numerals.")] [Test(Description = "Converts the supported range [1-3999] of Arabic to Roman numerals.")]
[Order(0)] [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); RomanNumeral romanNumeral = new RomanNumeral(arabicNumeral);
@ -39,7 +39,7 @@ namespace NzbDrone.Core.Test.ParserTests.RomanNumeralTests
[Test] [Test]
[Order(1)] [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]); RomanNumeral romanNumeral = new RomanNumeral(_arabicToRomanNumeralsMapping[arabicNumeral]);

@ -8,6 +8,7 @@ using NzbDrone.Core.Configuration.Events;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Messaging.Events;
using NzbDrone.Common.Http.Proxy; using NzbDrone.Common.Http.Proxy;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Configuration namespace NzbDrone.Core.Configuration
{ {
@ -211,6 +212,12 @@ namespace NzbDrone.Core.Configuration
set { SetValue("WhitelistedHardcodedSubs", value); } set { SetValue("WhitelistedHardcodedSubs", value); }
} }
public ParsingLeniencyType ParsingLeniency
{
get { return GetValueEnum<ParsingLeniencyType>("ParsingLeniency", ParsingLeniencyType.Strict); }
set { SetValue("ParsingLeniency", value); }
}
public bool RemoveCompletedDownloads public bool RemoveCompletedDownloads
{ {
get { return GetValueBoolean("RemoveCompletedDownloads", false); } get { return GetValueBoolean("RemoveCompletedDownloads", false); }

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Common.Http.Proxy; using NzbDrone.Common.Http.Proxy;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Configuration namespace NzbDrone.Core.Configuration
{ {
@ -54,6 +55,7 @@ namespace NzbDrone.Core.Configuration
bool AllowHardcodedSubs { get; set; } bool AllowHardcodedSubs { get; set; }
string WhitelistedHardcodedSubs { get; set; } string WhitelistedHardcodedSubs { get; set; }
ParsingLeniencyType ParsingLeniency { get; set; }
int NetImportSyncInterval { get; set; } int NetImportSyncInterval { get; set; }
string ListSyncLevel { get; set; } string ListSyncLevel { get; set; }

@ -26,13 +26,13 @@ namespace NzbDrone.Core.Datastore.Migration
var id = seriesReader.GetInt32(0); var id = seriesReader.GetInt32(0);
var relativePath = seriesReader.GetString(1); var relativePath = seriesReader.GetString(1);
var result = Parser.Parser.ParseMovieTitle(relativePath); var result = Parser.Parser.ParseMovieTitle(relativePath, false);
var edition = ""; var edition = "";
if (result != null) if (result != null)
{ {
edition = Parser.Parser.ParseMovieTitle(relativePath).Edition; edition = Parser.Parser.ParseMovieTitle(relativePath, false).Edition;
} }
using (IDbCommand updateCmd = conn.CreateCommand()) using (IDbCommand updateCmd = conn.CreateCommand())

@ -69,7 +69,7 @@ namespace NzbDrone.Core.DecisionEngine
try try
{ {
var parsedMovieInfo = Parser.Parser.ParseMovieTitle(report.Title); var parsedMovieInfo = Parser.Parser.ParseMovieTitle(report.Title, _configService.ParsingLeniency > 0);
if (parsedMovieInfo != null && !parsedMovieInfo.MovieTitle.IsNullOrWhiteSpace()) if (parsedMovieInfo != null && !parsedMovieInfo.MovieTitle.IsNullOrWhiteSpace())
{ {

@ -3,6 +3,7 @@ using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.History; using NzbDrone.Core.History;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
@ -18,17 +19,20 @@ namespace NzbDrone.Core.Download.TrackedDownloads
{ {
private readonly IParsingService _parsingService; private readonly IParsingService _parsingService;
private readonly IHistoryService _historyService; private readonly IHistoryService _historyService;
private readonly IConfigService _config;
private readonly Logger _logger; private readonly Logger _logger;
private readonly ICached<TrackedDownload> _cache; private readonly ICached<TrackedDownload> _cache;
public TrackedDownloadService(IParsingService parsingService, public TrackedDownloadService(IParsingService parsingService,
ICacheManager cacheManager, ICacheManager cacheManager,
IHistoryService historyService, IHistoryService historyService,
IConfigService config,
Logger logger) Logger logger)
{ {
_parsingService = parsingService; _parsingService = parsingService;
_historyService = historyService; _historyService = historyService;
_cache = cacheManager.GetCache<TrackedDownload>(GetType()); _cache = cacheManager.GetCache<TrackedDownload>(GetType());
_config = config;
_logger = logger; _logger = logger;
} }
@ -56,7 +60,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
try 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); var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId);
if (parsedMovieInfo != null) if (parsedMovieInfo != null)
@ -73,7 +77,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
trackedDownload.RemoteMovie == null || trackedDownload.RemoteMovie == null ||
trackedDownload.RemoteMovie.Movie == null) trackedDownload.RemoteMovie.Movie == null)
{ {
parsedMovieInfo = Parser.Parser.ParseMovieTitle(firstHistoryItem.SourceTitle); parsedMovieInfo = Parser.Parser.ParseMovieTitle(firstHistoryItem.SourceTitle, _config.ParsingLeniency > 0);
if (parsedMovieInfo != null) if (parsedMovieInfo != null)
{ {

@ -3,6 +3,7 @@ using System.IO;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.MediaFiles.EpisodeImport; using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
@ -29,6 +30,7 @@ namespace NzbDrone.Core.MediaFiles
private readonly IMakeImportDecision _importDecisionMaker; private readonly IMakeImportDecision _importDecisionMaker;
private readonly IImportApprovedMovie _importApprovedMovie; private readonly IImportApprovedMovie _importApprovedMovie;
private readonly IDetectSample _detectSample; private readonly IDetectSample _detectSample;
private readonly IConfigService _config;
private readonly Logger _logger; private readonly Logger _logger;
public DownloadedMovieImportService(IDiskProvider diskProvider, public DownloadedMovieImportService(IDiskProvider diskProvider,
@ -38,6 +40,7 @@ namespace NzbDrone.Core.MediaFiles
IMakeImportDecision importDecisionMaker, IMakeImportDecision importDecisionMaker,
IImportApprovedMovie importApprovedMovie, IImportApprovedMovie importApprovedMovie,
IDetectSample detectSample, IDetectSample detectSample,
IConfigService config,
Logger logger) Logger logger)
{ {
_diskProvider = diskProvider; _diskProvider = diskProvider;
@ -47,6 +50,7 @@ namespace NzbDrone.Core.MediaFiles
_importDecisionMaker = importDecisionMaker; _importDecisionMaker = importDecisionMaker;
_importApprovedMovie = importApprovedMovie; _importApprovedMovie = importApprovedMovie;
_detectSample = detectSample; _detectSample = detectSample;
_config = config;
_logger = logger; _logger = logger;
} }
@ -160,7 +164,7 @@ namespace NzbDrone.Core.MediaFiles
} }
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name); 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) if (folderInfo != null)
{ {

@ -154,7 +154,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
{ {
var title = Parser.Parser.RemoveFileExtension(downloadClientItem.Title); var title = Parser.Parser.RemoveFileExtension(downloadClientItem.Title);
var parsedTitle = Parser.Parser.ParseMovieTitle(title); var parsedTitle = Parser.Parser.ParseMovieTitle(title, false);
if (parsedTitle != null) if (parsedTitle != null)
{ {

@ -6,6 +6,7 @@ using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Download.TrackedDownloads; using NzbDrone.Core.Download.TrackedDownloads;
@ -38,6 +39,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
private readonly ITrackedDownloadService _trackedDownloadService; private readonly ITrackedDownloadService _trackedDownloadService;
private readonly IDownloadedMovieImportService _downloadedMovieImportService; private readonly IDownloadedMovieImportService _downloadedMovieImportService;
private readonly IEventAggregator _eventAggregator; private readonly IEventAggregator _eventAggregator;
private readonly IConfigService _config;
private readonly Logger _logger; private readonly Logger _logger;
public ManualImportService(IDiskProvider diskProvider, public ManualImportService(IDiskProvider diskProvider,
@ -53,6 +55,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
ITrackedDownloadService trackedDownloadService, ITrackedDownloadService trackedDownloadService,
IDownloadedMovieImportService downloadedMovieImportService, IDownloadedMovieImportService downloadedMovieImportService,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
IConfigService config,
Logger logger) Logger logger)
{ {
_diskProvider = diskProvider; _diskProvider = diskProvider;
@ -68,6 +71,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
_trackedDownloadService = trackedDownloadService; _trackedDownloadService = trackedDownloadService;
_downloadedMovieImportService = downloadedMovieImportService; _downloadedMovieImportService = downloadedMovieImportService;
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
_config = config;
_logger = logger; _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(); 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 seriesFiles = _diskScanService.GetVideoFiles(folder).ToList();
var decisions = _importDecisionMaker.GetImportDecisions(seriesFiles, series, folderInfo, SceneSource(series, folder), false); 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 file = message.Files[i];
var movie = _movieService.GetMovie(file.MovieId); 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 mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path);
var existingFile = movie.Path.IsParentPath(file.Path); var existingFile = movie.Path.IsParentPath(file.Path);

@ -119,7 +119,7 @@ namespace NzbDrone.Core.MetadataSource.PreDB
foreach (PreDBResult result in results) foreach (PreDBResult result in results)
{ {
var parsedInfo = Parser.Parser.ParseMovieTitle(result.Title); var parsedInfo = Parser.Parser.ParseMovieTitle(result.Title, true);
if (parsedInfo != null) if (parsedInfo != null)
{ {
@ -178,7 +178,7 @@ namespace NzbDrone.Core.MetadataSource.PreDB
foreach (PreDBResult result in results) foreach (PreDBResult result in results)
{ {
var parsed = Parser.Parser.ParseMovieTitle(result.Title); var parsed = Parser.Parser.ParseMovieTitle(result.Title, true);
if (parsed == null) if (parsed == null)
{ {
parsed = new Parser.Model.ParsedMovieInfo { MovieTitle = result.Title, Year = 0 }; parsed = new Parser.Model.ParsedMovieInfo { MovieTitle = result.Title, Year = 0 };

@ -414,7 +414,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
lowerTitle = lowerTitle.Replace(".", ""); lowerTitle = lowerTitle.Replace(".", "");
var parserResult = Parser.Parser.ParseMovieTitle(title, true); var parserResult = Parser.Parser.ParseMovieTitle(title, true, true);
var yearTerm = ""; var yearTerm = "";

@ -141,7 +141,7 @@ namespace NzbDrone.Core.NetImport.RSSImport
} }
releaseInfo.Title = title; releaseInfo.Title = title;
var result = Parser.Parser.ParseMovieTitle(title); var result = Parser.Parser.ParseMovieTitle(title, false);//Depreciated anyways
if (result != null) if (result != null)
{ {

@ -997,6 +997,7 @@
<Compile Include="Parser\Model\LocalMovie.cs" /> <Compile Include="Parser\Model\LocalMovie.cs" />
<Compile Include="Parser\Model\ParsedMovieInfo.cs" /> <Compile Include="Parser\Model\ParsedMovieInfo.cs" />
<Compile Include="Parser\Model\RemoteMovie.cs" /> <Compile Include="Parser\Model\RemoteMovie.cs" />
<Compile Include="Parser\ParsingLeniency.cs" />
<Compile Include="Parser\RomanNumerals\ArabicRomanNumeral.cs" /> <Compile Include="Parser\RomanNumerals\ArabicRomanNumeral.cs" />
<Compile Include="Parser\RomanNumerals\IRomanNumeral.cs" /> <Compile Include="Parser\RomanNumerals\IRomanNumeral.cs" />
<Compile Include="Parser\RomanNumerals\RomanNumeral.cs" /> <Compile Include="Parser\RomanNumerals\RomanNumeral.cs" />
@ -1381,4 +1382,4 @@
<Target Name="AfterBuild"> <Target Name="AfterBuild">
</Target> </Target>
--> -->
</Project> </Project>

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using FluentValidation.Results; using FluentValidation.Results;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
@ -21,7 +22,7 @@ namespace NzbDrone.Core.Organizer
public ValidationFailure ValidateMovieFilename(SampleResult sampleResult) public ValidationFailure ValidateMovieFilename(SampleResult sampleResult)
{ {
var validationFailure = new ValidationFailure("MovieFormat", ERROR_MESSAGE); 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) if(parsedMovieInfo == null)
{ {

@ -7,8 +7,10 @@ using System.Text.RegularExpressions;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using TinyIoC;
namespace NzbDrone.Core.Parser namespace NzbDrone.Core.Parser
{ {
@ -19,16 +21,16 @@ namespace NzbDrone.Core.Parser
private static readonly Regex[] ReportMovieTitleRegex = new[] private static readonly Regex[] ReportMovieTitleRegex = new[]
{ {
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.Special.Edition.2011 //Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.Special.Edition.2011
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*\(?(?<edition>(((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))))))\)?.+(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)", new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*\(?(?<edition>(((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}(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled), RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.2011.Special.Edition //TODO: Seems to slow down parsing heavily! //Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.2011.Special.Edition //TODO: Seems to slow down parsing heavily!
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|(19|20)\d{2}|\]|\W(19|20)\d{2})))+(\W+|_|$)(?!\\)\(?(?<edition>(((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))))))\)?", new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|(19|20)\d{2}|\]|\W(19|20)\d{2})))+(\W+|_|$)(?!\\)\(?(?<edition>(((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), RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Normal movie format, e.g: Mission.Impossible.3.2011 //Normal movie format, e.g: Mission.Impossible.3.2011
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled),
//PassThePopcorn Torrent names: Star.Wars[PassThePopcorn] //PassThePopcorn Torrent names: Star.Wars[PassThePopcorn]
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![()\[!]))*(?<year>(\[\w *\])))+(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![()\[!]))*(?<year>(\[\w *\])))+(\W+|_|$)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled),
@ -45,6 +47,17 @@ namespace NzbDrone.Core.Parser
//When year comes first. //When year comes first.
new Regex(@"^(?:(?:[-_\W](?<![)!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\W\d+)))+(\W+|_|$)(?<title>.+?)?$") new Regex(@"^(?:(?:[-_\W](?<![)!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\W\d+)))+(\W+|_|$)(?<title>.+?)?$")
}; };
private static readonly Regex[] ReportMovieTitleLenientRegexBefore = new[]
{
//Some german or french tracker formats
new Regex(@"^(?<title>(?![(\[]).+?)((\W|_))(?:(German|French|TrueFrench))(.+?)(?=((19|20)\d{2}|$))(?<year>(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[] private static readonly Regex[] ReportTitleRegex = new[]
{ {
@ -338,29 +351,29 @@ namespace NzbDrone.Core.Parser
return result; return result;
} }
public static ParsedMovieInfo ParseMoviePath(string path) public static ParsedMovieInfo ParseMoviePath(string path, bool isLenient)
{ {
var fileInfo = new FileInfo(path); var fileInfo = new FileInfo(path);
var result = ParseMovieTitle(fileInfo.Name, true); var result = ParseMovieTitle(fileInfo.Name, isLenient, true);
if (result == null) if (result == null)
{ {
Logger.Debug("Attempting to parse episode info using directory and file names. {0}", fileInfo.Directory.Name); 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) if (result == null)
{ {
Logger.Debug("Attempting to parse episode info using directory name. {0}", fileInfo.Directory.Name); 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; 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; ParsedMovieInfo realResult = null;
@ -368,8 +381,6 @@ namespace NzbDrone.Core.Parser
{ {
if (!ValidateBeforeParsing(title)) return null; if (!ValidateBeforeParsing(title)) return null;
//title = title.Replace(" ", "."); //TODO: Determine if this breaks something. However, it shouldn't.
Logger.Debug("Parsing string '{0}'", title); Logger.Debug("Parsing string '{0}'", title);
if (ReversedTitleRegex.IsMatch(title)) if (ReversedTitleRegex.IsMatch(title))
@ -398,6 +409,13 @@ namespace NzbDrone.Core.Parser
allRegexes.AddRange(ReportMovieTitleFolderRegex); allRegexes.AddRange(ReportMovieTitleFolderRegex);
} }
if (isLenient)
{
allRegexes.InsertRange(0, ReportMovieTitleLenientRegexBefore);
allRegexes.AddRange(ReportMovieTitleLenientRegexAfter);
}
foreach (var regex in allRegexes) foreach (var regex in allRegexes)
{ {
var match = regex.Matches(simpleTitle); var match = regex.Matches(simpleTitle);

@ -0,0 +1,9 @@
namespace NzbDrone.Core.Parser
{
public enum ParsingLeniencyType
{
Strict = 0,
ParsingLenient = 1,
MappingLenient = 2,
}
}

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.DataAugmentation.Scene; using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
@ -34,6 +35,7 @@ namespace NzbDrone.Core.Parser
private readonly ISeriesService _seriesService; private readonly ISeriesService _seriesService;
private readonly ISceneMappingService _sceneMappingService; private readonly ISceneMappingService _sceneMappingService;
private readonly IMovieService _movieService; private readonly IMovieService _movieService;
private readonly IConfigService _config;
private readonly Logger _logger; private readonly Logger _logger;
private static HashSet<ArabicRomanNumeral> _arabicRomanNumeralMappings; private static HashSet<ArabicRomanNumeral> _arabicRomanNumeralMappings;
@ -42,12 +44,14 @@ namespace NzbDrone.Core.Parser
ISeriesService seriesService, ISeriesService seriesService,
ISceneMappingService sceneMappingService, ISceneMappingService sceneMappingService,
IMovieService movieService, IMovieService movieService,
IConfigService configService,
Logger logger) Logger logger)
{ {
_episodeService = episodeService; _episodeService = episodeService;
_seriesService = seriesService; _seriesService = seriesService;
_sceneMappingService = sceneMappingService; _sceneMappingService = sceneMappingService;
_movieService = movieService; _movieService = movieService;
_config = configService;
_logger = logger; _logger = logger;
if (_arabicRomanNumeralMappings == null) if (_arabicRomanNumeralMappings == null)
@ -127,7 +131,7 @@ namespace NzbDrone.Core.Parser
else else
{ {
parsedMovieInfo = Parser.ParseMoviePath(filename); parsedMovieInfo = Parser.ParseMoviePath(filename, _config.ParsingLeniency > 0);
} }
if (parsedMovieInfo == null) if (parsedMovieInfo == null)
@ -172,7 +176,7 @@ namespace NzbDrone.Core.Parser
public Movie GetMovie(string title) public Movie GetMovie(string title)
{ {
var parsedMovieInfo = Parser.ParseMovieTitle(title); var parsedMovieInfo = Parser.ParseMovieTitle(title, _config.ParsingLeniency > 0);
if (parsedMovieInfo == null) if (parsedMovieInfo == null)
{ {

@ -9,7 +9,7 @@
if (!title.Contains(".")) return false; if (!title.Contains(".")) return false;
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 || if (parsedTitle == null ||
parsedTitle.ReleaseGroup == null || parsedTitle.ReleaseGroup == null ||

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug - Chrome" type="JavascriptDebugType" factoryName="JavaScript Debug" singleton="true" uri="http://localhost:8989"> <configuration default="false" name="Debug - Chrome" type="JavascriptDebugType" factoryName="JavaScript Debug" singleton="true" engineId="98ca6316-2f89-46d9-a9e5-fa9e2b0625b3" uri="http://localhost:7878">
<mapping url="http://localhost:8989/Calendar" local-file="$PROJECT_DIR$/Calendar" /> <mapping url="http://localhost:8989/Wanted" local-file="$PROJECT_DIR$/Wanted" />
<mapping url="http://localhost:8989/MainMenuView.js" local-file="$PROJECT_DIR$/MainMenuView.js" /> <mapping url="http://localhost:8989" local-file="$PROJECT_DIR$" />
<mapping url="http://localhost:8989/Settings" local-file="$PROJECT_DIR$/Settings" />
<mapping url="http://localhost:8989/Upcoming" local-file="$PROJECT_DIR$/Upcoming" />
<mapping url="http://localhost:8989/app.js" local-file="$PROJECT_DIR$/app.js" /> <mapping url="http://localhost:8989/app.js" local-file="$PROJECT_DIR$/app.js" />
<mapping url="http://localhost:8989/Mixins" local-file="$PROJECT_DIR$/Mixins" /> <mapping url="http://localhost:8989/Mixins" local-file="$PROJECT_DIR$/Mixins" />
<mapping url="http://localhost:8989/Wanted" local-file="$PROJECT_DIR$/Wanted" />
<mapping url="http://localhost:8989/Quality" local-file="$PROJECT_DIR$/Quality" /> <mapping url="http://localhost:8989/Quality" local-file="$PROJECT_DIR$/Quality" />
<mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" />
<mapping url="http://localhost:8989/Shared" local-file="$PROJECT_DIR$/Shared" /> <mapping url="http://localhost:8989/Shared" local-file="$PROJECT_DIR$/Shared" />
<mapping url="http://localhost:8989/AddSeries" local-file="$PROJECT_DIR$/AddSeries" />
<mapping url="http://localhost:8989/HeaderView.js" local-file="$PROJECT_DIR$/HeaderView.js" />
<mapping url="http://localhost:8989" local-file="$PROJECT_DIR$" />
<mapping url="http://localhost:8989/Routing.js" local-file="$PROJECT_DIR$/Routing.js" />
<mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" /> <mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" />
<mapping url="http://localhost:8989/Calendar" local-file="$PROJECT_DIR$/Calendar" />
<mapping url="http://localhost:8989/Series" local-file="$PROJECT_DIR$/Series" /> <mapping url="http://localhost:8989/Series" local-file="$PROJECT_DIR$/Series" />
<mapping url="http://localhost:8989/AddSeries" local-file="$PROJECT_DIR$/AddSeries" />
<mapping url="http://localhost:8989/Settings" local-file="$PROJECT_DIR$/Settings" />
<mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" />
<RunnerSettings RunnerId="JavascriptDebugRunner" /> <RunnerSettings RunnerId="JavascriptDebugRunner" />
<ConfigurationWrapper RunnerId="JavascriptDebugRunner" /> <ConfigurationWrapper RunnerId="JavascriptDebugRunner" />
<method /> <method />

@ -1,23 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug - Firefox" type="JavascriptDebugType" factoryName="JavaScript Debug" singleton="true" engineId="firefox" uri="http://localhost:8989">
<mapping url="http://localhost:8989/Calendar" local-file="$PROJECT_DIR$/Calendar" />
<mapping url="http://localhost:8989/MainMenuView.js" local-file="$PROJECT_DIR$/MainMenuView.js" />
<mapping url="http://localhost:8989/Settings" local-file="$PROJECT_DIR$/Settings" />
<mapping url="http://localhost:8989/Upcoming" local-file="$PROJECT_DIR$/Upcoming" />
<mapping url="http://localhost:8989/app.js" local-file="$PROJECT_DIR$/app.js" />
<mapping url="http://localhost:8989/Mixins" local-file="$PROJECT_DIR$/Mixins" />
<mapping url="http://localhost:8989/Wanted" local-file="$PROJECT_DIR$/Wanted" />
<mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" />
<mapping url="http://localhost:8989/Quality" local-file="$PROJECT_DIR$/Quality" />
<mapping url="http://localhost:8989/AddSeries" local-file="$PROJECT_DIR$/AddSeries" />
<mapping url="http://localhost:8989/Shared" local-file="$PROJECT_DIR$/Shared" />
<mapping url="http://localhost:8989/HeaderView.js" local-file="$PROJECT_DIR$/HeaderView.js" />
<mapping url="http://localhost:8989" local-file="$PROJECT_DIR$" />
<mapping url="http://localhost:8989/Routing.js" local-file="$PROJECT_DIR$/Routing.js" />
<mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" />
<mapping url="http://localhost:8989/Series" local-file="$PROJECT_DIR$/Series" />
<RunnerSettings RunnerId="JavascriptDebugRunner" />
<ConfigurationWrapper RunnerId="JavascriptDebugRunner" />
<method />
</configuration>
</component>

@ -9,7 +9,8 @@ var view = Marionette.ItemView.extend({
template : 'Settings/Indexers/Options/IndexerOptionsViewTemplate', template : 'Settings/Indexers/Options/IndexerOptionsViewTemplate',
ui : { ui : {
hcwhitelist : '.x-hcwhitelist', hcwhitelist : '.x-hcwhitelist',
leniencyTooltip : '.x-leniency-tooltip',
}, },
onRender : function() { onRender : function() {
@ -18,6 +19,18 @@ var view = Marionette.ItemView.extend({
allowDuplicates: true, allowDuplicates: true,
tagClass : 'label label-success' 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
});
}, },
}); });

@ -91,6 +91,22 @@
</div> </div>
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Parser Leniency</label>
<div class="col-sm-1 col-sm-push-2 help-inline">
<i class="icon-sonarr-form-info leniency-tooltip x-leniency-tooltip"/>
</div>
<div class="col-sm-2 col-sm-pull-1">
<select class="form-control" name="parsingLeniency">
<option value="strict">Strict</option>
<option value="parsingLenient">Lenient Parsing</option>
<option value="mappingLenient">Lenient Mapping</option>
</select>
</div>
</div>
<legend>Availability Options</legend> <legend>Availability Options</legend>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">Availability Delay</label> <label class="col-sm-3 control-label">Availability Delay</label>

@ -0,0 +1,7 @@
How strict the Parser should be. (Note: Strict is strongly recommended!)
<br><br>
<b>Strict:</b> Just as before, year must immediately follow title.
<br><br>
<b>Lenient Parsing:</b> 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)
<br><br>
<b>Lenient Mapping:</b> Includes Lenient Parsing. When title cannot be found Try mapping just parts of the title. (Useful when no year is present / not after title. <b>NOT IMPLEMENTED YET</b>)
Loading…
Cancel
Save