New: Option to remove illegal characters

Closes #809
pull/832/head
Mark McDowall 9 years ago
parent 68cd9ab8c8
commit 192d001b61

@ -6,6 +6,7 @@ namespace NzbDrone.Api.Config
public class NamingConfigResource : RestResource public class NamingConfigResource : RestResource
{ {
public bool RenameEpisodes { get; set; } public bool RenameEpisodes { get; set; }
public bool ReplaceIllegalCharacters { get; set; }
public int MultiEpisodeStyle { get; set; } public int MultiEpisodeStyle { get; set; }
public string StandardEpisodeFormat { get; set; } public string StandardEpisodeFormat { get; set; }
public string DailyEpisodeFormat { get; set; } public string DailyEpisodeFormat { get; set; }

@ -17,7 +17,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
namingConfig = new NamingConfig(); namingConfig = NamingConfig.Default;
Mocker.GetMock<INamingConfigService>() Mocker.GetMock<INamingConfigService>()
.Setup(c => c.GetConfig()).Returns(namingConfig); .Setup(c => c.GetConfig()).Returns(namingConfig);

@ -36,7 +36,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
_episodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p), ReleaseGroup = "SonarrTest" }; _episodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p), ReleaseGroup = "SonarrTest" };
_namingConfig = new NamingConfig(); _namingConfig = NamingConfig.Default;
_namingConfig.RenameEpisodes = true; _namingConfig.RenameEpisodes = true;
Mocker.GetMock<INamingConfigService>() Mocker.GetMock<INamingConfigService>()

@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
.Build(); .Build();
_namingConfig = new NamingConfig(); _namingConfig = NamingConfig.Default;
_namingConfig.RenameEpisodes = true; _namingConfig.RenameEpisodes = true;

@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
.Build(); .Build();
_namingConfig = new NamingConfig(); _namingConfig = NamingConfig.Default;
_namingConfig.RenameEpisodes = true; _namingConfig.RenameEpisodes = true;

@ -33,7 +33,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
.Build(); .Build();
_namingConfig = new NamingConfig(); _namingConfig = NamingConfig.Default;
_namingConfig.RenameEpisodes = true; _namingConfig.RenameEpisodes = true;

@ -15,7 +15,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
namingConfig = new NamingConfig(); namingConfig = NamingConfig.Default;
Mocker.GetMock<INamingConfigService>() Mocker.GetMock<INamingConfigService>()
.Setup(c => c.GetConfig()).Returns(namingConfig); .Setup(c => c.GetConfig()).Returns(namingConfig);

@ -1,4 +1,3 @@
using System;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Organizer; using NzbDrone.Core.Organizer;
@ -16,7 +15,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
namingConfig = new NamingConfig(); namingConfig = NamingConfig.Default;
Mocker.GetMock<INamingConfigService>() Mocker.GetMock<INamingConfigService>()
.Setup(c => c.GetConfig()).Returns(namingConfig); .Setup(c => c.GetConfig()).Returns(namingConfig);

@ -0,0 +1,15 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(93)]
public class naming_config_replace_illegal_characters : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("NamingConfig").AddColumn("ReplaceIllegalCharacters").AsBoolean().WithDefaultValue(true);
Update.Table("NamingConfig").Set(new { ReplaceIllegalCharacters = true }).AllRows();
}
}
}

@ -270,6 +270,7 @@
<Compile Include="Datastore\Migration\089_add_on_rename_to_notifcations.cs" /> <Compile Include="Datastore\Migration\089_add_on_rename_to_notifcations.cs" />
<Compile Include="Datastore\Migration\090_update_kickass_url.cs" /> <Compile Include="Datastore\Migration\090_update_kickass_url.cs" />
<Compile Include="Datastore\Migration\091_added_indexerstatus.cs" /> <Compile Include="Datastore\Migration\091_added_indexerstatus.cs" />
<Compile Include="Datastore\Migration\093_naming_config_replace_characters.cs" />
<Compile Include="Datastore\Migration\092_add_unverifiedscenenumbering.cs" /> <Compile Include="Datastore\Migration\092_add_unverifiedscenenumbering.cs" />
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" /> <Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" /> <Compile Include="Datastore\Migration\Framework\MigrationController.cs" />

@ -128,7 +128,7 @@ namespace NzbDrone.Core.Organizer
AddQualityTokens(tokenHandlers, series, episodeFile); AddQualityTokens(tokenHandlers, series, episodeFile);
AddMediaInfoTokens(tokenHandlers, episodeFile); AddMediaInfoTokens(tokenHandlers, episodeFile);
var fileName = ReplaceTokens(pattern, tokenHandlers).Trim(); var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim();
fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString()); fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString());
fileName = TrimSeparatorsRegex.Replace(fileName, string.Empty); fileName = TrimSeparatorsRegex.Replace(fileName, string.Empty);
@ -224,7 +224,7 @@ namespace NzbDrone.Core.Organizer
AddSeriesTokens(tokenHandlers, series); AddSeriesTokens(tokenHandlers, series);
return CleanFolderName(ReplaceTokens(namingConfig.SeriesFolderFormat, tokenHandlers)); return CleanFolderName(ReplaceTokens(namingConfig.SeriesFolderFormat, tokenHandlers, namingConfig));
} }
public string GetSeasonFolder(Series series, int seasonNumber, NamingConfig namingConfig = null) public string GetSeasonFolder(Series series, int seasonNumber, NamingConfig namingConfig = null)
@ -239,7 +239,7 @@ namespace NzbDrone.Core.Organizer
AddSeriesTokens(tokenHandlers, series); AddSeriesTokens(tokenHandlers, series);
AddSeasonTokens(tokenHandlers, seasonNumber); AddSeasonTokens(tokenHandlers, seasonNumber);
return CleanFolderName(ReplaceTokens(namingConfig.SeasonFolderFormat, tokenHandlers)); return CleanFolderName(ReplaceTokens(namingConfig.SeasonFolderFormat, tokenHandlers, namingConfig));
} }
public static string CleanTitle(string title) public static string CleanTitle(string title)
@ -251,7 +251,7 @@ namespace NzbDrone.Core.Organizer
return title; return title;
} }
public static string CleanFileName(string name) public static string CleanFileName(string name, bool replace = true)
{ {
string result = name; string result = name;
string[] badCharacters = { "\\", "/", "<", ">", "?", "*", ":", "|", "\"" }; string[] badCharacters = { "\\", "/", "<", ">", "?", "*", ":", "|", "\"" };
@ -259,7 +259,7 @@ namespace NzbDrone.Core.Organizer
for (int i = 0; i < badCharacters.Length; i++) for (int i = 0; i < badCharacters.Length; i++)
{ {
result = result.Replace(badCharacters[i], goodCharacters[i]); result = result.Replace(badCharacters[i], replace ? goodCharacters[i] : string.Empty);
} }
return result.Trim(); return result.Trim();
@ -551,12 +551,12 @@ namespace NzbDrone.Core.Organizer
return string.Join("+", tokens.Distinct()); return string.Join("+", tokens.Distinct());
} }
private string ReplaceTokens(string pattern, Dictionary<string, Func<TokenMatch, string>> tokenHandlers) private string ReplaceTokens(string pattern, Dictionary<string, Func<TokenMatch, string>> tokenHandlers, NamingConfig namingConfig)
{ {
return TitleRegex.Replace(pattern, match => ReplaceToken(match, tokenHandlers)); return TitleRegex.Replace(pattern, match => ReplaceToken(match, tokenHandlers, namingConfig));
} }
private string ReplaceToken(Match match, Dictionary<string, Func<TokenMatch, string>> tokenHandlers) private string ReplaceToken(Match match, Dictionary<string, Func<TokenMatch, string>> tokenHandlers, NamingConfig namingConfig)
{ {
var tokenMatch = new TokenMatch var tokenMatch = new TokenMatch
{ {
@ -591,7 +591,7 @@ namespace NzbDrone.Core.Organizer
replacementText = replacementText.Replace(" ", tokenMatch.Separator); replacementText = replacementText.Replace(" ", tokenMatch.Separator);
} }
replacementText = CleanFileName(replacementText); replacementText = CleanFileName(replacementText, namingConfig.ReplaceIllegalCharacters);
if (!replacementText.IsNullOrWhiteSpace()) if (!replacementText.IsNullOrWhiteSpace())
{ {

@ -11,6 +11,7 @@ namespace NzbDrone.Core.Organizer
return new NamingConfig return new NamingConfig
{ {
RenameEpisodes = false, RenameEpisodes = false,
ReplaceIllegalCharacters = true,
MultiEpisodeStyle = 0, MultiEpisodeStyle = 0,
StandardEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Episode Title} {Quality Full}", StandardEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Episode Title} {Quality Full}",
DailyEpisodeFormat = "{Series Title} - {Air-Date} - {Episode Title} {Quality Full}", DailyEpisodeFormat = "{Series Title} - {Air-Date} - {Episode Title} {Quality Full}",
@ -22,6 +23,7 @@ namespace NzbDrone.Core.Organizer
} }
public bool RenameEpisodes { get; set; } public bool RenameEpisodes { get; set; }
public bool ReplaceIllegalCharacters { get; set; }
public int MultiEpisodeStyle { get; set; } public int MultiEpisodeStyle { get; set; }
public string StandardEpisodeFormat { get; set; } public string StandardEpisodeFormat { get; set; }
public string DailyEpisodeFormat { get; set; } public string DailyEpisodeFormat { get; set; }
@ -29,4 +31,4 @@ namespace NzbDrone.Core.Organizer
public string SeriesFolderFormat { get; set; } public string SeriesFolderFormat { get; set; }
public string SeasonFolderFormat { get; set; } public string SeasonFolderFormat { get; set; }
} }
} }

@ -24,6 +24,29 @@
</div> </div>
</div> </div>
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Replace Illegal Characters</label>
<div class="col-sm-8">
<div class="input-group">
<label class="checkbox toggle well">
<input type="checkbox" name="replaceIllegalCharacters" />
<p>
<span>Yes</span>
<span>No</span>
</p>
<div class="btn btn-primary slide-button"/>
</label>
<span class="help-inline-checkbox">
<i class="icon-sonarr-form-info" title="Replace or Remove illegal characters"/>
</span>
</div>
</div>
</div>
<div class="x-naming-options"> <div class="x-naming-options">
<div class="basic-setting x-basic-naming"></div> <div class="basic-setting x-basic-naming"></div>
@ -184,7 +207,7 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">Single Episode Example</label> <label class="col-sm-3 control-label">Single Episode Example</label>
<div class="col-sm-8"> <div class="col-sm-8">
<p class="form-control-static x-single-episode-example naming-example"></p> <p class="form-control-static x-single-episode-example naming-example"></p>
</div> </div>

Loading…
Cancel
Save