New: Smart as default Colon Replacement

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
pull/10484/head
Bogdan 3 days ago
parent 1d286df85d
commit 6686fa0600

@ -13,33 +13,6 @@ import translate from 'Utilities/String/translate';
import NamingModal from './NamingModal';
import styles from './Naming.css';
const colonReplacementOptions = [
{
key: 'delete',
get value() {
return translate('Delete');
}
},
{
key: 'dash',
get value() {
return translate('ReplaceWithDash');
}
},
{
key: 'spaceDash',
get value() {
return translate('ReplaceWithSpaceDash');
}
},
{
key: 'spaceDashSpace',
get value() {
return translate('ReplaceWithSpaceDashSpace');
}
}
];
class Naming extends Component {
//
@ -103,6 +76,14 @@ class Naming extends Component {
const renameMovies = hasSettings && settings.renameMovies.value;
const replaceIllegalCharacters = hasSettings && settings.replaceIllegalCharacters.value;
const colonReplacementOptions = [
{ key: 'delete', value: translate('Delete') },
{ key: 'dash', value: translate('ReplaceWithDash') },
{ key: 'spaceDash', value: translate('ReplaceWithSpaceDash') },
{ key: 'spaceDashSpace', value: translate('ReplaceWithSpaceDashSpace') },
{ key: 'smart', value: translate('SmartReplace'), hint: translate('SmartReplaceHint') }
];
const standardMovieFormatHelpTexts = [];
const standardMovieFormatErrors = [];
const movieFolderFormatHelpTexts = [];

@ -299,7 +299,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
Subject.GetItems().Should().BeEmpty();
}
[TestCase("[ TOWN ]-[ http://www.town.ag ]-[ ANIME ]-[Usenet Provider >> http://www.ssl- <<] - [Commie] Aldnoah Zero 18 [234C8FC7]", "[ TOWN ]-[ http++www.town.ag ]-[ ANIME ]-[Usenet Provider http++www.ssl- ] - [Commie] Aldnoah Zero 18 [234C8FC7].nzb")]
[TestCase("[ TOWN ]-[ http://www.town.ag ]-[ ANIME ]-[Usenet Provider >> http://www.ssl- <<] - [Commie] Aldnoah Zero 18 [234C8FC7]", "[ TOWN ]-[ http-++www.town.ag ]-[ ANIME ]-[Usenet Provider http-++www.ssl- ] - [Commie] Aldnoah Zero 18 [234C8FC7].nzb")]
public async Task Download_should_use_clean_title(string title, string filename)
{
GivenSuccessfulDownload();

@ -0,0 +1,31 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.OrganizerTests
{
[TestFixture]
public class CleanFilenameFixture : CoreTest
{
[TestCase("Mission: Impossible - no [HDTV-720p]", "Mission - Impossible - no [HDTV-720p]")]
public void should_replace_invalid_characters(string name, string expectedName)
{
FileNameBuilder.CleanFileName(name).Should().Be(expectedName);
}
[TestCase(".45 (2006)", "45 (2006)")]
public void should_remove_periods_from_start(string name, string expectedName)
{
FileNameBuilder.CleanFileName(name).Should().Be(expectedName);
}
[TestCase(" The Movie Title", "The Movie Title")]
[TestCase("The Movie Title ", "The Movie Title")]
[TestCase(" The Movie Title ", "The Movie Title")]
public void should_remove_spaces_from_start_and_end(string name, string expectedName)
{
FileNameBuilder.CleanFileName(name).Should().Be(expectedName);
}
}
}

@ -1,20 +0,0 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.OrganizerTests
{
[TestFixture]
public class CleanFixture : CoreTest
{
[TestCase("Mission: Impossible - no [HDTV-720p]",
"Mission Impossible - no [HDTV-720p]")]
[TestCase(".45 (2006)", "45 (2006)")]
[TestCase(" The Movie Title ", "The Movie Title")]
public void CleanFileName(string name, string expectedName)
{
FileNameBuilder.CleanFileName(name).Should().Be(expectedName);
}
}
}

@ -0,0 +1,86 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
{
[TestFixture]
public class ColonReplacementFixture : CoreTest<FileNameBuilder>
{
private Movie _movie;
private MovieFile _movieFile;
private NamingConfig _namingConfig;
[SetUp]
public void Setup()
{
_movie = Builder<Movie>
.CreateNew()
.With(s => s.Title = "CSI: Vegas")
.Build();
_namingConfig = NamingConfig.Default;
_namingConfig.RenameMovies = true;
Mocker.GetMock<INamingConfigService>()
.Setup(c => c.GetConfig()).Returns(_namingConfig);
_movieFile = new MovieFile { Quality = new QualityModel(Quality.HDTV720p), ReleaseGroup = "RadarrTest" };
Mocker.GetMock<IQualityDefinitionService>()
.Setup(v => v.Get(Moq.It.IsAny<Quality>()))
.Returns<Quality>(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v));
Mocker.GetMock<ICustomFormatService>()
.Setup(v => v.All())
.Returns(new List<CustomFormat>());
}
[Test]
public void should_replace_colon_followed_by_space_with_space_dash_space_by_default()
{
_namingConfig.StandardMovieFormat = "{Movie Title}";
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("CSI - Vegas");
}
[TestCase("CSI: Vegas", ColonReplacementFormat.Smart, "CSI - Vegas")]
[TestCase("CSI: Vegas", ColonReplacementFormat.Dash, "CSI- Vegas")]
[TestCase("CSI: Vegas", ColonReplacementFormat.Delete, "CSI Vegas")]
[TestCase("CSI: Vegas", ColonReplacementFormat.SpaceDash, "CSI - Vegas")]
[TestCase("CSI: Vegas", ColonReplacementFormat.SpaceDashSpace, "CSI - Vegas")]
public void should_replace_colon_followed_by_space_with_expected_result(string movieName, ColonReplacementFormat replacementFormat, string expected)
{
_movie.Title = movieName;
_namingConfig.StandardMovieFormat = "{Movie Title}";
_namingConfig.ColonReplacementFormat = replacementFormat;
Subject.BuildFileName(_movie, _movieFile)
.Should().Be(expected);
}
[TestCase("Movie:Title", ColonReplacementFormat.Smart, "Movie-Title")]
[TestCase("Movie:Title", ColonReplacementFormat.Dash, "Movie-Title")]
[TestCase("Movie:Title", ColonReplacementFormat.Delete, "MovieTitle")]
[TestCase("Movie:Title", ColonReplacementFormat.SpaceDash, "Movie -Title")]
[TestCase("Movie:Title", ColonReplacementFormat.SpaceDashSpace, "Movie - Title")]
public void should_replace_colon_with_expected_result(string movieName, ColonReplacementFormat replacementFormat, string expected)
{
_movie.Title = movieName;
_namingConfig.StandardMovieFormat = "{Movie Title}";
_namingConfig.ColonReplacementFormat = replacementFormat;
Subject.BuildFileName(_movie, _movieFile)
.Should().Be(expected);
}
}
}

@ -53,7 +53,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
[TestCase("The Sixth Sense 2 (Thai)", "Sixth Sense 2, The (Thai)")]
[TestCase("The Amazing Race (Latin America)", "Amazing Race, The (Latin America)")]
[TestCase("The Rat Pack (A&E)", "Rat Pack, The (A&E)")]
[TestCase("The Climax: I (Almost) Got Away With It (2016)", "Climax I (Almost) Got Away With It, The (2016)")]
[TestCase("The Climax: I (Almost) Got Away With It (2016)", "Climax - I (Almost) Got Away With It, The (2016)")]
public void should_get_expected_title_back(string title, string expected)
{
_movie.Title = title;

@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(240)]
public class drop_multi_episode_style_from_naming_config : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Delete.Column("MultiEpisodeStyle").FromTable("NamingConfig");
}
}
}

@ -1634,6 +1634,8 @@
"SkipRedownload": "Skip Redownload",
"SkipRedownloadHelpText": "Prevents {appName} from trying to download an alternative release for this item",
"Small": "Small",
"SmartReplace": "Smart Replace",
"SmartReplaceHint": "Dash or Space Dash depending on name",
"Socks4": "Socks4",
"Socks5": "Socks5 (Support TOR)",
"SomeResultsHiddenFilter": "Some results are hidden by the applied filter",

@ -6,7 +6,6 @@ using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Diacritical;
using DryIoc.ImTools;
using NLog;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.Extensions;
@ -80,6 +79,9 @@ namespace NzbDrone.Core.Organizer
{ "wel", "cym" }
}.ToImmutableDictionary();
public static readonly ImmutableArray<string> BadCharacters = ImmutableArray.Create("\\", "/", "<", ">", "?", "*", "|", "\"");
public static readonly ImmutableArray<string> GoodCharacters = ImmutableArray.Create("+", "+", "", "", "!", "-", "", "");
public FileNameBuilder(INamingConfigService namingConfigService,
IQualityDefinitionService qualityDefinitionService,
IUpdateMediaInfo mediaInfoUpdater,
@ -241,20 +243,9 @@ namespace NzbDrone.Core.Organizer
return "_";
}
public static string CleanFileName(string name, bool replace = true, ColonReplacementFormat colonReplacement = ColonReplacementFormat.Delete)
public static string CleanFileName(string name)
{
var colonReplacementFormat = colonReplacement.GetFormatString();
var result = name;
string[] badCharacters = { "\\", "/", "<", ">", "?", "*", ":", "|", "\"" };
string[] goodCharacters = { "+", "+", "", "", "!", "-", colonReplacementFormat, "", "" };
for (var i = 0; i < badCharacters.Length; i++)
{
result = result.Replace(badCharacters[i], replace ? goodCharacters[i] : string.Empty);
}
return result.TrimStart(' ', '.').TrimEnd(' ');
return CleanFileName(name, NamingConfig.Default);
}
public static string CleanFolderName(string name)
@ -585,7 +576,7 @@ namespace NzbDrone.Core.Organizer
replacementText = replacementText.Replace(" ", tokenMatch.Separator);
}
replacementText = CleanFileName(replacementText, namingConfig.ReplaceIllegalCharacters, namingConfig.ColonReplacementFormat);
replacementText = CleanFileName(replacementText, namingConfig);
if (!replacementText.IsNullOrWhiteSpace())
{
@ -657,6 +648,51 @@ namespace NzbDrone.Core.Organizer
return ReservedDeviceNamesRegex.Replace(input, match => match.Value.Replace(".", "_"));
}
private static string CleanFileName(string name, NamingConfig namingConfig)
{
var result = name;
if (namingConfig.ReplaceIllegalCharacters)
{
// Smart replaces a colon followed by a space with space dash space for a better appearance
if (namingConfig.ColonReplacementFormat == ColonReplacementFormat.Smart)
{
result = result.Replace(": ", " - ");
result = result.Replace(":", "-");
}
else
{
var replacement = string.Empty;
switch (namingConfig.ColonReplacementFormat)
{
case ColonReplacementFormat.Dash:
replacement = "-";
break;
case ColonReplacementFormat.SpaceDash:
replacement = " -";
break;
case ColonReplacementFormat.SpaceDashSpace:
replacement = " - ";
break;
}
result = result.Replace(":", replacement);
}
}
else
{
result = result.Replace(":", string.Empty);
}
for (var i = 0; i < BadCharacters.Length; i++)
{
result = result.Replace(BadCharacters[i], namingConfig.ReplaceIllegalCharacters ? GoodCharacters[i] : string.Empty);
}
return result.TrimStart(' ', '.').TrimEnd(' ');
}
private string Truncate(string input, string formatter)
{
if (input.IsNullOrWhiteSpace())
@ -710,13 +746,12 @@ namespace NzbDrone.Core.Organizer
}
}
public enum MultiEpisodeStyle
public enum ColonReplacementFormat
{
Extend = 0,
Duplicate = 1,
Repeat = 2,
Scene = 3,
Range = 4,
PrefixedRange = 5
Delete = 0,
Dash = 1,
SpaceDash = 2,
SpaceDashSpace = 3,
Smart = 4
}
}

@ -8,8 +8,7 @@ namespace NzbDrone.Core.Organizer
{
RenameMovies = false,
ReplaceIllegalCharacters = true,
ColonReplacementFormat = 0,
MultiEpisodeStyle = 0,
ColonReplacementFormat = ColonReplacementFormat.Smart,
MovieFolderFormat = "{Movie Title} ({Release Year})",
StandardMovieFormat = "{Movie Title} ({Release Year}) {Quality Full}",
};
@ -17,36 +16,7 @@ namespace NzbDrone.Core.Organizer
public bool RenameMovies { get; set; }
public bool ReplaceIllegalCharacters { get; set; }
public ColonReplacementFormat ColonReplacementFormat { get; set; }
public int MultiEpisodeStyle { get; set; }
public string StandardMovieFormat { get; set; }
public string MovieFolderFormat { get; set; }
}
public enum ColonReplacementFormat
{
Delete = 0,
Dash = 1,
SpaceDash = 2,
SpaceDashSpace = 3
}
public static class ColonReplacementFormatMethods
{
public static string GetFormatString(this ColonReplacementFormat format)
{
switch (format)
{
case ColonReplacementFormat.Delete:
return "";
case ColonReplacementFormat.Dash:
return "-";
case ColonReplacementFormat.SpaceDash:
return " -";
case ColonReplacementFormat.SpaceDashSpace:
return " - ";
default:
return "";
}
}
}
}

Loading…
Cancel
Save