diff --git a/NzbDrone.Core.Test/EpisodeProviderTest.cs b/NzbDrone.Core.Test/EpisodeProviderTest.cs index 0bb642fef..68147abe1 100644 Binary files a/NzbDrone.Core.Test/EpisodeProviderTest.cs and b/NzbDrone.Core.Test/EpisodeProviderTest.cs differ diff --git a/NzbDrone.Core.Test/ParserTest.cs b/NzbDrone.Core.Test/ParserTest.cs index fe8e2ed4e..e93540ad3 100644 --- a/NzbDrone.Core.Test/ParserTest.cs +++ b/NzbDrone.Core.Test/ParserTest.cs @@ -17,7 +17,6 @@ public class ParserTest [Test] [Row("Sonny.With.a.Chance.S02E15", "Sonny.With.a.Chance", 2, 15)] - [Row("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", "WEEDS", 3, 1)] [Row("Two.and.a.Half.Me.103.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Me", 1, 3)] [Row("Two.and.a.Half.Me.113.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Me", 1, 13)] [Row("Two.and.a.Half.Me.1013.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Me", 10, 13)] @@ -36,12 +35,14 @@ public class ParserTest [Row("Pride.and.Prejudice.1995.S03E20.HDTV.XviD-LOL", "Pride and Prejudice 1995", 3, 20)] //[Row(@"Season 4\07 WS PDTV XviD FUtV", "", 4, 7)] [Row("The.Office.S03E115.DVDRip.XviD-OSiTV", "The.Office", 3, 115)] + [Row(@"Parks and Recreation - S02E21 - 94 Meetings - 720p TV.mkv", "Parks and Recreation", 2, 21)] public void episode_parse(string postTitle, string title, int season, int episode) { var result = Parser.ParseEpisodeInfo(postTitle); Assert.AreEqual(season, result.SeasonNumber); Assert.AreEqual(episode, result.Episodes[0]); Assert.AreEqual(Parser.NormalizeTitle(title), result.CleanTitle); + Assert.AreEqual(1, result.Episodes.Count); } [Test] @@ -88,20 +89,21 @@ public void quality_parse(string postTitle, object quality) [Test] [Timeout(1)] - [Row("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", "WEEDS", 3, new[] { 1, 2, 3, 4, 5, 6 })] - [Row("Two.and.a.Half.Men.103.104.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Men", 1, new[] { 3, 4 })] - [Row("Weeds.S03E01.S03E02.720p.HDTV.X264-DIMENSION", "Weeds", 3, new[] { 1, 2 })] - [Row("The Borgias S01e01 e02 ShoHD On Demand 1080i DD5 1 ALANiS", "The Borgias", 1, new[] { 1, 2 })] - [Row("Big Time Rush 1x01 to 10 480i DD2 0 Sianto", "Big Time Rush", 1, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 })] - [Row("White.Collar.2x04.2x05.720p.BluRay-FUTV", "White.Collar", 2, new[] { 4, 5 })] + [Row("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", "WEEDS", 3, new[] { 1, 2, 3, 4, 5, 6 }, 6)] + [Row("Two.and.a.Half.Men.103.104.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Men", 1, new[] { 3, 4 }, 2)] + [Row("Weeds.S03E01.S03E02.720p.HDTV.X264-DIMENSION", "Weeds", 3, new[] { 1, 2 }, 2)] + [Row("The Borgias S01e01 e02 ShoHD On Demand 1080i DD5 1 ALANiS", "The Borgias", 1, new[] { 1, 2 }, 2)] + [Row("Big Time Rush 1x01 to 10 480i DD2 0 Sianto", "Big Time Rush", 1, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 10)] + [Row("White.Collar.2x04.2x05.720p.BluRay-FUTV", "White.Collar", 2, new[] { 4, 5 }, 2)] //[Row("The.Kennedys.Part.1.and.Part.2.DSR.XviD-SYS", 1, new[] { 1, 2 })] - public void episode_multipart_parse(string postTitle, string title, int season, int[] episodes) + public void episode_multipart_parse(string postTitle, string title, int season, int[] episodes, int count) { var result = Parser.ParseEpisodeInfo(postTitle); Assert.AreEqual(season, result.SeasonNumber); Assert.Count(episodes.Length, result.Episodes); Assert.AreElementsEqualIgnoringOrder(episodes, result.Episodes); Assert.AreEqual(Parser.NormalizeTitle(title), result.CleanTitle); + Assert.AreEqual(count, result.Episodes.Count); } [Test] diff --git a/NzbDrone.Core/Model/SabnzbdInfoModel.cs b/NzbDrone.Core/Model/SabnzbdInfoModel.cs new file mode 100644 index 000000000..ecfd4c4c2 --- /dev/null +++ b/NzbDrone.Core/Model/SabnzbdInfoModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.Model +{ + public class SabnzbdInfoModel + { + public string ApiKey { get; set; } + public int Port { get; set; } + public string Username { get; set; } + public string Password { get; set; } + } +} diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index b7fa36edb..ebd2c3da9 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -167,6 +167,7 @@ + diff --git a/NzbDrone.Core/Parser.cs b/NzbDrone.Core/Parser.cs index b7f001e96..b8553aae7 100644 --- a/NzbDrone.Core/Parser.cs +++ b/NzbDrone.Core/Parser.cs @@ -16,7 +16,7 @@ public static class Parser { new Regex(@"^(?.+?)?\W?(?<year>\d{4}?)?\W+(?<airyear>\d{4})\W+(?<airmonth>\d{2})\W+(?<airday>\d{2})\W?(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), - new Regex(@"^(?<title>.*?)?(?:\W?S?(?<season>\d{1,2}(?!\d+))(?:(?:\-|\.|[ex]|\s|to)+(?<episode>\d{1,2}(?!\d+)))+)+\W?(?!\\)", + new Regex(@"^(?<title>.*?)?(?:\W?S?(?<season>\d{1,2}(?!\d+))(?:(?:\-|\.|[ex]|\s|\sto\s){1,2}(?<episode>\d{1,2}(?!\d+)))+)+\W?(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), new Regex(@"^(?<title>.+?)?\W?(?<year>\d{4}?)?(?:\W(?<season>\d+)(?<episode>\d{2}))+\W?(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), @@ -287,4 +287,4 @@ public static string NormalizePath(string path) return info.FullName.Trim('/', '\\', ' '); } } -} \ No newline at end of file +}��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� diff --git a/NzbDrone.Core/Providers/AutoConfigureProvider.cs b/NzbDrone.Core/Providers/AutoConfigureProvider.cs new file mode 100644 index 000000000..be3d96ecf --- /dev/null +++ b/NzbDrone.Core/Providers/AutoConfigureProvider.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using NzbDrone.Core.Model; +using NzbDrone.Core.Providers.Core; + +namespace NzbDrone.Core.Providers +{ + public class AutoConfigureProvider + { + private HttpProvider _httpProvider; + private ConfigProvider _configProvider; + + public AutoConfigureProvider(HttpProvider httpProvider, ConfigProvider configProvider) + { + _httpProvider = httpProvider; + _configProvider = configProvider; + } + + public SabnzbdInfoModel AutoConfigureSab(string username, string password) + { + //Get Output from Netstat + var netStatOutput = String.Empty; + //var port = GetSabnzbdPort(netStatOutput); + var port = 2222; + var apiKey = GetSabnzbdApiKey(port); + + if (port > 0 && !String.IsNullOrEmpty(apiKey)) + { + return new SabnzbdInfoModel + { + ApiKey = apiKey, + Port = port, + Username = username, + Password = password + }; + } + + return null; + } + + private int GetSabnzbdPort(string netstatOutput) + { + Regex regex = new Regex(@"^(?:TCP\W+127.0.0.1:(?<port>\d+\W+).+?\r\n\W+\[sabnzbd.exe\])", RegexOptions.IgnoreCase + | RegexOptions.Compiled); + var match = regex.Match(netstatOutput); + var port = 0; + Int32.TryParse(match.Groups["port"].Value, out port); + + return port; + } + + private string GetSabnzbdApiKey(int port, string ipAddress = "127.0.0.1") + { + var request = String.Format("http://{0}:{1}/config/general/", ipAddress, port); + var result = _httpProvider.DownloadString(request); + + Regex regex = new Regex("\\<input\\Wtype\\=\\\"text\\\"\\Wid\\=\\\"apikey\\\"\\Wvalue\\=\\\"(?<apikey>\\w+)\\W", RegexOptions.IgnoreCase + | RegexOptions.Compiled); + var match = regex.Match(result); + + return match.Groups["apikey"].Value; + } + } +} diff --git a/NzbDrone.Web/Controllers/SettingsController.cs b/NzbDrone.Web/Controllers/SettingsController.cs index 62c0efec9..f145d09be 100644 --- a/NzbDrone.Web/Controllers/SettingsController.cs +++ b/NzbDrone.Web/Controllers/SettingsController.cs @@ -24,14 +24,17 @@ public class SettingsController : Controller private readonly IndexerProvider _indexerProvider; private readonly QualityProvider _qualityProvider; private readonly RootDirProvider _rootDirProvider; + private readonly AutoConfigureProvider _autoConfigureProvider; public SettingsController(ConfigProvider configProvider, IndexerProvider indexerProvider, - QualityProvider qualityProvider, RootDirProvider rootDirProvider) + QualityProvider qualityProvider, RootDirProvider rootDirProvider, + AutoConfigureProvider autoConfigureProvider) { _configProvider = configProvider; _indexerProvider = indexerProvider; _qualityProvider = qualityProvider; _rootDirProvider = rootDirProvider; + _autoConfigureProvider = autoConfigureProvider; } public ActionResult Index(string viewName) @@ -276,6 +279,28 @@ public JsonResult DeleteQualityProfile(int profileId) return new JsonResult { Data = "ok" }; } + public JsonResult AutoConfigureSab(string username, string password) + { + SabnzbdInfoModel info; + + try + { + //info = _autoConfigureProvider.AutoConfigureSab(username, password); + info = new SabnzbdInfoModel + { + ApiKey = "123456", + Port = 2222 + }; + } + + catch (Exception) + { + return new JsonResult { Data = "failed" }; + } + + return Json(info); + } + [HttpPost] public ActionResult SaveGeneral(SettingsModel data) { diff --git a/NzbDrone.Web/Views/Settings/Downloads.cshtml b/NzbDrone.Web/Views/Settings/Downloads.cshtml index 149233ff1..968b6da3e 100644 --- a/NzbDrone.Web/Views/Settings/Downloads.cshtml +++ b/NzbDrone.Web/Views/Settings/Downloads.cshtml @@ -2,6 +2,7 @@ <script type="text/javascript"> $(document).ready(function () { + selectDownloadOptionAtStart(); //Load either SAB or Blackhole div var options = { target: '#result', beforeSubmit: showRequest, @@ -10,19 +11,26 @@ resetForm: false }; $('#form').ajaxForm(options); - selectDownloadOption(); //Load either SAB or Blackhole div $('#save_button').attr('disabled', ''); }); + + function selectDownloadOptionAtStart() { + var checked = $('UseBlackHole').val(); + $radios.filter('[value=' + checked + ']').attr('checked', true); + selectDownloadOption(); + } function selectDownloadOption() { - var selected = $("input[name='UseBlackHole']:checked").val(); + var selected = $("input[name='UseBlackhole']:checked").val(); if (selected == "True") { + $('#UseBlackHole').attr('checked', true); document.getElementById('blackhole').style.display = 'block'; document.getElementById('sab').style.display = 'none'; } else { + $('#UseBlackHole').attr('checked', false); document.getElementById('sab').style.display = 'block'; document.getElementById('blackhole').style.display = 'none'; } @@ -81,12 +89,13 @@ <div> <div> <b>@Html.LabelFor(m => m.UseBlackHole)</b> + @Html.CheckBoxFor(m => m.UseBlackHole, new { style="display:block" }) </div> <div> - @Html.RadioButtonFor(m => m.UseBlackHole, true, new { @class = "blackhole_radio" })Blackhole + @Html.RadioButton("UseBlackhole", true, new { @class="blackhole_radio" })Blackhole </div> <div> - @Html.RadioButtonFor(m => m.UseBlackHole, false, new { @class = "blackhole_radio" })SABnzbd + @Html.RadioButton("UseBlackhole", false, new { @class="blackhole_radio" })SABnzbd </div> </div> @@ -94,6 +103,8 @@ <fieldset class="sub-field"> <legend>SABnzbd</legend> + <button type="button" onclick="autoConfigureSab()">Auto-Configure</button> + <div class="config-section"> <div class="config-group"> <div class="config-title">@Html.LabelFor(m => m.SabHost)</div> @@ -172,4 +183,26 @@ </fieldset> } <div id="result"></div> - \ No newline at end of file + +<script type="text/javascript"> + var autoConfigureSabUrl = '@Url.Action("AutoConfigureSab", "Settings")'; + + function autoConfigureSab() { + $.ajax({ + type: "POST", + url: autoConfigureSabUrl, + data: jQuery.param({ username: $('#SabUsername').val(), password: $('#SabPassword').val() }), + error: function (req, status, error) { + alert("Sorry! We could not autoconfigure SABnzbd for you"); + }, + success: autoConfigureSuccess + }); + + function autoConfigureSuccess(data) { + $('#SabApiKey').val(data.ApiKey); + $('#SabPort').val(data.Port); + $('#SabUsername').val(data.Username); + $('#SabPassword').val(data.Password); + } + } +</script> \ No newline at end of file