mirror of https://github.com/Radarr/Radarr
Merge pull request #38 from fedoranimus/develop
First pass at Media Management
This commit is contained in:
commit
4c2be68549
|
@ -39,6 +39,8 @@ namespace NzbDrone.Api.Config
|
|||
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();
|
||||
}
|
||||
|
||||
private void UpdateNamingConfig(NamingConfigResource resource)
|
||||
|
@ -54,7 +56,13 @@ namespace NzbDrone.Api.Config
|
|||
var nameSpec = _namingConfigService.GetConfig();
|
||||
var resource = nameSpec.ToResource();
|
||||
|
||||
if (resource.StandardEpisodeFormat.IsNotNullOrWhiteSpace())
|
||||
//if (resource.StandardEpisodeFormat.IsNotNullOrWhiteSpace())
|
||||
//{
|
||||
// var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
|
||||
// basicConfig.AddToResource(resource);
|
||||
//}
|
||||
|
||||
if (resource.StandardMovieFormat.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
|
||||
basicConfig.AddToResource(resource);
|
||||
|
@ -73,39 +81,50 @@ 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 singleEpisodeSampleResult = _filenameSampleService.GetStandardSample(nameSpec);
|
||||
//var multiEpisodeSampleResult = _filenameSampleService.GetMultiEpisodeSample(nameSpec);
|
||||
//var dailyEpisodeSampleResult = _filenameSampleService.GetDailySample(nameSpec);
|
||||
//var animeEpisodeSampleResult = _filenameSampleService.GetAnimeSample(nameSpec);
|
||||
//var animeMultiEpisodeSampleResult = _filenameSampleService.GetAnimeMultiEpisodeSample(nameSpec);
|
||||
|
||||
sampleResource.SingleEpisodeExample = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
: singleEpisodeSampleResult.FileName;
|
||||
var movieSampleResult = _filenameSampleService.GetMovieSample(nameSpec);
|
||||
|
||||
|
||||
sampleResource.MultiEpisodeExample = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
: multiEpisodeSampleResult.FileName;
|
||||
//sampleResource.SingleEpisodeExample = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult) != null
|
||||
// ? "Invalid format"
|
||||
// : singleEpisodeSampleResult.FileName;
|
||||
|
||||
sampleResource.DailyEpisodeExample = _filenameValidationService.ValidateDailyFilename(dailyEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
: dailyEpisodeSampleResult.FileName;
|
||||
//sampleResource.MultiEpisodeExample = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult) != null
|
||||
// ? "Invalid format"
|
||||
// : multiEpisodeSampleResult.FileName;
|
||||
|
||||
sampleResource.AnimeEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
: animeEpisodeSampleResult.FileName;
|
||||
//sampleResource.DailyEpisodeExample = _filenameValidationService.ValidateDailyFilename(dailyEpisodeSampleResult) != null
|
||||
// ? "Invalid format"
|
||||
// : dailyEpisodeSampleResult.FileName;
|
||||
|
||||
sampleResource.AnimeMultiEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeMultiEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
: animeMultiEpisodeSampleResult.FileName;
|
||||
//sampleResource.AnimeEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult) != null
|
||||
// ? "Invalid format"
|
||||
// : animeEpisodeSampleResult.FileName;
|
||||
|
||||
sampleResource.SeriesFolderExample = nameSpec.SeriesFolderFormat.IsNullOrWhiteSpace()
|
||||
//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.GetSeriesFolderSample(nameSpec);
|
||||
|
||||
sampleResource.SeasonFolderExample = nameSpec.SeasonFolderFormat.IsNullOrWhiteSpace()
|
||||
? "Invalid format"
|
||||
: _filenameSampleService.GetSeasonFolderSample(nameSpec);
|
||||
: _filenameSampleService.GetMovieFolderSample(nameSpec);
|
||||
|
||||
return sampleResource.AsResponse();
|
||||
}
|
||||
|
@ -118,19 +137,25 @@ namespace NzbDrone.Api.Config
|
|||
var animeEpisodeSampleResult = _filenameSampleService.GetAnimeSample(nameSpec);
|
||||
var animeMultiEpisodeSampleResult = _filenameSampleService.GetAnimeMultiEpisodeSample(nameSpec);
|
||||
|
||||
var movieSampleResult = _filenameSampleService.GetMovieSample(nameSpec);
|
||||
|
||||
var singleEpisodeValidationResult = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult);
|
||||
var multiEpisodeValidationResult = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult);
|
||||
var dailyEpisodeValidationResult = _filenameValidationService.ValidateDailyFilename(dailyEpisodeSampleResult);
|
||||
var animeEpisodeValidationResult = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult);
|
||||
var animeMultiEpisodeValidationResult = _filenameValidationService.ValidateAnimeFilename(animeMultiEpisodeSampleResult);
|
||||
|
||||
//var standardMovieValidationResult = _filenameValidationService.ValidateMovieFilename(movieSampleResult); For now, let's hope the user is not stupid enough :/
|
||||
|
||||
var validationFailures = new List<ValidationFailure>();
|
||||
|
||||
validationFailures.AddIfNotNull(singleEpisodeValidationResult);
|
||||
validationFailures.AddIfNotNull(multiEpisodeValidationResult);
|
||||
validationFailures.AddIfNotNull(dailyEpisodeValidationResult);
|
||||
validationFailures.AddIfNotNull(animeEpisodeValidationResult);
|
||||
validationFailures.AddIfNotNull(animeMultiEpisodeValidationResult);
|
||||
//validationFailures.AddIfNotNull(singleEpisodeValidationResult);
|
||||
//validationFailures.AddIfNotNull(multiEpisodeValidationResult);
|
||||
//validationFailures.AddIfNotNull(dailyEpisodeValidationResult);
|
||||
//validationFailures.AddIfNotNull(animeEpisodeValidationResult);
|
||||
//validationFailures.AddIfNotNull(animeMultiEpisodeValidationResult);
|
||||
|
||||
//validationFailures.AddIfNotNull(standardMovieValidationResult);
|
||||
|
||||
if (validationFailures.Any())
|
||||
{
|
||||
|
|
|
@ -7,6 +7,8 @@ namespace NzbDrone.Api.Config
|
|||
{
|
||||
public bool RenameEpisodes { get; set; }
|
||||
public bool ReplaceIllegalCharacters { get; set; }
|
||||
public string StandardMovieFormat { get; set; }
|
||||
public string MovieFolderFormat { get; set; }
|
||||
public int MultiEpisodeStyle { get; set; }
|
||||
public string StandardEpisodeFormat { get; set; }
|
||||
public string DailyEpisodeFormat { get; set; }
|
||||
|
@ -36,7 +38,9 @@ namespace NzbDrone.Api.Config
|
|||
DailyEpisodeFormat = model.DailyEpisodeFormat,
|
||||
AnimeEpisodeFormat = model.AnimeEpisodeFormat,
|
||||
SeriesFolderFormat = model.SeriesFolderFormat,
|
||||
SeasonFolderFormat = model.SeasonFolderFormat
|
||||
SeasonFolderFormat = model.SeasonFolderFormat,
|
||||
StandardMovieFormat = model.StandardMovieFormat,
|
||||
MovieFolderFormat = model.MovieFolderFormat
|
||||
//IncludeSeriesTitle
|
||||
//IncludeEpisodeTitle
|
||||
//IncludeQuality
|
||||
|
@ -64,12 +68,14 @@ 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
|
||||
//MultiEpisodeStyle = resource.MultiEpisodeStyle,
|
||||
//StandardEpisodeFormat = resource.StandardEpisodeFormat,
|
||||
//DailyEpisodeFormat = resource.DailyEpisodeFormat,
|
||||
//AnimeEpisodeFormat = resource.AnimeEpisodeFormat,
|
||||
//SeriesFolderFormat = resource.SeriesFolderFormat,
|
||||
//SeasonFolderFormat = resource.SeasonFolderFormat,
|
||||
StandardMovieFormat = resource.StandardMovieFormat,
|
||||
MovieFolderFormat = resource.MovieFolderFormat
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,5 +9,8 @@
|
|||
public string AnimeMultiEpisodeExample { get; set; }
|
||||
public string SeriesFolderExample { get; set; }
|
||||
public string SeasonFolderExample { get; set; }
|
||||
|
||||
public string MovieExample { get; set; }
|
||||
public string MovieFolderExample { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using System.Data;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(109)]
|
||||
public class add_movie_formats_to_naming_config : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("NamingConfig").AddColumn("StandardMovieFormat").AsString().Nullable();
|
||||
Alter.Table("NamingConfig").AddColumn("MovieFolderFormat").AsString().Nullable();
|
||||
|
||||
Execute.WithConnection(ConvertConfig);
|
||||
}
|
||||
|
||||
private void ConvertConfig(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
|
||||
using (IDbCommand namingConfigCmd = conn.CreateCommand())
|
||||
{
|
||||
namingConfigCmd.Transaction = tran;
|
||||
namingConfigCmd.CommandText = @"SELECT * FROM NamingConfig LIMIT 1";
|
||||
using (IDataReader namingConfigReader = namingConfigCmd.ExecuteReader())
|
||||
{
|
||||
|
||||
while (namingConfigReader.Read())
|
||||
{
|
||||
// Output Settings
|
||||
var movieTitlePattern = "";
|
||||
var movieYearPattern = "({Release Year})";
|
||||
var qualityFormat = "[{Quality Title}]";
|
||||
|
||||
movieTitlePattern = "{Movie Title}";
|
||||
|
||||
var standardMovieFormat = string.Format("{0} {1} {2}", movieTitlePattern,
|
||||
movieYearPattern,
|
||||
qualityFormat);
|
||||
|
||||
var movieFolderFormat = string.Format("{0} {1}", movieTitlePattern, movieYearPattern);
|
||||
|
||||
|
||||
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||
{
|
||||
var text = string.Format("UPDATE NamingConfig " +
|
||||
"SET StandardMovieFormat = '{0}', " +
|
||||
"MovieFolderFormat = '{1}'",
|
||||
standardMovieFormat,
|
||||
movieFolderFormat);
|
||||
|
||||
updateCmd.Transaction = tran;
|
||||
updateCmd.CommandText = text;
|
||||
updateCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -286,6 +286,7 @@
|
|||
<Compile Include="Datastore\Migration\098_remove_titans_of_tv.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Datastore\Migration\109_add_movie_formats_to_naming_config.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationDbFactory.cs" />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
@ -24,7 +24,7 @@ namespace NzbDrone.Core.Organizer
|
|||
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
|
||||
string GetSeriesFolder(Series series, NamingConfig namingConfig = null);
|
||||
string GetSeasonFolder(Series series, int seasonNumber, NamingConfig namingConfig = null);
|
||||
string GetMovieFolder(Movie movie);
|
||||
string GetMovieFolder(Movie movie, NamingConfig namingConfig = null);
|
||||
}
|
||||
|
||||
public class FileNameBuilder : IBuildFileNames
|
||||
|
@ -58,6 +58,9 @@ namespace NzbDrone.Core.Organizer
|
|||
public static readonly Regex SeriesTitleRegex = new Regex(@"(?<token>\{(?:Series)(?<separator>[- ._])(Clean)?Title\})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{(?:Movie)(?<separator>[- ._])(Clean)?Title\})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled);
|
||||
private static readonly Regex TrimSeparatorsRegex = new Regex(@"[- ._]$", RegexOptions.Compiled);
|
||||
|
||||
|
@ -76,6 +79,7 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
_namingConfigService = namingConfigService;
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
//_movieFormatCache = cacheManager.GetCache<MovieFormat>(GetType(), "movieFormat");
|
||||
_episodeFormatCache = cacheManager.GetCache<EpisodeFormat[]>(GetType(), "episodeFormat");
|
||||
_absoluteEpisodeFormatCache = cacheManager.GetCache<AbsoluteEpisodeFormat[]>(GetType(), "absoluteEpisodeFormat");
|
||||
_logger = logger;
|
||||
|
@ -151,52 +155,20 @@ namespace NzbDrone.Core.Organizer
|
|||
return GetOriginalTitle(movieFile);
|
||||
}
|
||||
|
||||
/*if (namingConfig.StandardEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Standard)
|
||||
{
|
||||
throw new NamingFormatException("Standard episode format cannot be empty");
|
||||
}
|
||||
|
||||
if (namingConfig.DailyEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Daily)
|
||||
{
|
||||
throw new NamingFormatException("Daily episode format cannot be empty");
|
||||
}
|
||||
|
||||
if (namingConfig.AnimeEpisodeFormat.IsNullOrWhiteSpace() && series.SeriesType == SeriesTypes.Anime)
|
||||
{
|
||||
throw new NamingFormatException("Anime episode format cannot be empty");
|
||||
}*/
|
||||
|
||||
/*var pattern = namingConfig.StandardEpisodeFormat;
|
||||
//TODO: Update namingConfig for Movies!
|
||||
var pattern = namingConfig.StandardMovieFormat;
|
||||
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
episodes = episodes.OrderBy(e => e.SeasonNumber).ThenBy(e => e.EpisodeNumber).ToList();
|
||||
|
||||
if (series.SeriesType == SeriesTypes.Daily)
|
||||
{
|
||||
pattern = namingConfig.DailyEpisodeFormat;
|
||||
}
|
||||
|
||||
if (series.SeriesType == SeriesTypes.Anime && episodes.All(e => e.AbsoluteEpisodeNumber.HasValue))
|
||||
{
|
||||
pattern = namingConfig.AnimeEpisodeFormat;
|
||||
}
|
||||
|
||||
pattern = AddSeasonEpisodeNumberingTokens(pattern, tokenHandlers, episodes, namingConfig);
|
||||
pattern = AddAbsoluteNumberingTokens(pattern, tokenHandlers, series, episodes, namingConfig);
|
||||
|
||||
AddSeriesTokens(tokenHandlers, series);
|
||||
AddEpisodeTokens(tokenHandlers, episodes);
|
||||
AddEpisodeFileTokens(tokenHandlers, episodeFile);
|
||||
AddQualityTokens(tokenHandlers, series, episodeFile);
|
||||
AddMediaInfoTokens(tokenHandlers, episodeFile);
|
||||
AddMovieTokens(tokenHandlers, movie);
|
||||
AddReleaseDateTokens(tokenHandlers, movie.Year); //In case we want to separate the year
|
||||
AddQualityTokens(tokenHandlers, movie, movieFile);
|
||||
AddMediaInfoTokens(tokenHandlers, movieFile);
|
||||
|
||||
var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim();
|
||||
fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString());
|
||||
fileName = TrimSeparatorsRegex.Replace(fileName, string.Empty);*/
|
||||
fileName = TrimSeparatorsRegex.Replace(fileName, string.Empty);
|
||||
|
||||
//TODO: Update namingConfig for Movies!
|
||||
|
||||
return GetOriginalTitle(movieFile);
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public string BuildFilePath(Series series, int seasonNumber, string fileName, string extension)
|
||||
|
@ -242,6 +214,8 @@ namespace NzbDrone.Core.Organizer
|
|||
|
||||
public BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec)
|
||||
{
|
||||
return new BasicNamingConfig(); //For now let's be lazy
|
||||
|
||||
var episodeFormat = GetEpisodeFormat(nameSpec.StandardEpisodeFormat).LastOrDefault();
|
||||
|
||||
if (episodeFormat == null)
|
||||
|
@ -315,9 +289,19 @@ namespace NzbDrone.Core.Organizer
|
|||
return CleanFolderName(ReplaceTokens(namingConfig.SeasonFolderFormat, tokenHandlers, namingConfig));
|
||||
}
|
||||
|
||||
public string GetMovieFolder(Movie movie)
|
||||
public string GetMovieFolder(Movie movie, NamingConfig namingConfig = null)
|
||||
{
|
||||
return CleanFolderName(movie.Title);
|
||||
if(namingConfig == null)
|
||||
{
|
||||
namingConfig = _namingConfigService.GetConfig();
|
||||
}
|
||||
|
||||
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
AddMovieTokens(tokenHandlers, movie);
|
||||
AddReleaseDateTokens(tokenHandlers, movie.Year);
|
||||
|
||||
return CleanFolderName(ReplaceTokens(namingConfig.MovieFolderFormat, tokenHandlers, namingConfig));
|
||||
}
|
||||
|
||||
public static string CleanTitle(string title)
|
||||
|
@ -481,6 +465,17 @@ namespace NzbDrone.Core.Organizer
|
|||
return pattern;
|
||||
}
|
||||
|
||||
private void AddMovieTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Movie movie)
|
||||
{
|
||||
tokenHandlers["{Movie Title}"] = m => movie.Title;
|
||||
tokenHandlers["{Movie CleanTitle}"] = m => CleanTitle(movie.Title);
|
||||
}
|
||||
|
||||
private void AddReleaseDateTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, int releaseYear)
|
||||
{
|
||||
tokenHandlers["{Release Year}"] = m => string.Format("{0}", releaseYear.ToString()); //Do I need m.CustomFormat?
|
||||
}
|
||||
|
||||
private void AddSeasonTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, int seasonNumber)
|
||||
{
|
||||
tokenHandlers["{Season}"] = m => seasonNumber.ToString(m.CustomFormat);
|
||||
|
@ -520,6 +515,18 @@ namespace NzbDrone.Core.Organizer
|
|||
tokenHandlers["{Quality Real}"] = m => qualityReal;
|
||||
}
|
||||
|
||||
private void AddQualityTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Movie movie, MovieFile movieFile)
|
||||
{
|
||||
var qualityTitle = _qualityDefinitionService.Get(movieFile.Quality.Quality).Title;
|
||||
var qualityProper = GetQualityProper(movie, movieFile.Quality);
|
||||
var qualityReal = GetQualityReal(movie, movieFile.Quality);
|
||||
|
||||
tokenHandlers["{Quality Full}"] = m => String.Format("{0} {1} {2}", qualityTitle, qualityProper, qualityReal);
|
||||
tokenHandlers["{Quality Title}"] = m => qualityTitle;
|
||||
tokenHandlers["{Quality Proper}"] = m => qualityProper;
|
||||
tokenHandlers["{Quality Real}"] = m => qualityReal;
|
||||
}
|
||||
|
||||
private void AddMediaInfoTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, EpisodeFile episodeFile)
|
||||
{
|
||||
if (episodeFile.MediaInfo == null) return;
|
||||
|
@ -624,6 +631,110 @@ namespace NzbDrone.Core.Organizer
|
|||
tokenHandlers["{MediaInfo Full}"] = m => string.Format("{0} {1}{2} {3}", videoCodec, audioCodec, mediaInfoAudioLanguages, mediaInfoSubtitleLanguages);
|
||||
}
|
||||
|
||||
private void AddMediaInfoTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, MovieFile movieFile)
|
||||
{
|
||||
if (movieFile.MediaInfo == null) return;
|
||||
|
||||
string videoCodec;
|
||||
switch (movieFile.MediaInfo.VideoCodec)
|
||||
{
|
||||
case "AVC":
|
||||
if (movieFile.SceneName.IsNotNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(movieFile.SceneName).Contains("h264"))
|
||||
{
|
||||
videoCodec = "h264";
|
||||
}
|
||||
else
|
||||
{
|
||||
videoCodec = "x264";
|
||||
}
|
||||
break;
|
||||
|
||||
case "V_MPEGH/ISO/HEVC":
|
||||
if (movieFile.SceneName.IsNotNullOrWhiteSpace() && Path.GetFileNameWithoutExtension(movieFile.SceneName).Contains("h265"))
|
||||
{
|
||||
videoCodec = "h265";
|
||||
}
|
||||
else
|
||||
{
|
||||
videoCodec = "x265";
|
||||
}
|
||||
break;
|
||||
|
||||
case "MPEG-2 Video":
|
||||
videoCodec = "MPEG2";
|
||||
break;
|
||||
|
||||
default:
|
||||
videoCodec = movieFile.MediaInfo.VideoCodec;
|
||||
break;
|
||||
}
|
||||
|
||||
string audioCodec;
|
||||
switch (movieFile.MediaInfo.AudioFormat)
|
||||
{
|
||||
case "AC-3":
|
||||
audioCodec = "AC3";
|
||||
break;
|
||||
|
||||
case "E-AC-3":
|
||||
audioCodec = "EAC3";
|
||||
break;
|
||||
|
||||
case "MPEG Audio":
|
||||
if (movieFile.MediaInfo.AudioProfile == "Layer 3")
|
||||
{
|
||||
audioCodec = "MP3";
|
||||
}
|
||||
else
|
||||
{
|
||||
audioCodec = movieFile.MediaInfo.AudioFormat;
|
||||
}
|
||||
break;
|
||||
|
||||
case "DTS":
|
||||
audioCodec = movieFile.MediaInfo.AudioFormat;
|
||||
break;
|
||||
|
||||
default:
|
||||
audioCodec = movieFile.MediaInfo.AudioFormat;
|
||||
break;
|
||||
}
|
||||
|
||||
var mediaInfoAudioLanguages = GetLanguagesToken(movieFile.MediaInfo.AudioLanguages);
|
||||
if (!mediaInfoAudioLanguages.IsNullOrWhiteSpace())
|
||||
{
|
||||
mediaInfoAudioLanguages = string.Format("[{0}]", mediaInfoAudioLanguages);
|
||||
}
|
||||
|
||||
if (mediaInfoAudioLanguages == "[EN]")
|
||||
{
|
||||
mediaInfoAudioLanguages = string.Empty;
|
||||
}
|
||||
|
||||
var mediaInfoSubtitleLanguages = GetLanguagesToken(movieFile.MediaInfo.Subtitles);
|
||||
if (!mediaInfoSubtitleLanguages.IsNullOrWhiteSpace())
|
||||
{
|
||||
mediaInfoSubtitleLanguages = string.Format("[{0}]", mediaInfoSubtitleLanguages);
|
||||
}
|
||||
|
||||
var videoBitDepth = movieFile.MediaInfo.VideoBitDepth > 0 ? movieFile.MediaInfo.VideoBitDepth.ToString() : string.Empty;
|
||||
var audioChannels = movieFile.MediaInfo.FormattedAudioChannels > 0 ?
|
||||
movieFile.MediaInfo.FormattedAudioChannels.ToString("F1", CultureInfo.InvariantCulture) :
|
||||
string.Empty;
|
||||
|
||||
tokenHandlers["{MediaInfo Video}"] = m => videoCodec;
|
||||
tokenHandlers["{MediaInfo VideoCodec}"] = m => videoCodec;
|
||||
tokenHandlers["{MediaInfo VideoBitDepth}"] = m => videoBitDepth;
|
||||
|
||||
tokenHandlers["{MediaInfo Audio}"] = m => audioCodec;
|
||||
tokenHandlers["{MediaInfo AudioCodec}"] = m => audioCodec;
|
||||
tokenHandlers["{MediaInfo AudioChannels}"] = m => audioChannels;
|
||||
|
||||
tokenHandlers["{MediaInfo Simple}"] = m => string.Format("{0} {1}", videoCodec, audioCodec);
|
||||
|
||||
tokenHandlers["{MediaInfo Full}"] = m => string.Format("{0} {1}{2} {3}", videoCodec, audioCodec, mediaInfoAudioLanguages, mediaInfoSubtitleLanguages);
|
||||
}
|
||||
|
||||
private string GetLanguagesToken(string mediaInfoLanguages)
|
||||
{
|
||||
List<string> tokens = new List<string>();
|
||||
|
@ -803,6 +914,16 @@ namespace NzbDrone.Core.Organizer
|
|||
return MultiPartCleanupRegex.Replace(title, string.Empty).Trim();
|
||||
}
|
||||
|
||||
private string GetQualityProper(Movie movie, QualityModel quality)
|
||||
{
|
||||
if (quality.Revision.Version > 1)
|
||||
{
|
||||
return "Proper";
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
private string GetQualityProper(Series series, QualityModel quality)
|
||||
{
|
||||
if (quality.Revision.Version > 1)
|
||||
|
@ -828,6 +949,16 @@ namespace NzbDrone.Core.Organizer
|
|||
return string.Empty;
|
||||
}
|
||||
|
||||
private string GetQualityReal(Movie movie, QualityModel quality)
|
||||
{
|
||||
if (quality.Revision.Real > 0)
|
||||
{
|
||||
return "REAL";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private string GetOriginalTitle(EpisodeFile episodeFile)
|
||||
{
|
||||
if (episodeFile.SceneName.IsNullOrWhiteSpace())
|
||||
|
|
|
@ -3,6 +3,7 @@ using NzbDrone.Core.MediaFiles;
|
|||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Organizer
|
||||
{
|
||||
|
@ -13,8 +14,10 @@ namespace NzbDrone.Core.Organizer
|
|||
SampleResult GetDailySample(NamingConfig nameSpec);
|
||||
SampleResult GetAnimeSample(NamingConfig nameSpec);
|
||||
SampleResult GetAnimeMultiEpisodeSample(NamingConfig nameSpec);
|
||||
SampleResult GetMovieSample(NamingConfig nameSpec);
|
||||
string GetSeriesFolderSample(NamingConfig nameSpec);
|
||||
string GetSeasonFolderSample(NamingConfig nameSpec);
|
||||
string GetMovieFolderSample(NamingConfig nameSpec);
|
||||
}
|
||||
|
||||
public class FileNameSampleService : IFilenameSampleService
|
||||
|
@ -34,10 +37,19 @@ namespace NzbDrone.Core.Organizer
|
|||
private static EpisodeFile _animeEpisodeFile;
|
||||
private static EpisodeFile _animeMultiEpisodeFile;
|
||||
|
||||
private static MovieFile _movieFile;
|
||||
private static Movie _movie;
|
||||
|
||||
public FileNameSampleService(IBuildFileNames buildFileNames)
|
||||
{
|
||||
_buildFileNames = buildFileNames;
|
||||
|
||||
_movie = new Movie
|
||||
{
|
||||
Title = "Movie Title",
|
||||
Year = 2010
|
||||
};
|
||||
|
||||
_standardSeries = new Series
|
||||
{
|
||||
SeriesType = SeriesTypes.Standard,
|
||||
|
@ -106,6 +118,15 @@ namespace NzbDrone.Core.Organizer
|
|||
Subtitles = "Japanese/English"
|
||||
};
|
||||
|
||||
_movieFile = new MovieFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.Bluray1080p, new Revision(2)),
|
||||
RelativePath = "Movie.Title.2010.1080p.BluRay.DTS.x264-EVOLVE.mkv",
|
||||
SceneName = "Movie.Title.2010.1080p.BluRay.DTS.x264-EVOLVE",
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfo
|
||||
};
|
||||
|
||||
_singleEpisodeFile = new EpisodeFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.HDTV720p, new Revision(2)),
|
||||
|
@ -217,6 +238,16 @@ namespace NzbDrone.Core.Organizer
|
|||
return result;
|
||||
}
|
||||
|
||||
public SampleResult GetMovieSample(NamingConfig nameSpec)
|
||||
{
|
||||
var result = new SampleResult
|
||||
{
|
||||
FileName = BuildSample(_movie, _movieFile, nameSpec),
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string GetSeriesFolderSample(NamingConfig nameSpec)
|
||||
{
|
||||
return _buildFileNames.GetSeriesFolder(_standardSeries, nameSpec);
|
||||
|
@ -227,6 +258,11 @@ namespace NzbDrone.Core.Organizer
|
|||
return _buildFileNames.GetSeasonFolder(_standardSeries, _episode1.SeasonNumber, nameSpec);
|
||||
}
|
||||
|
||||
public string GetMovieFolderSample(NamingConfig nameSpec)
|
||||
{
|
||||
return _buildFileNames.GetMovieFolder(_movie, nameSpec);
|
||||
}
|
||||
|
||||
private string BuildSample(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig nameSpec)
|
||||
{
|
||||
try
|
||||
|
@ -238,5 +274,17 @@ namespace NzbDrone.Core.Organizer
|
|||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildSample(Movie movie, MovieFile movieFile, NamingConfig nameSpec)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _buildFileNames.BuildFileName(movie, movieFile, nameSpec);
|
||||
}
|
||||
catch (NamingFormatException)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,18 @@ namespace NzbDrone.Core.Organizer
|
|||
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
||||
return ruleBuilder.SetValidator(new RegularExpressionValidator(SeasonFolderRegex)).WithMessage("Must contain season number");
|
||||
}
|
||||
|
||||
public static IRuleBuilderOptions<T, string> ValidMovieFolderFormat<T>(this IRuleBuilder<T, string> ruleBuilder)
|
||||
{
|
||||
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
||||
return ruleBuilder.SetValidator(new RegularExpressionValidator(FileNameBuilder.MovieTitleRegex)).WithMessage("Must contain movie title");
|
||||
}
|
||||
|
||||
public static IRuleBuilderOptions<T, string> ValidMovieFormat<T>(this IRuleBuilder<T, string> ruleBuilder)
|
||||
{
|
||||
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
||||
return ruleBuilder.SetValidator(new RegularExpressionValidator(FileNameBuilder.MovieTitleRegex)).WithMessage("Must contain movie title");
|
||||
}
|
||||
}
|
||||
|
||||
public class ValidStandardEpisodeFormatValidator : PropertyValidator
|
||||
|
|
|
@ -11,12 +11,26 @@ namespace NzbDrone.Core.Organizer
|
|||
ValidationFailure ValidateStandardFilename(SampleResult sampleResult);
|
||||
ValidationFailure ValidateDailyFilename(SampleResult sampleResult);
|
||||
ValidationFailure ValidateAnimeFilename(SampleResult sampleResult);
|
||||
ValidationFailure ValidateMovieFilename(SampleResult sampleResult);
|
||||
}
|
||||
|
||||
public class FileNameValidationService : IFilenameValidationService
|
||||
{
|
||||
private const string ERROR_MESSAGE = "Produces invalid file names";
|
||||
|
||||
public ValidationFailure ValidateMovieFilename(SampleResult sampleResult)
|
||||
{
|
||||
var validationFailure = new ValidationFailure("MovieFormat", ERROR_MESSAGE);
|
||||
var parsedMovieInfo = Parser.Parser.ParseMovieTitle(sampleResult.FileName);
|
||||
|
||||
if(parsedMovieInfo == null)
|
||||
{
|
||||
return validationFailure;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ValidationFailure ValidateStandardFilename(SampleResult sampleResult)
|
||||
{
|
||||
var validationFailure = new ValidationFailure("StandardEpisodeFormat", ERROR_MESSAGE);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.Organizer
|
||||
{
|
||||
|
@ -13,7 +13,9 @@ namespace NzbDrone.Core.Organizer
|
|||
DailyEpisodeFormat = "{Series Title} - {Air-Date} - {Episode Title} {Quality Full}",
|
||||
AnimeEpisodeFormat = "{Series Title} - S{season:00}E{episode:00} - {Episode Title} {Quality Full}",
|
||||
SeriesFolderFormat = "{Series Title}",
|
||||
SeasonFolderFormat = "Season {season}"
|
||||
SeasonFolderFormat = "Season {season}",
|
||||
MovieFolderFormat = "{Movie Title} ({Release Year})",
|
||||
StandardMovieFormat = "{Movie Title} ({Release Year}) {Quality Full}",
|
||||
};
|
||||
|
||||
public bool RenameEpisodes { get; set; }
|
||||
|
@ -24,5 +26,7 @@ namespace NzbDrone.Core.Organizer
|
|||
public string AnimeEpisodeFormat { get; set; }
|
||||
public string SeriesFolderFormat { get; set; }
|
||||
public string SeasonFolderFormat { get; set; }
|
||||
public string StandardMovieFormat { get; set; }
|
||||
public string MovieFolderFormat { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ module.exports = Marionette.Layout.extend({
|
|||
},
|
||||
|
||||
initialize : function(options) {
|
||||
console.log(options)
|
||||
console.log(options);
|
||||
this.isExisting = options.isExisting;
|
||||
this.collection = new AddMoviesCollection();
|
||||
|
||||
|
@ -125,7 +125,7 @@ module.exports = Marionette.Layout.extend({
|
|||
}
|
||||
|
||||
else if (!this.isExisting) {
|
||||
this.resultCollectionView.setExisting(options.movie.get('tmdbId'))
|
||||
this.resultCollectionView.setExisting(options.movie.get('tmdbId'));
|
||||
/*this.collection.term = '';
|
||||
this.collection.reset();
|
||||
this._clearResults();
|
||||
|
|
|
@ -23,7 +23,7 @@ module.exports = Marionette.CollectionView.extend({
|
|||
|
||||
setExisting : function(tmdbid) {
|
||||
var movies = this.collection.where({ tmdbId : tmdbid });
|
||||
console.warn(movies)
|
||||
console.warn(movies);
|
||||
//debugger;
|
||||
if (movies.length > 0) {
|
||||
this.children.findByModel(movies[0])._configureTemplateHelpers();
|
||||
|
|
|
@ -92,14 +92,14 @@ var view = Marionette.ItemView.extend({
|
|||
|
||||
_configureTemplateHelpers : function() {
|
||||
var existingMovies = MoviesCollection.where({ tmdbId : this.model.get('tmdbId') });
|
||||
console.log(existingMovies)
|
||||
console.log(existingMovies);
|
||||
if (existingMovies.length > 0) {
|
||||
this.templateHelpers.existing = existingMovies[0].toJSON();
|
||||
}
|
||||
|
||||
this.templateHelpers.profiles = Profiles.toJSON();
|
||||
console.log(this.model)
|
||||
console.log(this.templateHelpers.existing)
|
||||
console.log(this.model);
|
||||
console.log(this.templateHelpers.existing);
|
||||
if (!this.model.get('isExisting')) {
|
||||
this.templateHelpers.rootFolders = RootFolders.toJSON();
|
||||
}
|
||||
|
@ -245,14 +245,14 @@ var view = Marionette.ItemView.extend({
|
|||
options.ignoreEpisodesWithoutFiles = true;
|
||||
}
|
||||
|
||||
else if (monitor === 'latest') {
|
||||
this.model.setSeasonPass(lastSeason.seasonNumber);
|
||||
}
|
||||
// else if (monitor === 'latest') {
|
||||
// this.model.setSeasonPass(lastSeason.seasonNumber);
|
||||
// }
|
||||
|
||||
else if (monitor === 'first') {
|
||||
this.model.setSeasonPass(lastSeason.seasonNumber + 1);
|
||||
this.model.setSeasonMonitored(firstSeason.seasonNumber);
|
||||
}
|
||||
// else if (monitor === 'first') {
|
||||
// this.model.setSeasonPass(lastSeason.seasonNumber + 1);
|
||||
// this.model.setSeasonMonitored(firstSeason.seasonNumber);
|
||||
// }
|
||||
|
||||
else if (monitor === 'missing') {
|
||||
options.ignoreEpisodesWithFiles = true;
|
||||
|
@ -262,9 +262,9 @@ var view = Marionette.ItemView.extend({
|
|||
options.ignoreEpisodesWithoutFiles = true;
|
||||
}
|
||||
|
||||
else if (monitor === 'none') {
|
||||
this.model.setSeasonPass(lastSeason.seasonNumber + 1);
|
||||
}
|
||||
// else if (monitor === 'none') {
|
||||
// this.model.setSeasonPass(lastSeason.seasonNumber + 1);
|
||||
// }
|
||||
|
||||
return options;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<legend>File Management</legend>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Ignore Deleted Episodes</label>
|
||||
<label class="col-sm-3 control-label">Ignore Deleted Movies</label>
|
||||
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
|
@ -17,7 +17,7 @@
|
|||
</label>
|
||||
|
||||
<span class="help-inline-checkbox">
|
||||
<i class="icon-sonarr-form-info" title="Episodes deleted from disk are automatically unmonitored in Sonarr"/>
|
||||
<i class="icon-sonarr-form-info" title="Movies deleted from disk are automatically unmonitored in Radarr"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -39,7 +39,7 @@
|
|||
</label>
|
||||
|
||||
<span class="help-inline-checkbox">
|
||||
<i class="icon-sonarr-form-info" title="Should Sonarr automatically upgrade to propers when available?"/>
|
||||
<i class="icon-sonarr-form-info" title="Should Radarr automatically upgrade to propers when available?"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -26,10 +26,10 @@ var view = Marionette.ItemView.extend({
|
|||
},
|
||||
|
||||
_parseNamingModel : function() {
|
||||
var standardFormat = this.namingModel.get('standardEpisodeFormat');
|
||||
var standardFormat = this.namingModel.get('standardMovieFormat');
|
||||
|
||||
var includeSeriesTitle = standardFormat.match(/\{Series[-_. ]Title\}/i);
|
||||
var includeEpisodeTitle = standardFormat.match(/\{Episode[-_. ]Title\}/i);
|
||||
var includeSeriesTitle = false;//standardFormat.match(/\{Series[-_. ]Title\}/i);
|
||||
var includeEpisodeTitle = false;//standardFormat.match(/\{Episode[-_. ]Title\}/i);
|
||||
var includeQuality = standardFormat.match(/\{Quality[-_. ]Title\}/i);
|
||||
var numberStyle = standardFormat.match(/s?\{season(?:\:0+)?\}[ex]\{episode(?:\:0+)?\}/i);
|
||||
var replaceSpaces = standardFormat.indexOf(' ') === -1;
|
||||
|
@ -115,4 +115,4 @@ var view = Marionette.ItemView.extend({
|
|||
}
|
||||
});
|
||||
|
||||
module.exports = AsModelBoundView.call(view);
|
||||
module.exports = AsModelBoundView.call(view);
|
||||
|
|
|
@ -19,7 +19,9 @@ module.exports = (function() {
|
|||
namingTokenHelper : '.x-naming-token-helper',
|
||||
multiEpisodeStyle : '.x-multi-episode-style',
|
||||
seriesFolderExample : '.x-series-folder-example',
|
||||
seasonFolderExample : '.x-season-folder-example'
|
||||
seasonFolderExample : '.x-season-folder-example',
|
||||
movieExample : '.x-movie-example',
|
||||
movieFolderExample : '.x-movie-folder-example'
|
||||
},
|
||||
events : {
|
||||
"change .x-rename-episodes" : '_setFailedDownloadOptionsVisibility',
|
||||
|
@ -58,6 +60,8 @@ module.exports = (function() {
|
|||
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'));
|
||||
},
|
||||
_addToken : function(e) {
|
||||
e.preventDefault();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<fieldset>
|
||||
<legend>Episode Naming</legend>
|
||||
<legend>Movie Naming</legend>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Rename Episodes</label>
|
||||
<label class="col-sm-3 control-label">Rename Movies</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
|
@ -18,7 +18,7 @@
|
|||
</label>
|
||||
|
||||
<span class="help-inline-checkbox">
|
||||
<i class="icon-sonarr-form-warning" title="Sonarr will use the existing file name if set to no"/>
|
||||
<i class="icon-sonarr-form-warning" title="Radarr will use the existing file name if set to no"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -51,25 +51,23 @@
|
|||
<div class="basic-setting x-basic-naming"></div>
|
||||
|
||||
<div class="form-group advanced-setting">
|
||||
<label class="col-sm-3 control-label">Standard 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">
|
||||
<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/NzbDrone/NzbDrone/wiki/Sorting-and-Renaming" class="help-link" title="More information"><i class="icon-sonarr-form-info-link"/></a> <!-- TODO: Update wiki link -->
|
||||
</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="standardEpisodeFormat" 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}}
|
||||
{{> SeasonNamingPartial}}
|
||||
{{> EpisodeNamingPartial}}
|
||||
{{> EpisodeTitleNamingPartial}}
|
||||
{{> MovieTitleNamingPartial}}
|
||||
{{> ReleaseYearNamingPartial}}
|
||||
{{> QualityNamingPartial}}
|
||||
{{> MediaInfoNamingPartial}}
|
||||
{{> ReleaseGroupNamingPartial}}
|
||||
|
@ -81,7 +79,7 @@
|
|||
</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="col-sm-1 col-sm-push-8 help-inline">
|
||||
|
@ -111,9 +109,9 @@
|
|||
</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>
|
||||
|
||||
<div class="col-sm-1 col-sm-push-8 help-inline">
|
||||
|
@ -144,31 +142,32 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>--}}
|
||||
|
||||
<div class="form-group advanced-setting">
|
||||
<label class="col-sm-3 control-label">Series Folder Format</label>
|
||||
<label class="col-sm-3 control-label">Movie Folder 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. Only used when adding a new series."></i>
|
||||
<i class="icon-sonarr-form-info" title="" data-original-title="All caps or all lower-case can also be used. Only used when adding a new movie."></i>
|
||||
</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="seriesFolderFormat" data-onkeyup="true"/>
|
||||
<input type="text" class="form-control naming-format" name="movieFolderFormat" 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}}
|
||||
{{> MovieTitleNamingPartial}}
|
||||
{{> ReleaseYearNamingPartial}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{!--<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Season Folder Format</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
|
@ -186,9 +185,9 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>--}}
|
||||
|
||||
<div class="x-naming-options">
|
||||
{{!--<div class="x-naming-options">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Multi-Episode Style</label>
|
||||
|
||||
|
@ -203,17 +202,17 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>--}}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Single Episode Example</label>
|
||||
<label class="col-sm-3 control-label">Movie Example</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
<p class="form-control-static x-single-episode-example naming-example"></p>
|
||||
<p class="form-control-static x-movie-example naming-example"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{!--<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Multi-Episode Example</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
|
@ -242,21 +241,21 @@
|
|||
<div class="col-sm-8">
|
||||
<p class="form-control-static x-anime-multi-episode-example naming-example"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>--}}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Series Folder Example</label>
|
||||
<label class="col-sm-3 control-label">Movie Folder Example</label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
<p class="form-control-static x-series-folder-example naming-example"></p>
|
||||
<p class="form-control-static x-movie-folder-example naming-example"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{!--<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>
|
||||
</div>--}}
|
||||
</fieldset>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<li class="dropdown-submenu">
|
||||
<a href="#" tabindex="-1" data-token="Movie Title">Movie Title</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" data-token="Movie Title">Movie Title</a></li>
|
||||
<li><a href="#" data-token="Movie.Title">Movie.Title</a></li>
|
||||
<li><a href="#" data-token="Movie_Title">Movie_Title</a></li>
|
||||
<li><a href="#" data-token="Movie CleanTitle">Movie CleanTitle</a></li>
|
||||
<li><a href="#" data-token="Movie.CleanTitle">Movie.CleanTitle</a></li>
|
||||
<li><a href="#" data-token="Movie_CleanTitle">Movie_CleanTitle</a></li>
|
||||
</ul>
|
||||
</li>
|
|
@ -0,0 +1 @@
|
|||
<li><a href="#" data-token="Release Year">Release Year</a></li>
|
|
@ -2,7 +2,7 @@
|
|||
<legend>Folders</legend>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Create empty series folders</label>
|
||||
<label class="col-sm-3 control-label">Create empty movie folders</label>
|
||||
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
|
@ -18,7 +18,7 @@
|
|||
</label>
|
||||
|
||||
<span class="help-inline-checkbox">
|
||||
<i class="icon-sonarr-form-info" title="Create missing series folders during disk scan"/>
|
||||
<i class="icon-sonarr-form-info" title="Create missing movie folders during disk scan"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -46,7 +46,7 @@
|
|||
</label>
|
||||
|
||||
<span class="help-inline-checkbox">
|
||||
<i class="icon-sonarr-form-info" title="Use when drone is unable to detect free space from your series root folder"/>
|
||||
<i class="icon-sonarr-form-info" title="Use when drone is unable to detect free space from your movies root folder"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -71,7 +71,7 @@
|
|||
|
||||
<span class="help-inline-checkbox">
|
||||
<i class="icon-sonarr-form-info" title="Use Hardlinks when trying to copy files from torrents that are still being seeded"/>
|
||||
<i class="icon-sonarr-form-warning" title="Occasionally, file locks may prevent renaming files that are being seeded. You may temporarily disable seeding and use Sonarr's rename function as a work around."/>
|
||||
<i class="icon-sonarr-form-warning" title="Occasionally, file locks may prevent renaming files that are being seeded. You may temporarily disable seeding and use Radarr's rename function as a work around."/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue