Added: Setting for Colon Replacement Format (#2711)

Fixes #2140
Fixes #2657
pull/2/head
Qstick 7 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>()); Get["/samples"] = x => GetExamples(this.Bind<NamingConfigResource>());
SharedValidator.RuleFor(c => c.MultiEpisodeStyle).InclusiveBetween(0, 5); 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.StandardMovieFormat).ValidMovieFormat();
SharedValidator.RuleFor(c => c.MovieFolderFormat).ValidMovieFolderFormat(); SharedValidator.RuleFor(c => c.MovieFolderFormat).ValidMovieFolderFormat();
} }
@ -56,12 +51,6 @@ namespace NzbDrone.Api.Config
var nameSpec = _namingConfigService.GetConfig(); var nameSpec = _namingConfigService.GetConfig();
var resource = nameSpec.ToResource(); var resource = nameSpec.ToResource();
//if (resource.StandardEpisodeFormat.IsNotNullOrWhiteSpace())
//{
// var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
// basicConfig.AddToResource(resource);
//}
if (resource.StandardMovieFormat.IsNotNullOrWhiteSpace()) if (resource.StandardMovieFormat.IsNotNullOrWhiteSpace())
{ {
var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec); var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
@ -80,48 +69,13 @@ namespace NzbDrone.Api.Config
{ {
var nameSpec = config.ToModel(); var nameSpec = config.ToModel();
var sampleResource = new NamingSampleResource(); 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); 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() sampleResource.MovieExample = nameSpec.StandardMovieFormat.IsNullOrWhiteSpace()
? "Invalid Format" ? "Invalid Format"
: movieSampleResult.FileName; : 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() sampleResource.MovieFolderExample = nameSpec.MovieFolderFormat.IsNullOrWhiteSpace()
? "Invalid format" ? "Invalid format"
: _filenameSampleService.GetMovieFolderSample(nameSpec); : _filenameSampleService.GetMovieFolderSample(nameSpec);
@ -137,12 +91,6 @@ namespace NzbDrone.Api.Config
var validationFailures = new List<ValidationFailure>(); var validationFailures = new List<ValidationFailure>();
//validationFailures.AddIfNotNull(singleEpisodeValidationResult);
//validationFailures.AddIfNotNull(multiEpisodeValidationResult);
//validationFailures.AddIfNotNull(dailyEpisodeValidationResult);
//validationFailures.AddIfNotNull(animeEpisodeValidationResult);
//validationFailures.AddIfNotNull(animeMultiEpisodeValidationResult);
//validationFailures.AddIfNotNull(standardMovieValidationResult); //validationFailures.AddIfNotNull(standardMovieValidationResult);
if (validationFailures.Any()) if (validationFailures.Any())

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

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

@ -12,8 +12,8 @@ namespace NzbDrone.Core.Test.OrganizerTests
"Mission Impossible - no [HDTV-720p]")] "Mission Impossible - no [HDTV-720p]")]
public void CleanFileName(string name, string expectedName) 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.Cache;
using NzbDrone.Common.Crypto; using NzbDrone.Common.Crypto;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
@ -23,13 +23,15 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
private readonly Logger _logger; private readonly Logger _logger;
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly IDiskScanService _diskScanService; private readonly IDiskScanService _diskScanService;
private readonly INamingConfigService _namingConfigService;
private readonly ICached<Dictionary<string, WatchFolderItem>> _watchFolderItemCache; 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; _logger = logger;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_diskScanService = diskScanService; _diskScanService = diskScanService;
_namingConfigService = namingConfigService;
_watchFolderItemCache = cacheManager.GetCache<Dictionary<string, WatchFolderItem>>(GetType()); _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) 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)) 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 var newWatchItem = new WatchFolderItem
{ {
@ -88,7 +93,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
foreach (var videoFile in _diskScanService.GetVideoFiles(watchFolder, false)) 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 var newWatchItem = new WatchFolderItem
{ {

@ -28,10 +28,11 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
ITorrentFileInfoReader torrentFileInfoReader, ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService, IRemotePathMappingService remotePathMappingService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger) : base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{ {
_scanWatchFolder = scanWatchFolder; _scanWatchFolder = scanWatchFolder;
@ -47,7 +48,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
var title = remoteMovie.Release.Title; var title = remoteMovie.Release.Title;
title = FileNameBuilder.CleanFileName(title); title = CleanFileName(title);
var filepath = Path.Combine(Settings.TorrentFolder, string.Format("{0}.magnet", 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; var title = remoteMovie.Release.Title;
title = FileNameBuilder.CleanFileName(title); title = CleanFileName(title);
var filepath = Path.Combine(Settings.TorrentFolder, string.Format("{0}.torrent", 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, public UsenetBlackhole(IScanWatchFolder scanWatchFolder,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService, IRemotePathMappingService remotePathMappingService,
Logger logger) Logger logger)
: base(httpClient, configService, diskProvider, remotePathMappingService, logger) : base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{ {
_scanWatchFolder = scanWatchFolder; _scanWatchFolder = scanWatchFolder;
@ -36,7 +37,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
{ {
var title = remoteMovie.Release.Title; var title = remoteMovie.Release.Title;
title = FileNameBuilder.CleanFileName(title); title = CleanFileName(title);
var filepath = Path.Combine(Settings.NzbFolder, title + ".nzb"); var filepath = Path.Combine(Settings.NzbFolder, title + ".nzb");

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

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

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

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

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

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

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

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

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

@ -1,4 +1,4 @@
using System; using System;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
@ -7,6 +7,7 @@ using NLog;
using FluentValidation.Results; using FluentValidation.Results;
using NzbDrone.Core.MediaFiles.TorrentInfo; using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download.Clients.Transmission namespace NzbDrone.Core.Download.Clients.Transmission
{ {
@ -16,10 +17,11 @@ namespace NzbDrone.Core.Download.Clients.Transmission
ITorrentFileInfoReader torrentFileInfoReader, ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService, IRemotePathMappingService remotePathMappingService,
Logger logger) 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.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles.TorrentInfo; using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@ -23,10 +24,11 @@ namespace NzbDrone.Core.Download.Clients.Transmission
ITorrentFileInfoReader torrentFileInfoReader, ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService, IRemotePathMappingService remotePathMappingService,
Logger logger) Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger) : base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{ {
_proxy = proxy; _proxy = proxy;
} }

@ -1,10 +1,11 @@
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.Transmission; using NzbDrone.Core.Download.Clients.Transmission;
using NzbDrone.Core.MediaFiles.TorrentInfo; using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
namespace NzbDrone.Core.Download.Clients.Vuze namespace NzbDrone.Core.Download.Clients.Vuze
@ -17,10 +18,11 @@ namespace NzbDrone.Core.Download.Clients.Vuze
ITorrentFileInfoReader torrentFileInfoReader, ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService, IRemotePathMappingService remotePathMappingService,
Logger logger) 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.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download.Clients.RTorrent namespace NzbDrone.Core.Download.Clients.RTorrent
{ {
@ -27,11 +28,12 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
ITorrentFileInfoReader torrentFileInfoReader, ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService, IRemotePathMappingService remotePathMappingService,
IRTorrentDirectoryValidator rTorrentDirectoryValidator, IRTorrentDirectoryValidator rTorrentDirectoryValidator,
Logger logger) Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, remotePathMappingService, logger) : base(torrentFileInfoReader, httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{ {
_proxy = proxy; _proxy = proxy;
_rTorrentDirectoryValidator = rTorrentDirectoryValidator; _rTorrentDirectoryValidator = rTorrentDirectoryValidator;

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

@ -11,6 +11,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.RemotePathMappings; using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Download namespace NzbDrone.Core.Download
{ {
@ -18,6 +19,7 @@ namespace NzbDrone.Core.Download
where TSettings : IProviderConfig, new() where TSettings : IProviderConfig, new()
{ {
protected readonly IConfigService _configService; protected readonly IConfigService _configService;
protected readonly INamingConfigService _namingConfigService;
protected readonly IDiskProvider _diskProvider; protected readonly IDiskProvider _diskProvider;
protected readonly IRemotePathMappingService _remotePathMappingService; protected readonly IRemotePathMappingService _remotePathMappingService;
protected readonly Logger _logger; protected readonly Logger _logger;
@ -39,12 +41,14 @@ namespace NzbDrone.Core.Download
protected TSettings Settings => (TSettings)Definition.Settings; protected TSettings Settings => (TSettings)Definition.Settings;
protected DownloadClientBase(IConfigService configService, protected DownloadClientBase(IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService, IRemotePathMappingService remotePathMappingService,
Logger logger) Logger logger)
{ {
_configService = configService; _configService = configService;
_namingConfigService = namingConfigService;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_remotePathMappingService = remotePathMappingService; _remotePathMappingService = remotePathMappingService;
_logger = logger; _logger = logger;
@ -151,6 +155,13 @@ namespace NzbDrone.Core.Download
return null; 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, protected TorrentClientBase(ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient, IHttpClient httpClient,
IConfigService configService, IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService, IRemotePathMappingService remotePathMappingService,
Logger logger) Logger logger)
: base(configService, diskProvider, remotePathMappingService, logger) : base(configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_torrentFileInfoReader = torrentFileInfoReader; _torrentFileInfoReader = torrentFileInfoReader;
@ -178,7 +179,7 @@ namespace NzbDrone.Core.Download
throw new ReleaseDownloadException(remoteMovie.Release, "Downloading torrent failed", ex); 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 hash = _torrentFileInfoReader.GetHashFromTorrentFile(torrentFile);
var actualHash = AddFromTorrentFile(remoteMovie, hash, filename, torrentFile); var actualHash = AddFromTorrentFile(remoteMovie, hash, filename, torrentFile);

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

@ -124,6 +124,7 @@
<Compile Include="Authentication\UserRepository.cs" /> <Compile Include="Authentication\UserRepository.cs" />
<Compile Include="Authentication\UserService.cs" /> <Compile Include="Authentication\UserService.cs" />
<Compile Include="Datastore\Migration\123_create_netimport_table.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\143_clean_core_tv.cs" />
<Compile Include="Datastore\Migration\142_movie_extras.cs" /> <Compile Include="Datastore\Migration\142_movie_extras.cs" />
<Compile Include="Datastore\Migration\140_add_alternative_titles_table.cs" /> <Compile Include="Datastore\Migration\140_add_alternative_titles_table.cs" />
@ -1300,4 +1301,4 @@
<Target Name="AfterBuild"> <Target Name="AfterBuild">
</Target> </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}"}); 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) public static string CleanTitle(string title)
@ -283,11 +284,14 @@ namespace NzbDrone.Core.Organizer
return title.Trim(); 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 result = name;
string[] badCharacters = { "\\", "/", "<", ">", "?", "*", ":", "|", "\"" }; string[] badCharacters = { "\\", "/", "<", ">", "?", "*", ":", "|", "\"" };
string[] goodCharacters = { "+", "+", "", "", "!", "-", "", "", "" }; string[] goodCharacters = { "+", "+", "", "", "!", "-", colonReplacementFormat, "", "" };
for (int i = 0; i < badCharacters.Length; i++) for (int i = 0; i < badCharacters.Length; i++)
{ {
@ -297,12 +301,12 @@ namespace NzbDrone.Core.Organizer
return result.Trim(); 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 = FileNameCleanupRegex.Replace(name, match => match.Captures[0].Value[0].ToString());
name = name.Trim(' ', '.'); name = name.Trim(' ', '.');
return CleanFileName(name); return CleanFileName(name, namingConfig);
} }
private void AddMovieTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Movie movie) 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 = replacementText.Replace(" ", tokenMatch.Separator);
} }
replacementText = CleanFileName(replacementText, namingConfig.ReplaceIllegalCharacters); replacementText = CleanFileName(replacementText, namingConfig);
if (!replacementText.IsNullOrWhiteSpace()) if (!replacementText.IsNullOrWhiteSpace())
{ {

@ -1,3 +1,4 @@
using System;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Organizer namespace NzbDrone.Core.Organizer
@ -8,6 +9,7 @@ namespace NzbDrone.Core.Organizer
{ {
RenameEpisodes = false, RenameEpisodes = false,
ReplaceIllegalCharacters = true, ReplaceIllegalCharacters = true,
ColonReplacementFormat = 0,
MultiEpisodeStyle = 0, MultiEpisodeStyle = 0,
MovieFolderFormat = "{Movie Title} ({Release Year})", MovieFolderFormat = "{Movie Title} ({Release Year})",
StandardMovieFormat = "{Movie Title} ({Release Year}) {Quality Full}", StandardMovieFormat = "{Movie Title} ({Release Year}) {Quality Full}",
@ -15,8 +17,38 @@ namespace NzbDrone.Core.Organizer
public bool RenameEpisodes { get; set; } public bool RenameEpisodes { get; set; }
public bool ReplaceIllegalCharacters { get; set; } public bool ReplaceIllegalCharacters { get; set; }
public ColonReplacementFormat ColonReplacementFormat { get; set; }
public int MultiEpisodeStyle { get; set; } public int MultiEpisodeStyle { get; set; }
public string StandardMovieFormat { get; set; } public string StandardMovieFormat { get; set; }
public string MovieFolderFormat { 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 : { ui : {
namingOptions : '.x-naming-options', namingOptions : '.x-naming-options',
renameEpisodesCheckbox : '.x-rename-episodes', renameEpisodesCheckbox : '.x-rename-episodes',
singleEpisodeExample : '.x-single-episode-example', replacingOptions : '.x-replacing-options',
multiEpisodeExample : '.x-multi-episode-example', replaceIllegalChars : '.x-replace-illegal-chars',
dailyEpisodeExample : '.x-daily-episode-example',
animeEpisodeExample : '.x-anime-episode-example',
animeMultiEpisodeExample : '.x-anime-multi-episode-example',
namingTokenHelper : '.x-naming-token-helper', namingTokenHelper : '.x-naming-token-helper',
multiEpisodeStyle : '.x-multi-episode-style',
seriesFolderExample : '.x-series-folder-example',
seasonFolderExample : '.x-season-folder-example',
movieExample : '.x-movie-example', movieExample : '.x-movie-example',
movieFolderExample : '.x-movie-folder-example' movieFolderExample : '.x-movie-folder-example'
}, },
events : { events : {
"change .x-rename-episodes" : '_setFailedDownloadOptionsVisibility', 'change .x-rename-episodes' : '_setRenameEpisodesVisibility',
"click .x-show-wizard" : '_showWizard', 'change .x-replace-illegal-chars': '_setReplaceIllegalCharsVisibility',
"click .x-naming-token-helper a" : '_addToken', 'click .x-show-wizard' : '_showWizard',
"change .x-multi-episode-style" : '_multiEpisodeFomatChanged' 'click .x-naming-token-helper a' : '_addToken',
'change .x-multi-episode-style' : '_multiEpisodeFomatChanged'
}, },
regions : { basicNamingRegion : '.x-basic-naming' }, regions : { basicNamingRegion : '.x-basic-naming' },
onRender : function() { onRender : function() {
if (!this.model.get('renameEpisodes')) { if (!this.model.get('renameEpisodes')) {
this.ui.namingOptions.hide(); this.ui.namingOptions.hide();
} }
if (!this.model.get('replaceIllegalCharacters')) {
this.ui.replacingOptions.hide();
}
var basicNamingView = new BasicNamingView({ model : this.model }); var basicNamingView = new BasicNamingView({ model : this.model });
this.basicNamingRegion.show(basicNamingView); this.basicNamingRegion.show(basicNamingView);
this.namingSampleModel = new NamingSampleModel(); this.namingSampleModel = new NamingSampleModel();
@ -41,7 +39,7 @@ module.exports = (function() {
this.listenTo(this.namingSampleModel, 'sync', this._showSamples); this.listenTo(this.namingSampleModel, 'sync', this._showSamples);
this._updateSamples(); this._updateSamples();
}, },
_setFailedDownloadOptionsVisibility : function() { _setRenameEpisodesVisibility : function() {
var checked = this.ui.renameEpisodesCheckbox.prop('checked'); var checked = this.ui.renameEpisodesCheckbox.prop('checked');
if (checked) { if (checked) {
this.ui.namingOptions.slideDown(); this.ui.namingOptions.slideDown();
@ -49,17 +47,18 @@ module.exports = (function() {
this.ui.namingOptions.slideUp(); 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() { _updateSamples : function() {
this.namingSampleModel.fetch({ data : this.model.toJSON() }); this.namingSampleModel.fetch({ data : this.model.toJSON() });
}, },
_showSamples : function() { _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.movieExample.html(this.namingSampleModel.get('movieExample'));
this.ui.movieFolderExample.html(this.namingSampleModel.get('movieFolderExample')); this.ui.movieFolderExample.html(this.namingSampleModel.get('movieFolderExample'));
}, },
@ -86,4 +85,4 @@ module.exports = (function() {
AsModelBoundView.call(view); AsModelBoundView.call(view);
AsValidatedView.call(view); AsValidatedView.call(view);
return view; return view;
}).call(this); }).call(this);

@ -24,126 +24,82 @@
</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>
<div class="form-group advanced-setting"> <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"> <div class="col-sm-8">
<i class="icon-sonarr-form-info" title="" data-original-title="All caps or all lower-case can also be used"></i> <div class="input-group">
<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> <label class="checkbox toggle well">
</div> <input type="checkbox" name="replaceIllegalCharacters" class="x-replace-illegal-chars"/>
<div class="col-sm-8 col-sm-pull-1"> <p>
<div class="input-group x-helper-input"> <span>Yes</span>
<input type="text" class="form-control naming-format" name="standardMovieFormat" data-onkeyup="true" /> <span>No</span>
<div class="input-group-btn btn-group x-naming-token-helper"> </p>
<button class="btn btn-icon-only dropdown-toggle" data-toggle="dropdown">
<i class="icon-sonarr-add"></i> <div class="btn btn-primary slide-button"/>
</button> </label>
<ul class="dropdown-menu">
{{> MovieTitleNamingPartial}} <span class="help-inline-checkbox">
{{> ReleaseYearNamingPartial}} <i class="icon-sonarr-form-info" title="Replace or Remove illegal characters"/>
{{> QualityNamingPartial}} </span>
{{> MediaInfoNamingPartial}}
{{> ReleaseGroupNamingPartial}}
{{> OriginalTitleNamingPartial}}
{{> ImdbIdNamingPartial}}
{{> SeparatorNamingPartial}}
</ul>
</div>
</div> </div>
</div> </div>
</div> </div>
{{!--<div class="form-group advanced-setting"> <div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Daily Episode Format</label> <div class="x-replacing-options">
<div class="col-sm-1 col-sm-push-8 help-inline"> <label class="col-sm-3 control-label">Colon Replacement Format</label>
<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>
<div class="col-sm-8 col-sm-pull-1"> <span class="col-sm-1 col-sm-push-8 help-inline">
<div class="input-group x-helper-input"> <i class="icon-sonarr-form-info" title="Colons are illegal characters; Radarr will delete them by default" />
<input type="text" class="form-control naming-format" name="dailyEpisodeFormat" data-onkeyup="true" /> </span>
<div class="input-group-btn btn-group x-naming-token-helper">
<button class="btn btn-icon-only dropdown-toggle" data-toggle="dropdown"> <div class="col-sm-8 col-sm-pull-1">
<i class="icon-sonarr-add"></i> <select class="form-control" name="colonReplacementFormat">
</button> <option value="delete">Delete</option>
<ul class="dropdown-menu"> <option value="dash">Replace with Dash</option>
{{> SeriesTitleNamingPartial}} <option value="spaceDash">Replace with Space Dash</option>
{{> AirDateNamingPartial}} <option value="spaceDashSpace">Replace with Space Dash Space</option>
{{> SeasonNamingPartial}}
{{> EpisodeNamingPartial}} </select>
{{> EpisodeTitleNamingPartial}}
{{> QualityNamingPartial}}
{{> MediaInfoNamingPartial}}
{{> ReleaseGroupNamingPartial}}
{{> OriginalTitleNamingPartial}}
{{> SeparatorNamingPartial}}
</ul>
</div>
</div> </div>
</div> </div>
</div>--}} </div>
{{!--<div class="form-group advanced-setting"> <div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Anime Episode Format</label> <label class="col-sm-3 control-label">Standard Movie Format</label>
<div class="col-sm-1 col-sm-push-8 help-inline"> <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> <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>
<div class="col-sm-8 col-sm-pull-1"> <div class="col-sm-8 col-sm-pull-1">
<div class="input-group x-helper-input"> <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"> <div class="input-group-btn btn-group x-naming-token-helper">
<button class="btn btn-icon-only dropdown-toggle" data-toggle="dropdown"> <button class="btn btn-icon-only dropdown-toggle" data-toggle="dropdown">
<i class="icon-sonarr-add"></i> <i class="icon-sonarr-add"></i>
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
{{> SeriesTitleNamingPartial}} {{> MovieTitleNamingPartial}}
{{> AbsoluteEpisodeNamingPartial}} {{> ReleaseYearNamingPartial}}
{{> SeasonNamingPartial}}
{{> EpisodeNamingPartial}}
{{> EpisodeTitleNamingPartial}}
{{> QualityNamingPartial}} {{> QualityNamingPartial}}
{{> MediaInfoNamingPartial}} {{> MediaInfoNamingPartial}}
{{> ReleaseGroupNamingPartial}} {{> ReleaseGroupNamingPartial}}
{{> OriginalTitleNamingPartial}} {{> OriginalTitleNamingPartial}}
{{> ImdbIdNamingPartial}}
{{> SeparatorNamingPartial}} {{> SeparatorNamingPartial}}
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>--}}
<div class="form-group advanced-setting"> <div class="form-group advanced-setting">
<label class="col-sm-3 control-label">Movie Folder Format</label> <label class="col-sm-3 control-label">Movie Folder Format</label>
@ -173,43 +129,6 @@
</div> </div>
</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"> <div class="form-group">
<label class="col-sm-3 control-label">Movie Example</label> <label class="col-sm-3 control-label">Movie Example</label>
@ -218,37 +137,6 @@
</div> </div>
</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"> <div class="form-group">
<label class="col-sm-3 control-label">Movie Folder Example</label> <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> <p class="form-control-static x-movie-folder-example naming-example"></p>
</div> </div>
</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> </fieldset>

Loading…
Cancel
Save