diff --git a/NzbDrone.Core/EpisodeSortingHelper.cs b/NzbDrone.Core/EpisodeSortingHelper.cs new file mode 100644 index 000000000..16b7f2c5a --- /dev/null +++ b/NzbDrone.Core/EpisodeSortingHelper.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NzbDrone.Core.Model; + +namespace NzbDrone.Core +{ + public static class EpisodeSortingHelper + { + private static readonly List SeparatorStyles = new List + { + new EpisodeSortingType {Id = 0, Name = "Dash", Pattern = " - "}, + new EpisodeSortingType {Id = 1, Name = "Space", Pattern = " "} + }; + + private static readonly List NumberStyles = new List + { + new EpisodeSortingType { Id = 0, Name = "1x05", Pattern = "%sx%0e"}, + new EpisodeSortingType { Id = 1, Name = "01x05", Pattern = "%0sx%0e"}, + new EpisodeSortingType { Id = 2, Name = "S01E05", Pattern = "S%0sE%0e"}, + new EpisodeSortingType { Id = 3, Name = "s01e05", Pattern = "s%0se%0e"} + }; + + private static readonly List MultiEpisodeStyles = new List + { + new EpisodeSortingType { Id = 0, Name = "Extend", Pattern = "" }, + new EpisodeSortingType { Id = 1, Name = "Duplicate", Pattern = "" }, + new EpisodeSortingType { Id = 2, Name = "Repeat", Pattern = "" } + }; + + public static List GetSeparatorStyles() + { + return SeparatorStyles; + } + + public static List GetNumberStyles() + { + return NumberStyles; + } + + public static List GetMultiEpisodeStyles() + { + return MultiEpisodeStyles; + } + + public static EpisodeSortingType GetSeparatorStyle(int id) + { + return SeparatorStyles.Single(s => s.Id == id); + } + + public static EpisodeSortingType GetNumberStyle(int id) + { + return NumberStyles.Single(s => s.Id == id); + } + + public static EpisodeSortingType GetMultiEpisodeStyle(int id) + { + return MultiEpisodeStyles.Single(s => s.Id == id); + } + + public static EpisodeSortingType GetSeparatorStyle(string name) + { + return SeparatorStyles.Single(s => s.Name == name); + } + + public static EpisodeSortingType GetNumberStyle(string name) + { + return NumberStyles.Single(s => s.Name == name); + } + + public static EpisodeSortingType GetMultiEpisodeStyle(string name) + { + return MultiEpisodeStyles.Single(s => s.Name == name); + } + } +} diff --git a/NzbDrone.Core/Model/EpisodeSortingType.cs b/NzbDrone.Core/Model/EpisodeSortingType.cs new file mode 100644 index 000000000..678b0aa59 --- /dev/null +++ b/NzbDrone.Core/Model/EpisodeSortingType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.Model +{ + public class EpisodeSortingType + { + public int Id { get; set; } + public string Name { get; set; } + public string Pattern { get; set; } + } +} diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index ce6167a7a..48435cf3e 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -156,6 +156,7 @@ + @@ -165,6 +166,7 @@ + diff --git a/NzbDrone.Core/Providers/RenameProvider.cs b/NzbDrone.Core/Providers/RenameProvider.cs index 57b80c219..acf539d06 100644 --- a/NzbDrone.Core/Providers/RenameProvider.cs +++ b/NzbDrone.Core/Providers/RenameProvider.cs @@ -208,7 +208,7 @@ namespace NzbDrone.Core.Providers private string GetSeasonFolder(int seasonNumber) { return - _configProvider.GetValue("SeasonFolder", "Season %s", true).Replace("%s", seasonNumber.ToString()). + _configProvider.GetValue("Sorting_SeasonFolderFormat", "Season %s", true).Replace("%s", seasonNumber.ToString()). Replace("%0s", seasonNumber.ToString("00")); } } diff --git a/NzbDrone.Core/Providers/SeriesProvider.cs b/NzbDrone.Core/Providers/SeriesProvider.cs index a5f4269ae..05b01a370 100644 --- a/NzbDrone.Core/Providers/SeriesProvider.cs +++ b/NzbDrone.Core/Providers/SeriesProvider.cs @@ -113,7 +113,7 @@ namespace NzbDrone.Core.Providers repoSeries.QualityProfileId = Convert.ToInt32(_config.GetValue("DefaultQualityProfile", "1", true)); repoSeries.SeasonFolder = true; - if (!Convert.ToBoolean(_config.GetValue("SeasonFolder", true, true))) + if (!Convert.ToBoolean(_config.GetValue("Sorting_SeasonFolder", true, true))) repoSeries.SeasonFolder = false; _sonioRepo.Add(repoSeries); diff --git a/NzbDrone.Web/Controllers/SettingsController.cs b/NzbDrone.Web/Controllers/SettingsController.cs index a0f85430d..be14a241f 100644 --- a/NzbDrone.Web/Controllers/SettingsController.cs +++ b/NzbDrone.Web/Controllers/SettingsController.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Web; using System.Web.Mvc; using NLog; +using NzbDrone.Core; using NzbDrone.Core.Model; using NzbDrone.Core.Providers; using NzbDrone.Core.Repository.Quality; @@ -120,6 +121,30 @@ namespace NzbDrone.Web.Controllers return View("Index", model); } + public ActionResult EpisodeSorting() + { + ViewData["viewName"] = "EpisodeSorting"; + + var model = new EpisodeSortingModel(); + + model.ShowName = Convert.ToBoolean(_configProvider.GetValue("Sorting_ShowName", true, true)); + model.EpisodeName = Convert.ToBoolean(_configProvider.GetValue("Sorting_EpisodeName", true, true)); + model.ReplaceSpaces = Convert.ToBoolean(_configProvider.GetValue("Sorting_ReplaceSpaces", false, true)); + model.AppendQuality = Convert.ToBoolean(_configProvider.GetValue("Sorting_AppendQuality", false, true)); + model.UseAirByDate = Convert.ToBoolean(_configProvider.GetValue("Sorting_UseAirByDate", true, true)); + model.SeasonFolders = Convert.ToBoolean(_configProvider.GetValue("Sorting_SeasonFolder", true, true)); + model.SeasonFolderFormat = _configProvider.GetValue("Sorting_SeasonFolderFormat", "Season %s", true); + model.SeparatorStyle = Convert.ToInt32(_configProvider.GetValue("Sorting_SeparatorStyle", 0, true)); + model.NumberStyle = Convert.ToInt32(_configProvider.GetValue("Sorting_NumberStyle", 2, true)); + model.MultiEpisodeStyle = Convert.ToInt32(_configProvider.GetValue("Sorting_MultiEpisodeStyle", 0, true)); + + model.SeparatorStyles = new SelectList(EpisodeSortingHelper.GetSeparatorStyles(), "Id", "Name"); + model.NumberStyles = new SelectList(EpisodeSortingHelper.GetNumberStyles(), "Id", "Name"); + model.MultiEpisodeStyles = new SelectList(EpisodeSortingHelper.GetMultiEpisodeStyles(), "Id", "Name"); + + return View("Index", model); + } + public ViewResult AddUserProfile() { var qualityTypes = new List(); @@ -249,5 +274,27 @@ namespace NzbDrone.Web.Controllers return Content(_settingsFailed); } + + [HttpPost] + public ActionResult SaveEpisodeSorting(EpisodeSortingModel data) + { + if (ModelState.IsValid) + { + _configProvider.SetValue("Sorting_ShowName", data.ShowName.ToString()); + _configProvider.SetValue("Sorting_EpisodeName", data.EpisodeName.ToString()); + _configProvider.SetValue("Sorting_ReplaceSpaces", data.ReplaceSpaces.ToString()); + _configProvider.SetValue("Sorting_AppendQuality", data.AppendQuality.ToString()); + _configProvider.SetValue("Sorting_UseAirByDate", data.UseAirByDate.ToString()); + _configProvider.SetValue("Sorting_SeasonFolder", data.SeasonFolders.ToString()); + _configProvider.SetValue("Sorting_SeasonFolderFormat", data.SeasonFolderFormat); + _configProvider.SetValue("Sorting_SeparatorStyle", data.SeparatorStyle.ToString()); + _configProvider.SetValue("Sorting_NumberStyle", data.NumberStyle.ToString()); + _configProvider.SetValue("Sorting_MultiEpisodeStyle", data.MultiEpisodeStyle.ToString()); + + return Content(_settingsSaved); + } + + return Content(_settingsFailed); + } } } diff --git a/NzbDrone.Web/Models/EpisodeSortingModel.cs b/NzbDrone.Web/Models/EpisodeSortingModel.cs new file mode 100644 index 000000000..a02965433 --- /dev/null +++ b/NzbDrone.Web/Models/EpisodeSortingModel.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using NzbDrone.Core.Model; + +namespace NzbDrone.Web.Models +{ + public class EpisodeSortingModel + { + public bool ShowName { get; set; } + public bool EpisodeName { get; set; } + public bool ReplaceSpaces { get; set; } + public bool AppendQuality { get; set; } + public bool UseAirByDate { get; set; } + public bool SeasonFolders { get; set; } + public string SeasonFolderFormat { get; set; } + public int SeparatorStyle { get; set; } + public int NumberStyle { get; set; } + public int MultiEpisodeStyle { get; set; } + public SelectList SeparatorStyles { get; set; } + public SelectList NumberStyles { get; set; } + public SelectList MultiEpisodeStyles { get; set; } + } +} \ No newline at end of file diff --git a/NzbDrone.Web/NzbDrone.Web.csproj b/NzbDrone.Web/NzbDrone.Web.csproj index e1f67cdb9..fde1b8dea 100644 --- a/NzbDrone.Web/NzbDrone.Web.csproj +++ b/NzbDrone.Web/NzbDrone.Web.csproj @@ -86,6 +86,7 @@ + @@ -272,6 +273,7 @@ + diff --git a/NzbDrone.Web/Views/Series/Edit.aspx b/NzbDrone.Web/Views/Series/Edit.aspx index 207d993ed..65b8f5532 100644 --- a/NzbDrone.Web/Views/Series/Edit.aspx +++ b/NzbDrone.Web/Views/Series/Edit.aspx @@ -57,6 +57,14 @@ <%: Html.CheckBoxFor(model => model.Monitored) %> <%: Html.ValidationMessageFor(model => model.Monitored) %> + +
+ <%: Html.LabelFor(model => model.SeasonFolder) %> +
+
+ <%: Html.CheckBoxFor(model => model.SeasonFolder)%> + <%: Html.ValidationMessageFor(model => model.SeasonFolder)%> +
<%: Html.LabelFor(model => model.QualityProfileId) %> diff --git a/NzbDrone.Web/Views/Settings/EpisodeSorting.ascx b/NzbDrone.Web/Views/Settings/EpisodeSorting.ascx new file mode 100644 index 000000000..3446f6997 --- /dev/null +++ b/NzbDrone.Web/Views/Settings/EpisodeSorting.ascx @@ -0,0 +1,126 @@ +<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> + + + + <% Html.EnableClientValidation(); %> + +<% using (Html.BeginForm("SaveEpisodeSorting", "Settings", FormMethod.Post, new { id = "form", name = "form" })) + {%> +<%--<%: Html.ValidationSummary(true, "Unable to save your settings. Please correct the errors and try again.") %>--%> + +
+ Episode Sorting + +
+
+
<%= Html.LabelFor(m => m.ShowName)%>
+
<%= Html.CheckBoxFor(m => m.ShowName)%>
+ +
+
<%= Html.ValidationMessageFor(m => m.ShowName)%>
+
+ +
+
+
<%= Html.LabelFor(m => m.EpisodeName)%>
+
<%= Html.CheckBoxFor(m => m.EpisodeName)%>
+ +
+
<%= Html.ValidationMessageFor(m => m.EpisodeName)%>
+
+ +
+
+
<%= Html.LabelFor(m => m.ReplaceSpaces)%>
+
<%= Html.CheckBoxFor(m => m.ReplaceSpaces)%>
+ +
+
<%= Html.ValidationMessageFor(m => m.ReplaceSpaces)%>
+
+ +
+
+
<%= Html.LabelFor(m => m.AppendQuality)%>
+
<%= Html.CheckBoxFor(m => m.AppendQuality)%>
+ +
+
<%= Html.ValidationMessageFor(m => m.AppendQuality)%>
+
+ +
+
+
<%= Html.LabelFor(m => m.UseAirByDate)%>
+
<%= Html.CheckBoxFor(m => m.UseAirByDate)%>
+ +
+
<%= Html.ValidationMessageFor(m => m.UseAirByDate)%>
+
+ +
+
+
<%= Html.LabelFor(m => m.SeasonFolders)%>
+
<%= Html.CheckBoxFor(m => m.SeasonFolders)%>
+ +
+
<%= Html.ValidationMessageFor(m => m.SeasonFolders)%>
+
+ +
+
+
<%= Html.LabelFor(m => m.SeasonFolderFormat)%>
+
<%= Html.TextBoxFor(m => m.SeasonFolderFormat)%>
+
+
<%= Html.ValidationMessageFor(m => m.SeasonFolderFormat)%>
+
+ +
+
+
<%= Html.LabelFor(m => m.SeparatorStyle) %>
+
<%= Html.DropDownListFor(m => m.SeparatorStyle, Model.SeparatorStyles)%>
+
+
<%= Html.ValidationMessageFor(m => m.SeparatorStyle)%>
+
+ +
+
+
<%= Html.LabelFor(m => m.NumberStyle) %>
+
<%= Html.DropDownListFor(m => m.NumberStyle, Model.NumberStyles)%>
+
+
<%= Html.ValidationMessageFor(m => m.NumberStyle)%>
+
+ +
+
+
<%= Html.LabelFor(m => m.MultiEpisodeStyle) %>
+
<%= Html.DropDownListFor(m => m.MultiEpisodeStyle, Model.MultiEpisodeStyles)%>
+
+
<%= Html.ValidationMessageFor(m => m.MultiEpisodeStyle)%>
+
+ + + + <% } %> +
+
\ No newline at end of file diff --git a/NzbDrone.Web/Views/Settings/SubMenu.ascx b/NzbDrone.Web/Views/Settings/SubMenu.ascx index ca2411bb2..274ee17b0 100644 --- a/NzbDrone.Web/Views/Settings/SubMenu.ascx +++ b/NzbDrone.Web/Views/Settings/SubMenu.ascx @@ -3,11 +3,14 @@ <%@ Import Namespace="Telerik.Web.Mvc.UI" %> <% - Html.Telerik().Menu().Name("Menu").Items(items => {items.Add().Text("General").Action("General", "Settings"); }) - .Items(items => items.Add().Text("Indexers").Action("Indexers", "Settings")) - .Items(items => items.Add().Text("Downloads").Action("Downloads", "Settings")) - .Items(items => items.Add().Text("Quality").Action("Quality", "Settings")) - .Render(); + Html.Telerik().Menu().Name("Menu").Items(items => + { + items.Add().Text("General").Action("General", "Settings"); + items.Add().Text("Indexers").Action("Indexers", "Settings"); + items.Add().Text("Downloads").Action("Downloads", "Settings"); + items.Add().Text("Quality").Action("Quality", "Settings"); + items.Add().Text("Episode Sorting").Action("EpisodeSorting", "Settings"); + }).Render(); %> \ No newline at end of file