diff --git a/NzbDrone.5.1.ReSharper b/NzbDrone.5.1.ReSharper deleted file mode 100644 index f86d34090..000000000 --- a/NzbDrone.5.1.ReSharper +++ /dev/null @@ -1,153 +0,0 @@ - - - - - SOLUTION - - - - public - protected - internal - private - new - abstract - virtual - override - sealed - static - readonly - extern - unsafe - volatile - - - - - $object$_On$event$ - $event$Handler - - - - - - - - - - - - - - - - - - - - - 2 - False - False - False - False - False - CHOP_IF_LONG - CHOP_IF_LONG - 200 - CHOP_IF_LONG - - - False - - - $object$_On$event$ - $event$Handler - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $object$_On$event$ - $event$Handler - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NzbDrone.Core.Test/ParserTest.cs b/NzbDrone.Core.Test/ParserTest.cs index adb25142d..4b718ac9e 100644 --- a/NzbDrone.Core.Test/ParserTest.cs +++ b/NzbDrone.Core.Test/ParserTest.cs @@ -13,7 +13,8 @@ namespace NzbDrone.Core.Test public class ParserTest { [Test] - [Row("Sonny.With.a.Chance.S02E15", 2,15)] + [Row("Sonny.With.a.Chance.S02E15", 2, 15)] + [Row("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", 3, 1)] [Row("Two.and.a.Half.Me.103.720p.HDTV.X264-DIMENSION", 1, 3)] [Row("Two.and.a.Half.Me.113.720p.HDTV.X264-DIMENSION", 1, 13)] [Row("Two.and.a.Half.Me.1013.720p.HDTV.X264-DIMENSION", 10, 13)] @@ -34,18 +35,6 @@ namespace NzbDrone.Core.Test Assert.AreEqual(episode, result.Episodes[0]); } - [Test] - [Row("The.Office.US.S03E01E02.DUAL.BDRip.XviD.AC3.-HELLYWOOD", 3, 1, 2)] - [Row("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", 3, 1, 6)] - public void episode_parse_multi(string path, int season, int episodeOne, int episodeTwo) - { - var result = Parser.ParseEpisodeInfo(path); - Assert.Count(2, result); - Assert.AreEqual(season, result[0].SeasonNumber); - Assert.AreEqual(episodeOne, result[0].EpisodeNumber); - Assert.AreEqual(episodeTwo, result[1].EpisodeNumber); - } - [Test] [Row("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", QualityTypes.BDRip)] [Row("WEEDS.S03E01-06.DUAL.BDRip.AC3.-HELLYWOOD", QualityTypes.BDRip)] @@ -84,4 +73,4 @@ namespace NzbDrone.Core.Test Assert.AreEqual(clean, result); } } -} +} \ No newline at end of file diff --git a/NzbDrone.Core/Parser.cs b/NzbDrone.Core/Parser.cs index 9ba9a1f01..757eb546f 100644 --- a/NzbDrone.Core/Parser.cs +++ b/NzbDrone.Core/Parser.cs @@ -9,64 +9,6 @@ using NzbDrone.Core.Model; using NzbDrone.Core.Providers; using NzbDrone.Core.Repository.Quality; -namespace NzbDrone.Core -{ - internal static class Parser - { - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - - private static readonly Regex[] ReportTitleRegex = new[] - { - new Regex(@"(?.+?)?\W?(?<year>\d+?)?\WS?(?<season>\d+)((?:\-|\.|[a-z])(?<episode>\d+))+\W(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), - new Regex(@"(?<title>.+?)?\W?(?<year>\d+?)?\WS?(?<season>\d+)(?<episode>\d{2})\W(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled) //Supports 103/113 naming - }; - - private static readonly Regex[] SeasonReportTitleRegex = new[] - { - new Regex(@"(?<title>.+?)?\W?(?<year>\d{4}?)?\W(?:S|Season)?\W?(?<season>\d+)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), - }; - - private static readonly Regex NormalizeRegex = new Regex(@"((\s|^)the(\s|$))|((\s|^)and(\s|$))|[^a-z]", RegexOptions.IgnoreCase | RegexOptions.Compiled); - - /// <summary> - /// Parses a post title into list of episodes it contains - /// </summary> - /// <param name="title">Title of the report</param> - /// <returns>List of episodes contained to the post</returns> - internal static EpisodeParseResult ParseEpisodeInfo(string title) - { - Logger.Trace("Parsing string '{0}'", title); - - foreach (var regex in ReportTitleRegex) - { - var match = regex.Matches(title); - - if (match.Count != 0) - { - var seriesName = NormalizeTitle(match[0].Groups["title"].Value); - var year = 0; - Int32.TryParse(match[0].Groups["year"].Value, out year); - - if (year < 1900 || year > DateTime.Now.Year + 1) - { - year = 0; - } - - var seasonNumber = Convert.ToInt32(matchGroup.Groups["season"].Value); - - foreach (Capture episode in matchGroup.Groups["episode"].Captures) - { -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using NLog; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; -using NzbDrone.Core.Repository.Quality; - namespace NzbDrone.Core { internal static class Parser @@ -314,472 +256,6 @@ namespace NzbDrone.Core return info.FullName.Trim('/', '\\', ' '); } - + } -} -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using NLog; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; -using NzbDrone.Core.Repository.Quality; - -namespace NzbDrone.Core -{ - internal static class Parser - { - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - - private static readonly Regex[] ReportTitleRegex = new[] - { - new Regex(@"(?<title>.+?)?\W?(?<year>\d+?)?\WS?(?<season>\d+)(?:\-|\.|[a-z])(?<episode>\d+)\W(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), - new Regex(@"(?<title>.+?)?\W?(?<year>\d+?)?\WS?(?<season>\d+)(?<episode>\d{2})\W(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled) //Supports 103/113 naming - }; - - private static readonly Regex[] SeasonReportTitleRegex = new[] - { - new Regex(@"(?<title>.+?)?\W?(?<year>\d{4}?)?\W(?:S|Season)?\W?(?<season>\d+)(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), - }; - - private static readonly Regex NormalizeRegex = new Regex(@"((\s|^)the(\s|$))|((\s|^)and(\s|$))|[^a-z]", RegexOptions.IgnoreCase | RegexOptions.Compiled); - - /// <summary> - /// Parses a post title into list of episodes it contains - /// </summary> - /// <param name="title">Title of the report</param> - /// <returns>List of episodes contained to the post</returns> - internal static EpisodeParseResult ParseEpisodeInfo(string title) - { - Logger.Trace("Parsing string '{0}'", title); - - foreach (var regex in ReportTitleRegex) - { - var match = regex.Matches(title); - - if (match.Count != 0) - { - var seriesName = NormalizeTitle(match[0].Groups["title"].Value); - var year = 0; - Int32.TryParse(match[0].Groups["year"].Value, out year); - - if (year < 1900 || year > DateTime.Now.Year + 1) - { - year = 0; - } - - var parsedEpisode = new EpisodeParseResult - { - Proper = title.ToLower().Contains("proper"), - SeriesTitle = seriesName, - SeasonNumber = Convert.ToInt32(match[0].Groups["season"].Value), - Year = year, - Episodes = new List<int>() - }; - - foreach (Match matchGroup in match) - { - parsedEpisode.Episodes.Add(Convert.ToInt32(matchGroup.Groups["episode"].Value)); - - } - - parsedEpisode.Quality = ParseQuality(title); - - Logger.Trace("Episode Parsed. {0}", parsedEpisode); - - return parsedEpisode; - } - } - - return null; - } - - /// <summary> - /// Parses a post title into season it contains - /// </summary> - /// <param name="title">Title of the report</param> - /// <returns>Season information contained in the post</returns> - internal static SeasonParseResult ParseSeasonInfo(string title) - { - Logger.Trace("Parsing string '{0}'", title); - - foreach (var regex in ReportTitleRegex) - { - var match = regex.Matches(title); - - if (match.Count != 0) - { - var seriesName = NormalizeTitle(match[0].Groups["title"].Value); - var year = 0; - Int32.TryParse(match[0].Groups["year"].Value, out year); - - if (year < 1900 || year > DateTime.Now.Year + 1) - { - year = 0; - } - - var seasonNumber = Convert.ToInt32(match[0].Groups["season"].Value); - - var result = new SeasonParseResult - { - SeriesTitle = seriesName, - SeasonNumber = seasonNumber, - Year = year - }; - - - result.Quality = ParseQuality(title); - - Logger.Trace("Season Parsed. {0}", result); - return result; - } - } - - return null; //Return null - } - - /// <summary> - /// Parses a post title to find the series that relates to it - /// </summary> - /// <param name="title">Title of the report</param> - /// <returns>Normalized Series Name</returns> - internal static string ParseSeriesName(string title) - { - Logger.Trace("Parsing string '{0}'", title); - - foreach (var regex in ReportTitleRegex) - { - var match = regex.Matches(title); - - if (match.Count != 0) - { - var seriesName = NormalizeTitle(match[0].Groups["title"].Value); - var year = 0; - Int32.TryParse(match[0].Groups["year"].Value, out year); - - if (year < 1900 || year > DateTime.Now.Year + 1) - { - year = 0; - } - - Logger.Trace("Series Parsed. {0}", seriesName); - return seriesName; - } - } - - return String.Empty; - } - - /// <summary> - /// Parses proper status out of a report title - /// </summary> - /// <param name="title">Title of the report</param> - /// <returns></returns> - internal static bool ParseProper(string title) - { - return title.ToLower().Contains("proper"); - } - - private static QualityTypes ParseQuality(string name) - { - Logger.Trace("Trying to parse quality for {0}", name); - - var result = QualityTypes.Unknown; - name = name.ToLowerInvariant(); - - if (name.Contains("dvd")) - return QualityTypes.DVD; - - if (name.Contains("bdrip") || name.Contains("brrip")) - { - return QualityTypes.BDRip; - } - - if (name.Contains("xvid") || name.Contains("divx")) - { - if (name.Contains("bluray")) - { - return QualityTypes.BDRip; - } - - return QualityTypes.TV; - } - - if (name.Contains("bluray")) - { - if (name.Contains("720p")) - return QualityTypes.Bluray720; - - if (name.Contains("1080p")) - return QualityTypes.Bluray1080; - - return QualityTypes.Bluray720; - } - if (name.Contains("web-dl")) - return QualityTypes.WEBDL; - if (name.Contains("x264") || name.Contains("h264") || name.Contains("720p")) - return QualityTypes.HDTV; - - //Based on extension - if (result == QualityTypes.Unknown) - { - switch (new FileInfo(name).Extension.ToLower()) - { - case ".avi": - case ".xvid": - case ".wmv": - { - result = QualityTypes.TV; - break; - } - case ".mkv": - { - result = QualityTypes.HDTV; - break; - } - } - } - - Logger.Trace("Quality Parsed:{0} Title:", result, name); - return result; - } - - /// <summary> - /// Normalizes the title. removing all non-word characters as well as common tokens - /// such as 'the' and 'and' - /// </summary> - /// <param name="title">title</param> - /// <returns></returns> - internal static string NormalizeTitle(string title) - { - return NormalizeRegex.Replace(title, String.Empty).ToLower(); - } - - //Note: changing case on path is a problem for running on mono/*nix - //Not going to change the casing any more... Looks Ugly in UI anyways :P - public static string NormalizePath(string path) - { - if (String.IsNullOrEmpty(path)) - throw new ArgumentException("Path can not be null or empty"); - - var info = new FileInfo(path); - - if (info.FullName.StartsWith(@"\\")) //UNC - { - return info.FullName.TrimEnd('/', '\\', ' '); - } - - return info.FullName.Trim('/', '\\', ' '); - } - - - } -} - - Proper = title.ToLower().Contains("proper"), - SeriesTitle = seriesName, - SeasonNumber = Convert.ToInt32(match[0].Groups["season"].Value), - Year = year, - Episodes = new List<int>() - }; - - foreach (Match matchGroup in match) - { - parsedEpisode.Episodes.Add(Convert.ToInt32(matchGroup.Groups["episode"].Value)); - - } - - parsedEpisode.Quality = ParseQuality(title); - Logger.Trace("Episode Parsed. {0}", parsedEpisode); - - return parsedEpisode; - } - } - - return null; - } - - /// <summary> - /// Parses a post title into season it contains - /// </summary> - /// <param name="title">Title of the report</param> - /// <returns>Season information contained in the post</returns> - internal static SeasonParseResult ParseSeasonInfo(string title) - { - Logger.Trace("Parsing string '{0}'", title); - - foreach (var regex in ReportTitleRegex) - { - var match = regex.Matches(title); - - if (match.Count != 0) - { - var seriesName = NormalizeTitle(match[0].Groups["title"].Value); - var year = 0; - Int32.TryParse(match[0].Groups["year"].Value, out year); - - if (year < 1900 || year > DateTime.Now.Year + 1) - { - year = 0; - } - - var seasonNumber = Convert.ToInt32(match[0].Groups["season"].Value); - - var result = new SeasonParseResult - { - SeriesTitle = seriesName, - SeasonNumber = seasonNumber, - Year = year - }; - - - result.Quality = ParseQuality(title); - - Logger.Trace("Season Parsed. {0}", result); - return result; - } - } - - return null; //Return null - } - - /// <summary> - /// Parses a post title to find the series that relates to it - /// </summary> - /// <param name="title">Title of the report</param> - /// <returns>Normalized Series Name</returns> - internal static string ParseSeriesName(string title) - { - Logger.Trace("Parsing string '{0}'", title); - - foreach (var regex in ReportTitleRegex) - { - var match = regex.Matches(title); - - if (match.Count != 0) - { - var seriesName = NormalizeTitle(match[0].Groups["title"].Value); - var year = 0; - Int32.TryParse(match[0].Groups["year"].Value, out year); - - if (year < 1900 || year > DateTime.Now.Year + 1) - { - year = 0; - } - - Logger.Trace("Series Parsed. {0}", seriesName); - return seriesName; - } - } - - return String.Empty; - } - - /// <summary> - /// Parses proper status out of a report title - /// </summary> - /// <param name="title">Title of the report</param> - /// <returns></returns> - internal static bool ParseProper(string title) - { - return title.ToLower().Contains("proper"); - } - - private static QualityTypes ParseQuality(string name) - { - Logger.Trace("Trying to parse quality for {0}", name); - - var result = QualityTypes.Unknown; - name = name.ToLowerInvariant(); - - if (name.Contains("dvd")) - return QualityTypes.DVD; - - if (name.Contains("bdrip") || name.Contains("brrip")) - { - return QualityTypes.BDRip; - } - - if (name.Contains("xvid") || name.Contains("divx")) - { - if (name.Contains("bluray")) - { - return QualityTypes.BDRip; - } - - return QualityTypes.TV; - } - - if (name.Contains("bluray")) - { - if (name.Contains("720p")) - return QualityTypes.Bluray720; - - if (name.Contains("1080p")) - return QualityTypes.Bluray1080; - - return QualityTypes.Bluray720; - } - if (name.Contains("web-dl")) - return QualityTypes.WEBDL; - if (name.Contains("x264") || name.Contains("h264") || name.Contains("720p")) - return QualityTypes.HDTV; - - //Based on extension - if (result == QualityTypes.Unknown) - { - switch (new FileInfo(name).Extension.ToLower()) - { - case ".avi": - case ".xvid": - case ".wmv": - { - result = QualityTypes.TV; - break; - } - case ".mkv": - { - result = QualityTypes.HDTV; - break; - } - } - } - - Logger.Trace("Quality Parsed:{0} Title:", result, name); - return result; - } - - /// <summary> - /// Normalizes the title. removing all non-word characters as well as common tokens - /// such as 'the' and 'and' - /// </summary> - /// <param name="title">title</param> - /// <returns></returns> - internal static string NormalizeTitle(string title) - { - return NormalizeRegex.Replace(title, String.Empty).ToLower(); - } - - //Note: changing case on path is a problem for running on mono/*nix - //Not going to change the casing any more... Looks Ugly in UI anyways :P - public static string NormalizePath(string path) - { - if (String.IsNullOrEmpty(path)) - throw new ArgumentException("Path can not be null or empty"); - - var info = new FileInfo(path); - - if (info.FullName.StartsWith(@"\\")) //UNC - { - return info.FullName.TrimEnd('/', '\\', ' '); - } - - return info.FullName.Trim('/', '\\', ' '); - } - - - } -} +} \ No newline at end of file diff --git a/NzbDrone.Core/Providers/ITvDbProvider.cs b/NzbDrone.Core/Providers/ITvDbProvider.cs index 70a852a20..3746389ea 100644 --- a/NzbDrone.Core/Providers/ITvDbProvider.cs +++ b/NzbDrone.Core/Providers/ITvDbProvider.cs @@ -6,6 +6,7 @@ namespace NzbDrone.Core.Providers public interface ITvDbProvider { IList<TvdbSearchResult> SearchSeries(string name); + int GetBestMatch(List<TvdbSearchResult> searchResults, string searchString); TvdbSearchResult GetSeries(string title); TvdbSeries GetSeries(int id, bool loadEpisodes); } diff --git a/NzbDrone.Core/Providers/TvDbProvider.cs b/NzbDrone.Core/Providers/TvDbProvider.cs index 5651a5efc..6d5e2fdca 100644 --- a/NzbDrone.Core/Providers/TvDbProvider.cs +++ b/NzbDrone.Core/Providers/TvDbProvider.cs @@ -52,6 +52,23 @@ namespace NzbDrone.Core.Providers return null; } + public int GetBestMatch(List<TvdbSearchResult> searchResults, string title) + { + if (searchResults.Count == 0) + return 0; + + foreach (var tvdbSearchResult in searchResults) + { + if (IsTitleMatch(tvdbSearchResult.SeriesName, title)) + { + Logger.Debug("Search for '{0}' was successful", title); + return tvdbSearchResult.Id; + } + } + + return searchResults[0].Id; + } + public TvdbSeries GetSeries(int id, bool loadEpisodes) { Logger.Debug("Fetching SeriesId'{0}' from tvdb", id); diff --git a/NzbDrone.Web/Controllers/AddSeriesController.cs b/NzbDrone.Web/Controllers/AddSeriesController.cs index 0f4a4a6c1..d20e2ef26 100644 --- a/NzbDrone.Web/Controllers/AddSeriesController.cs +++ b/NzbDrone.Web/Controllers/AddSeriesController.cs @@ -80,12 +80,14 @@ namespace NzbDrone.Web.Controllers ViewData["path"] = path; ViewData["javaPath"] = path.Replace(Path.DirectorySeparatorChar, '|').Replace(Path.VolumeSeparatorChar, '^'); + var defaultQuality = _configProvider.DefaultQualityProfile; var qualityProfiles = _qualityProvider.GetAllProfiles(); + ViewData["quality"] = new SelectList( qualityProfiles, "QualityProfileId", "Name", - "HD"); + defaultQuality); ; return PartialView("AddSeriesItem", suggestions); @@ -117,8 +119,9 @@ namespace NzbDrone.Web.Controllers public SelectList GetSuggestionList(string searchString) { var dataVal = _tvDbProvider.SearchSeries(searchString); + var bestResult = _tvDbProvider.GetBestMatch(dataVal.ToList(), searchString); - return new SelectList(dataVal, "Id", "SeriesName"); + return new SelectList(dataVal, "Id", "SeriesName", bestResult); } } diff --git a/NzbDrone.Web/Views/AddSeries/AddExisting.aspx b/NzbDrone.Web/Views/AddSeries/AddExisting.aspx index fab8a8da8..de3aa9c21 100644 --- a/NzbDrone.Web/Views/AddSeries/AddExisting.aspx +++ b/NzbDrone.Web/Views/AddSeries/AddExisting.aspx @@ -7,6 +7,9 @@ </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <% + if (Model.Count() == 0) + Html.DisplayText("No Series to Add"); + foreach (var path in Model) { Html.RenderAction("RenderPartial", "AddSeries", new { path }); diff --git a/NzbDrone.Web/Views/AddSeries/AddSeriesItem.cshtml b/NzbDrone.Web/Views/AddSeries/AddSeriesItem.cshtml index 7fd70a03c..09458c69f 100644 --- a/NzbDrone.Web/Views/AddSeries/AddSeriesItem.cshtml +++ b/NzbDrone.Web/Views/AddSeries/AddSeriesItem.cshtml @@ -1,6 +1,6 @@ @using NzbDrone.Core.Repository.Quality @model SelectList -<div padding: 10px" id="div_@(ViewData["guid"])"> +<div style="padding:3px" id="div_@(ViewData["guid"])"> <fieldset> <legend>@ViewData["path"].ToString()</legend> <div> @@ -11,7 +11,7 @@ .Filterable(f => f.FilterMode(AutoCompleteFilterMode.Contains)) .HighlightFirstMatch(true) .HtmlAttributes(new { style = "width: 300px;" }) - .SelectedIndex(0).Render();} + .Render();} @Html.Telerik().DropDownList().Name("qualityList_" + ViewData["guid"].ToString()).BindTo((SelectList)ViewData["quality"]).HtmlAttributes(new { style = "width: 100px;" }) <button class="listButton" onclick="addSeries('@ViewData["guid"]','@ViewData["javaPath"].ToString()' )"> Add</button>