mirror of https://github.com/lidarr/Lidarr
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; }
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue