Added: Setting for Colon Replacement Format (#2711)

Fixes #2140
Fixes #2657
pull/2/head
Qstick 6 years ago committed by Leonardo Galli
parent 38932d82db
commit 210902ecb6

@ -34,11 +34,6 @@ namespace NzbDrone.Api.Config
Get["/samples"] = x => GetExamples(this.Bind<NamingConfigResource>());
SharedValidator.RuleFor(c => c.MultiEpisodeStyle).InclusiveBetween(0, 5);
/*SharedValidator.RuleFor(c => c.StandardEpisodeFormat).ValidEpisodeFormat();
SharedValidator.RuleFor(c => c.DailyEpisodeFormat).ValidDailyEpisodeFormat();
SharedValidator.RuleFor(c => c.AnimeEpisodeFormat).ValidAnimeEpisodeFormat();
SharedValidator.RuleFor(c => c.SeriesFolderFormat).ValidSeriesFolderFormat();
SharedValidator.RuleFor(c => c.SeasonFolderFormat).ValidSeasonFolderFormat();*/
SharedValidator.RuleFor(c => c.StandardMovieFormat).ValidMovieFormat();
SharedValidator.RuleFor(c => c.MovieFolderFormat).ValidMovieFolderFormat();
}
@ -56,12 +51,6 @@ namespace NzbDrone.Api.Config
var nameSpec = _namingConfigService.GetConfig();
var resource = nameSpec.ToResource();
//if (resource.StandardEpisodeFormat.IsNotNullOrWhiteSpace())
//{
// var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
// basicConfig.AddToResource(resource);
//}
if (resource.StandardMovieFormat.IsNotNullOrWhiteSpace())
{
var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
@ -80,48 +69,13 @@ namespace NzbDrone.Api.Config
{
var nameSpec = config.ToModel();
var sampleResource = new NamingSampleResource();
//var singleEpisodeSampleResult = _filenameSampleService.GetStandardSample(nameSpec);
//var multiEpisodeSampleResult = _filenameSampleService.GetMultiEpisodeSample(nameSpec);
//var dailyEpisodeSampleResult = _filenameSampleService.GetDailySample(nameSpec);
//var animeEpisodeSampleResult = _filenameSampleService.GetAnimeSample(nameSpec);
//var animeMultiEpisodeSampleResult = _filenameSampleService.GetAnimeMultiEpisodeSample(nameSpec);
var movieSampleResult = _filenameSampleService.GetMovieSample(nameSpec);
//sampleResource.SingleEpisodeExample = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult) != null
// ? "Invalid format"
// : singleEpisodeSampleResult.FileName;
//sampleResource.MultiEpisodeExample = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult) != null
// ? "Invalid format"
// : multiEpisodeSampleResult.FileName;
//sampleResource.DailyEpisodeExample = _filenameValidationService.ValidateDailyFilename(dailyEpisodeSampleResult) != null
// ? "Invalid format"
// : dailyEpisodeSampleResult.FileName;
//sampleResource.AnimeEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult) != null
// ? "Invalid format"
// : animeEpisodeSampleResult.FileName;
//sampleResource.AnimeMultiEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeMultiEpisodeSampleResult) != null
// ? "Invalid format"
// : animeMultiEpisodeSampleResult.FileName;
sampleResource.MovieExample = nameSpec.StandardMovieFormat.IsNullOrWhiteSpace()
? "Invalid Format"
: movieSampleResult.FileName;
//sampleResource.SeriesFolderExample = nameSpec.SeriesFolderFormat.IsNullOrWhiteSpace()
// ? "Invalid format"
// : _filenameSampleService.GetSeriesFolderSample(nameSpec);
//sampleResource.SeasonFolderExample = nameSpec.SeasonFolderFormat.IsNullOrWhiteSpace()
// ? "Invalid format"
// : _filenameSampleService.GetSeasonFolderSample(nameSpec);
sampleResource.MovieFolderExample = nameSpec.MovieFolderFormat.IsNullOrWhiteSpace()
? "Invalid format"
: _filenameSampleService.GetMovieFolderSample(nameSpec);
@ -137,12 +91,6 @@ namespace NzbDrone.Api.Config
var validationFailures = new List<ValidationFailure>();
//validationFailures.AddIfNotNull(singleEpisodeValidationResult);
//validationFailures.AddIfNotNull(multiEpisodeValidationResult);
//validationFailures.AddIfNotNull(dailyEpisodeValidationResult);
//validationFailures.AddIfNotNull(animeEpisodeValidationResult);
//validationFailures.AddIfNotNull(animeMultiEpisodeValidationResult);
//validationFailures.AddIfNotNull(standardMovieValidationResult);
if (validationFailures.Any())

@ -7,6 +7,7 @@ namespace NzbDrone.Api.Config
{
public bool RenameEpisodes { get; set; }
public bool ReplaceIllegalCharacters { get; set; }
public ColonReplacementFormat ColonReplacementFormat { get; set; }
public string StandardMovieFormat { get; set; }
public string MovieFolderFormat { get; set; }
public int MultiEpisodeStyle { get; set; }
@ -28,6 +29,7 @@ namespace NzbDrone.Api.Config
RenameEpisodes = model.RenameEpisodes,
ReplaceIllegalCharacters = model.ReplaceIllegalCharacters,
ColonReplacementFormat = model.ColonReplacementFormat,
MultiEpisodeStyle = model.MultiEpisodeStyle,
StandardMovieFormat = model.StandardMovieFormat,
MovieFolderFormat = model.MovieFolderFormat
@ -58,12 +60,7 @@ namespace NzbDrone.Api.Config
RenameEpisodes = resource.RenameEpisodes,
ReplaceIllegalCharacters = resource.ReplaceIllegalCharacters,
//MultiEpisodeStyle = resource.MultiEpisodeStyle,
//StandardEpisodeFormat = resource.StandardEpisodeFormat,
//DailyEpisodeFormat = resource.DailyEpisodeFormat,
//AnimeEpisodeFormat = resource.AnimeEpisodeFormat,
//SeriesFolderFormat = resource.SeriesFolderFormat,
//SeasonFolderFormat = resource.SeasonFolderFormat,
ColonReplacementFormat = resource.ColonReplacementFormat,
StandardMovieFormat = resource.StandardMovieFormat,
MovieFolderFormat = resource.MovieFolderFormat
};

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
@ -66,7 +66,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
{ "uri", CleanFileName(_remoteEpisode.Release.Title) }
},
Transfer = new Dictionary<string, string>
{
@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
{ "uri", CleanFileName(_remoteEpisode.Release.Title) }
},
Transfer = new Dictionary<string, string>
{
@ -112,7 +112,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
{ "uri", CleanFileName(_remoteEpisode.Release.Title) }
},
Transfer = new Dictionary<string, string>
{
@ -135,7 +135,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
{ "uri", CleanFileName(_remoteEpisode.Release.Title) }
},
Transfer = new Dictionary<string, string>
{
@ -158,7 +158,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
{ "uri", CleanFileName(_remoteEpisode.Release.Title) }
},
Transfer = new Dictionary<string, string>
{
@ -247,6 +247,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
.Returns(tasks);
}
protected static string CleanFileName(String name)
{
return FileNameBuilder.CleanFileName(name, NamingConfig.Default) + ".nzb";
}
[Test]
public void Download_with_TvDirectory_should_force_directory()
{

@ -12,8 +12,8 @@ namespace NzbDrone.Core.Test.OrganizerTests
"Mission Impossible - no [HDTV-720p]")]
public void CleanFileName(string name, string expectedName)
{
FileNameBuilder.CleanFileName(name).Should().Be(expectedName);
FileNameBuilder.CleanFileName(name, NamingConfig.Default).Should().Be(expectedName);
}
}
}
}

@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(146)]
public class naming_config_colon_action : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("NamingConfig").AddColumn("ColonReplacementFormat").AsInt32().NotNullable().WithDefaultValue(0);
}
}
}

@ -1,4 +1,4 @@
using NLog;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Crypto;
using NzbDrone.Common.Disk;
@ -23,13 +23,15 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
private readonly Logger _logger;
private readonly IDiskProvider _diskProvider;
private readonly IDiskScanService _diskScanService;
private readonly INamingConfigService _namingConfigService;
private readonly ICached<Dictionary<string, WatchFolderItem>> _watchFolderItemCache;
public ScanWatchFolder(ICacheManager cacheManager, IDiskScanService diskScanService, IDiskProvider diskProvider, Logger logger)
public ScanWatchFolder(ICacheManager cacheManager, IDiskScanService diskScanService, INamingConfigService namingConfigService, IDiskProvider diskProvider, Logger logger)
{
_logger = logger;
_diskProvider = diskProvider;
_diskScanService = diskScanService;
_namingConfigService = namingConfigService;
_watchFolderItemCache = cacheManager.GetCache<Dictionary<string, WatchFolderItem>>(GetType());
}
@ -50,9 +52,12 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
private IEnumerable<WatchFolderItem> GetDownloadItems(string watchFolder, Dictionary<string, WatchFolderItem> lastWatchItems, TimeSpan waitPeriod)
{
// get a fresh naming config each time, in case the user has made changes
NamingConfig namingConfig = _namingConfigService.GetConfig();
foreach (var folder in _diskProvider.GetDirectories(watchFolder))
{
var title = FileNameBuilder.CleanFileName(Path.GetFileName(folder));
var title = FileNameBuilder.CleanFileName(Path.GetFileName(folder), namingConfig);
var newWatchItem = new WatchFolderItem
{
@ -88,7 +93,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
foreach (var videoFile in _diskScanService.GetVideoFiles(watchFolder, false))
{
var title = FileNameBuilder.CleanFileName(Path.GetFileName(videoFile));
var title = FileNameBuilder.CleanFileName(Path.GetFileName(videoFile), namingConfig);
var newWatchItem = new WatchFolderItem
{

@ -28,10 +28,11 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_scanWatchFolder = scanWatchFolder;
@ -47,7 +48,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
var title = remoteMovie.Release.Title;
title = FileNameBuilder.CleanFileName(title);
title = CleanFileName(title);
var filepath = Path.Combine(Settings.TorrentFolder, string.Format("{0}.magnet", title));
@ -66,7 +67,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
{
var title = remoteMovie.Release.Title;
title = FileNameBuilder.CleanFileName(title);
title = CleanFileName(title);
var filepath = Path.Combine(Settings.TorrentFolder, string.Format("{0}.torrent", title));

@ -22,10 +22,11 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
public UsenetBlackhole(IScanWatchFolder scanWatchFolder,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_scanWatchFolder = scanWatchFolder;
@ -36,7 +37,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
{
var title = remoteMovie.Release.Title;
title = FileNameBuilder.CleanFileName(title);
title = CleanFileName(title);
var filepath = Path.Combine(Settings.NzbFolder, title + ".nzb");

@ -12,6 +12,7 @@ using NLog;
using FluentValidation.Results;
using System.Net;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download.Clients.Deluge
{
@ -23,10 +24,11 @@ namespace NzbDrone.Core.Download.Clients.Deluge
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_proxy = proxy;
}

@ -11,6 +11,7 @@ using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Validation;
@ -33,10 +34,11 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_dsInfoProxy = dsInfoProxy;
_dsTaskProxy = dsTaskProxy;

@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Validation;
@ -30,11 +31,12 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
IDownloadStationTaskProxy dsTaskProxy,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger
)
: base(httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_dsInfoProxy = dsInfoProxy;
_dsTaskProxy = dsTaskProxy;

@ -9,6 +9,7 @@ using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.Hadouken.Models;
using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Validation;
@ -23,10 +24,11 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_proxy = proxy;
}

@ -11,6 +11,7 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download.Clients.NzbVortex
{
@ -21,10 +22,11 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
public NzbVortex(INzbVortexProxy proxy,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_proxy = proxy;
}

@ -11,6 +11,7 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download.Clients.Nzbget
{
@ -23,10 +24,11 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
public Nzbget(INzbgetProxy proxy,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_proxy = proxy;
}

@ -20,10 +20,11 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
public Pneumatic(IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(configService, diskProvider, remotePathMappingService, logger)
: base(configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_httpClient = httpClient;
}
@ -43,7 +44,7 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
// throw new NotSupportedException("Full season releases are not supported with Pneumatic.");
//}
title = FileNameBuilder.CleanFileName(title);
title = CleanFileName(title);
//Save to the Pneumatic directory (The user will need to ensure its accessible by XBMC)
var nzbFile = Path.Combine(Settings.NzbFolder, title + ".nzb");
@ -70,7 +71,7 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
continue;
}
var title = FileNameBuilder.CleanFileName(Path.GetFileName(file));
var title = CleanFileName(Path.GetFileName(file));
var historyItem = new DownloadClientItem
{

@ -12,6 +12,7 @@ using FluentValidation.Results;
using System.Net;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download.Clients.QBittorrent
{
@ -23,10 +24,11 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_proxy = proxy;
}

@ -11,6 +11,7 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
@ -21,10 +22,11 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
public Sabnzbd(ISabnzbdProxy proxy,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_proxy = proxy;
}

@ -1,4 +1,4 @@
using System;
using System;
using System.Text.RegularExpressions;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Http;
@ -7,6 +7,7 @@ using NLog;
using FluentValidation.Results;
using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download.Clients.Transmission
{
@ -16,10 +17,11 @@ namespace NzbDrone.Core.Download.Clients.Transmission
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(proxy, torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
}

@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Validation;
@ -23,10 +24,11 @@ namespace NzbDrone.Core.Download.Clients.Transmission
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_proxy = proxy;
}

@ -1,10 +1,11 @@
using FluentValidation.Results;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.Transmission;
using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.RemotePathMappings;
namespace NzbDrone.Core.Download.Clients.Vuze
@ -17,10 +18,11 @@ namespace NzbDrone.Core.Download.Clients.Vuze
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(proxy, torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(proxy, torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
}

@ -15,6 +15,7 @@ using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download.Clients.RTorrent
{
@ -27,11 +28,12 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
IRTorrentDirectoryValidator rTorrentDirectoryValidator,
Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_proxy = proxy;
_rTorrentDirectoryValidator = rTorrentDirectoryValidator;

@ -13,6 +13,7 @@ using System.Net;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Common.Cache;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download.Clients.UTorrent
{
@ -26,10 +27,11 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger)
: base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_proxy = proxy;

@ -11,6 +11,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download
{
@ -18,6 +19,7 @@ namespace NzbDrone.Core.Download
where TSettings : IProviderConfig, new()
{
protected readonly IConfigService _configService;
protected readonly INamingConfigService _namingConfigService;
protected readonly IDiskProvider _diskProvider;
protected readonly IRemotePathMappingService _remotePathMappingService;
protected readonly Logger _logger;
@ -39,12 +41,14 @@ namespace NzbDrone.Core.Download
protected TSettings Settings => (TSettings)Definition.Settings;
protected DownloadClientBase(IConfigService configService,
protected DownloadClientBase(IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
{
_configService = configService;
_namingConfigService = namingConfigService;
_diskProvider = diskProvider;
_remotePathMappingService = remotePathMappingService;
_logger = logger;
@ -151,6 +155,13 @@ namespace NzbDrone.Core.Download
return null;
}
// proxy method to pass in our naming config
protected String CleanFileName(string name)
{
// get a fresh naming config each time, in case the user has made changes
NamingConfig namingConfig = _namingConfigService.GetConfig();
return FileNameBuilder.CleanFileName(name, namingConfig);
}
}
}

@ -25,10 +25,11 @@ namespace NzbDrone.Core.Download
protected TorrentClientBase(ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(configService, diskProvider, remotePathMappingService, logger)
: base(configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_httpClient = httpClient;
_torrentFileInfoReader = torrentFileInfoReader;
@ -178,7 +179,7 @@ namespace NzbDrone.Core.Download
throw new ReleaseDownloadException(remoteMovie.Release, "Downloading torrent failed", ex);
}
var filename = string.Format("{0}.torrent", FileNameBuilder.CleanFileName(remoteMovie.Release.Title));
var filename = string.Format("{0}.torrent", CleanFileName(remoteMovie.Release.Title));
var hash = _torrentFileInfoReader.GetHashFromTorrentFile(torrentFile);
var actualHash = AddFromTorrentFile(remoteMovie, hash, filename, torrentFile);

@ -20,10 +20,11 @@ namespace NzbDrone.Core.Download
protected UsenetClientBase(IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
Logger logger)
: base(configService, diskProvider, remotePathMappingService, logger)
: base(configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_httpClient = httpClient;
}
@ -35,7 +36,7 @@ namespace NzbDrone.Core.Download
public override string Download(RemoteMovie remoteMovie)
{
var url = remoteMovie.Release.DownloadUrl;
var filename = FileNameBuilder.CleanFileName(remoteMovie.Release.Title) + ".nzb";
var filename = CleanFileName(remoteMovie.Release.Title) + ".nzb";
byte[] nzbData;

@ -124,6 +124,7 @@
<Compile Include="Authentication\UserRepository.cs" />
<Compile Include="Authentication\UserService.cs" />
<Compile Include="Datastore\Migration\123_create_netimport_table.cs" />
<Compile Include="Datastore\Migration\146_naming_config_colon_replacement_format.cs" />
<Compile Include="Datastore\Migration\143_clean_core_tv.cs" />
<Compile Include="Datastore\Migration\142_movie_extras.cs" />
<Compile Include="Datastore\Migration\140_add_alternative_titles_table.cs" />
@ -1300,4 +1301,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

@ -248,8 +248,9 @@ namespace NzbDrone.Core.Organizer
{
AddMovieFileTokens(tokenHandlers, new MovieFile { SceneName = $"{movie.Title} {movie.Year}", RelativePath = $"{movie.Title} {movie.Year}"});
}
return CleanFolderName(ReplaceTokens(namingConfig.MovieFolderFormat, tokenHandlers, namingConfig));
string name = ReplaceTokens(namingConfig.MovieFolderFormat, tokenHandlers, namingConfig);
return CleanFolderName(name, namingConfig);
}
public static string CleanTitle(string title)
@ -283,11 +284,14 @@ namespace NzbDrone.Core.Organizer
return title.Trim();
}
public static string CleanFileName(string name, bool replace = true)
public static string CleanFileName(string name, NamingConfig namingConfig)
{
bool replace = namingConfig.ReplaceIllegalCharacters;
var colonReplacementFormat = namingConfig.ColonReplacementFormat.GetFormatString();
string result = name;
string[] badCharacters = { "\\", "/", "<", ">", "?", "*", ":", "|", "\"" };
string[] goodCharacters = { "+", "+", "", "", "!", "-", "", "", "" };
string[] goodCharacters = { "+", "+", "", "", "!", "-", colonReplacementFormat, "", "" };
for (int i = 0; i < badCharacters.Length; i++)
{
@ -297,12 +301,12 @@ namespace NzbDrone.Core.Organizer
return result.Trim();
}
public static string CleanFolderName(string name)
public static string CleanFolderName(string name, NamingConfig namingConfig)
{
name = FileNameCleanupRegex.Replace(name, match => match.Captures[0].Value[0].ToString());
name = name.Trim(' ', '.');
return CleanFileName(name);
return CleanFileName(name, namingConfig);
}
private void AddMovieTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Movie movie)
@ -557,7 +561,7 @@ namespace NzbDrone.Core.Organizer
replacementText = replacementText.Replace(" ", tokenMatch.Separator);
}
replacementText = CleanFileName(replacementText, namingConfig.ReplaceIllegalCharacters);
replacementText = CleanFileName(replacementText, namingConfig);
if (!replacementText.IsNullOrWhiteSpace())
{

@ -1,3 +1,4 @@
using System;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Organizer
@ -8,6 +9,7 @@ namespace NzbDrone.Core.Organizer
{
RenameEpisodes = false,
ReplaceIllegalCharacters = true,
ColonReplacementFormat = 0,
MultiEpisodeStyle = 0,
MovieFolderFormat = "{Movie Title} ({Release Year})",
StandardMovieFormat = "{Movie Title} ({Release Year}) {Quality Full}",
@ -15,8 +17,38 @@ namespace NzbDrone.Core.Organizer
public bool RenameEpisodes { 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
}
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 "";
}
}
}
}

@ -11,29 +11,27 @@ module.exports = (function() {
ui : {
namingOptions : '.x-naming-options',
renameEpisodesCheckbox : '.x-rename-episodes',
singleEpisodeExample : '.x-single-episode-example',
multiEpisodeExample : '.x-multi-episode-example',
dailyEpisodeExample : '.x-daily-episode-example',
animeEpisodeExample : '.x-anime-episode-example',
animeMultiEpisodeExample : '.x-anime-multi-episode-example',
replacingOptions : '.x-replacing-options',
replaceIllegalChars : '.x-replace-illegal-chars',
namingTokenHelper : '.x-naming-token-helper',
multiEpisodeStyle : '.x-multi-episode-style',
seriesFolderExample : '.x-series-folder-example',
seasonFolderExample : '.x-season-folder-example',
movieExample : '.x-movie-example',
movieFolderExample : '.x-movie-folder-example'
},
events : {
"change .x-rename-episodes" : '_setFailedDownloadOptionsVisibility',
"click .x-show-wizard" : '_showWizard',
"click .x-naming-token-helper a" : '_addToken',
"change .x-multi-episode-style" : '_multiEpisodeFomatChanged'
'change .x-rename-episodes' : '_setRenameEpisodesVisibility',
'change .x-replace-illegal-chars': '_setReplaceIllegalCharsVisibility',
'click .x-show-wizard' : '_showWizard',
'click .x-naming-token-helper a' : '_addToken',
'change .x-multi-episode-style' : '_multiEpisodeFomatChanged'
},
regions : { basicNamingRegion : '.x-basic-naming' },
onRender : function() {
if (!this.model.get('renameEpisodes')) {
this.ui.namingOptions.hide();
}
if (!this.model.get('replaceIllegalCharacters')) {
this.ui.replacingOptions.hide();
}
var basicNamingView = new BasicNamingView({ model : this.model });
this.basicNamingRegion.show(basicNamingView);
this.namingSampleModel = new NamingSampleModel();
@ -41,7 +39,7 @@ module.exports = (function() {
this.listenTo(this.namingSampleModel, 'sync', this._showSamples);
this._updateSamples();
},
_setFailedDownloadOptionsVisibility : function() {
_setRenameEpisodesVisibility : function() {
var checked = this.ui.renameEpisodesCheckbox.prop('checked');
if (checked) {
this.ui.namingOptions.slideDown();
@ -49,17 +47,18 @@ module.exports = (function() {
this.ui.namingOptions.slideUp();
}
},
_setReplaceIllegalCharsVisibility : function() {
var checked = this.ui.replaceIllegalChars.prop('checked');
if (checked) {
this.ui.replacingOptions.slideDown();
} else {
this.ui.replacingOptions.slideUp();
}
},
_updateSamples : function() {
this.namingSampleModel.fetch({ data : this.model.toJSON() });
},
_showSamples : function() {
this.ui.singleEpisodeExample.html(this.namingSampleModel.get('singleEpisodeExample'));
this.ui.multiEpisodeExample.html(this.namingSampleModel.get('multiEpisodeExample'));
this.ui.dailyEpisodeExample.html(this.namingSampleModel.get('dailyEpisodeExample'));
this.ui.animeEpisodeExample.html(this.namingSampleModel.get('animeEpisodeExample'));
this.ui.animeMultiEpisodeExample.html(this.namingSampleModel.get('animeMultiEpisodeExample'));
this.ui.seriesFolderExample.html(this.namingSampleModel.get('seriesFolderExample'));
this.ui.seasonFolderExample.html(this.namingSampleModel.get('seasonFolderExample'));
this.ui.movieExample.html(this.namingSampleModel.get('movieExample'));
this.ui.movieFolderExample.html(this.namingSampleModel.get('movieFolderExample'));
},
@ -86,4 +85,4 @@ module.exports = (function() {
AsModelBoundView.call(view);
AsValidatedView.call(view);
return view;
}).call(this);
}).call(this);

@ -24,126 +24,82 @@
</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="basic-setting x-basic-naming"></div>
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Standard Movie Format</label>
<label class="col-sm-3 control-label">Replace Illegal Characters</label>
<div class="col-sm-1 col-sm-push-8 help-inline">
<i class="icon-sonarr-form-info" title="" data-original-title="All caps or all lower-case can also be used"></i>
<a href="https://github.com/Radarr/Radarr/wiki/Sorting-and-Renaming" class="help-link" title="More information"><i class="icon-sonarr-form-info-link"/></a>
</div>
<div class="col-sm-8">
<div class="input-group">
<label class="checkbox toggle well">
<input type="checkbox" name="replaceIllegalCharacters" class="x-replace-illegal-chars"/>
<div class="col-sm-8 col-sm-pull-1">
<div class="input-group x-helper-input">
<input type="text" class="form-control naming-format" name="standardMovieFormat" data-onkeyup="true" />
<div class="input-group-btn btn-group x-naming-token-helper">
<button class="btn btn-icon-only dropdown-toggle" data-toggle="dropdown">
<i class="icon-sonarr-add"></i>
</button>
<ul class="dropdown-menu">
{{> MovieTitleNamingPartial}}
{{> ReleaseYearNamingPartial}}
{{> QualityNamingPartial}}
{{> MediaInfoNamingPartial}}
{{> ReleaseGroupNamingPartial}}
{{> OriginalTitleNamingPartial}}
{{> ImdbIdNamingPartial}}
{{> SeparatorNamingPartial}}
</ul>
</div>
<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="form-group advanced-setting">
<label class="col-sm-3 control-label">Daily Episode Format</label>
<div class="form-group advanced-setting">
<div class="x-replacing-options">
<div class="col-sm-1 col-sm-push-8 help-inline">
<i class="icon-sonarr-form-info" title="" data-original-title="All caps or all lower-case can also be used"></i>
<a href="https://github.com/NzbDrone/NzbDrone/wiki/Sorting-and-Renaming" class="help-link" title="More information"><i class="icon-sonarr-form-info-link"/></a>
</div>
<label class="col-sm-3 control-label">Colon Replacement Format</label>
<div class="col-sm-8 col-sm-pull-1">
<div class="input-group x-helper-input">
<input type="text" class="form-control naming-format" name="dailyEpisodeFormat" data-onkeyup="true" />
<div class="input-group-btn btn-group x-naming-token-helper">
<button class="btn btn-icon-only dropdown-toggle" data-toggle="dropdown">
<i class="icon-sonarr-add"></i>
</button>
<ul class="dropdown-menu">
{{> SeriesTitleNamingPartial}}
{{> AirDateNamingPartial}}
{{> SeasonNamingPartial}}
{{> EpisodeNamingPartial}}
{{> EpisodeTitleNamingPartial}}
{{> QualityNamingPartial}}
{{> MediaInfoNamingPartial}}
{{> ReleaseGroupNamingPartial}}
{{> OriginalTitleNamingPartial}}
{{> SeparatorNamingPartial}}
</ul>
</div>
<span class="col-sm-1 col-sm-push-8 help-inline">
<i class="icon-sonarr-form-info" title="Colons are illegal characters; Radarr will delete them by default" />
</span>
<div class="col-sm-8 col-sm-pull-1">
<select class="form-control" name="colonReplacementFormat">
<option value="delete">Delete</option>
<option value="dash">Replace with Dash</option>
<option value="spaceDash">Replace with Space Dash</option>
<option value="spaceDashSpace">Replace with Space Dash Space</option>
</select>
</div>
</div>
</div>--}}
</div>
{{!--<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Anime Episode Format</label>
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Standard Movie Format</label>
<div class="col-sm-1 col-sm-push-8 help-inline">
<i class="icon-sonarr-form-info" title="" data-original-title="All caps or all lower-case can also be used"></i>
<a href="https://github.com/NzbDrone/NzbDrone/wiki/Sorting-and-Renaming" class="help-link" title="More information"><i class="icon-sonarr-form-info-link"/></a>
<a href="https://github.com/Radarr/Radarr/wiki/Sorting-and-Renaming" class="help-link" title="More information"><i class="icon-sonarr-form-info-link"/></a>
</div>
<div class="col-sm-8 col-sm-pull-1">
<div class="input-group x-helper-input">
<input type="text" class="form-control naming-format" name="animeEpisodeFormat" data-onkeyup="true" />
<input type="text" class="form-control naming-format" name="standardMovieFormat" data-onkeyup="true" />
<div class="input-group-btn btn-group x-naming-token-helper">
<button class="btn btn-icon-only dropdown-toggle" data-toggle="dropdown">
<i class="icon-sonarr-add"></i>
</button>
<ul class="dropdown-menu">
{{> SeriesTitleNamingPartial}}
{{> AbsoluteEpisodeNamingPartial}}
{{> SeasonNamingPartial}}
{{> EpisodeNamingPartial}}
{{> EpisodeTitleNamingPartial}}
{{> MovieTitleNamingPartial}}
{{> ReleaseYearNamingPartial}}
{{> QualityNamingPartial}}
{{> MediaInfoNamingPartial}}
{{> ReleaseGroupNamingPartial}}
{{> OriginalTitleNamingPartial}}
{{> ImdbIdNamingPartial}}
{{> SeparatorNamingPartial}}
</ul>
</div>
</div>
</div>
</div>
</div>--}}
<div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Movie Folder Format</label>
@ -173,43 +129,6 @@
</div>
</div>
{{!--<div class="form-group">
<label class="col-sm-3 control-label">Season Folder Format</label>
<div class="col-sm-8">
<div class="input-group x-helper-input">
<input type="text" class="form-control naming-format" name="seasonFolderFormat" data-onkeyup="true"/>
<div class="input-group-btn btn-group x-naming-token-helper">
<button class="btn btn-icon-only dropdown-toggle" data-toggle="dropdown">
<i class="icon-sonarr-add"></i>
</button>
<ul class="dropdown-menu">
{{> SeriesTitleNamingPartial}}
{{> SeasonNamingPartial}}
{{> SeparatorNamingPartial}}
</ul>
</div>
</div>
</div>
</div>--}}
{{!--<div class="x-naming-options">
<div class="form-group">
<label class="col-sm-3 control-label">Multi-Episode Style</label>
<div class="col-sm-2">
<select class="form-control x-multi-episode-style" name="multiEpisodeStyle">
<option value="0">Extend</option>
<option value="1">Duplicate</option>
<option value="2">Repeat</option>
<option value="3">Scene</option>
<option value="4">Range</option>
<option value="5">Prefixed Range</option>
</select>
</div>
</div>
</div>--}}
<div class="form-group">
<label class="col-sm-3 control-label">Movie Example</label>
@ -218,37 +137,6 @@
</div>
</div>
{{!--<div class="form-group">
<label class="col-sm-3 control-label">Multi-Episode Example</label>
<div class="col-sm-8">
<p class="form-control-static x-multi-episode-example naming-example"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Daily-Episode Example</label>
<div class="col-sm-8">
<p class="form-control-static x-daily-episode-example naming-example"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Anime Episode Example</label>
<div class="col-sm-8">
<p class="form-control-static x-anime-episode-example naming-example"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Anime Multi-Episode Example</label>
<div class="col-sm-8">
<p class="form-control-static x-anime-multi-episode-example naming-example"></p>
</div>
</div>--}}
<div class="form-group">
<label class="col-sm-3 control-label">Movie Folder Example</label>
@ -256,12 +144,4 @@
<p class="form-control-static x-movie-folder-example naming-example"></p>
</div>
</div>
{{!--<div class="form-group">
<label class="col-sm-3 control-label">Season Folder Example</label>
<div class="col-sm-8">
<p class="form-control-static x-season-folder-example naming-example"></p>
</div>
</div>--}}
</fieldset>

Loading…
Cancel
Save