#680 - begin resolution feature

This commit is contained in:
Luke Pulverenti 2014-01-21 11:24:12 -05:00
parent 1235283279
commit a29e1eb036
5 changed files with 93 additions and 53 deletions

View File

@ -328,16 +328,12 @@ namespace MediaBrowser.Model.Configuration
public string SeasonZeroFolderName { get; set; }
public string EpisodeNamePattern { get; set; }
public string MultiEpisodeNamePattern { get; set; }
public bool OverwriteExistingEpisodes { get; set; }
public bool DeleteEmptyFolders { get; set; }
/// <summary>
/// Will log results but will not actually make any changes
/// </summary>
public bool EnableTrialMode { get; set; }
public TvFileOrganizationOptions()
{
MinFileSizeMb = 50;
@ -347,10 +343,9 @@ namespace MediaBrowser.Model.Configuration
WatchLocations = new string[] { };
EpisodeNamePattern = "%sn - %sx%0e - %en.%ext";
MultiEpisodeNamePattern = "%sn - %sx%0e-x%0ed - %en.%ext";
SeasonFolderPattern = "Season %s";
SeasonZeroFolderName = "Season 0";
EnableTrialMode = true;
}
}
}

View File

@ -33,6 +33,24 @@ namespace MediaBrowser.Model.FileOrganization
/// </summary>
/// <value>The extracted year.</value>
public int? ExtractedYear { get; set; }
/// <summary>
/// Gets or sets the extracted season number.
/// </summary>
/// <value>The extracted season number.</value>
public int? ExtractedSeasonNumber { get; set; }
/// <summary>
/// Gets or sets the extracted episode number.
/// </summary>
/// <value>The extracted episode number.</value>
public int? ExtractedEpisodeNumber { get; set; }
/// <summary>
/// Gets or sets the extracted ending episode number.
/// </summary>
/// <value>The extracted ending episode number.</value>
public int? ExtractedEndingEpisodeNumber { get; set; }
/// <summary>
/// Gets or sets the target path.
@ -69,8 +87,7 @@ namespace MediaBrowser.Model.FileOrganization
{
Success,
Failure,
SkippedExisting,
SkippedTrial
SkippedExisting
}
public enum FileOrganizerType

View File

@ -43,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
throw new ArgumentNullException("result");
}
result.Id = (result.OriginalPath + (result.TargetPath ?? string.Empty)).GetMD5().ToString("N");
result.Id = result.OriginalPath.GetMD5().ToString("N");
return _repo.SaveResult(result, cancellationToken);
}

View File

@ -67,7 +67,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
var result = await SortFile(file.FullName, options, allSeries).ConfigureAwait(false);
if (result.Status == FileSortingStatus.Success && !options.EnableTrialMode)
if (result.Status == FileSortingStatus.Success)
{
scanLibrary = true;
}
@ -83,19 +83,16 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
cancellationToken.ThrowIfCancellationRequested();
progress.Report(99);
if (!options.EnableTrialMode)
foreach (var path in watchLocations)
{
foreach (var path in watchLocations)
if (options.LeftOverFileExtensionsToDelete.Length > 0)
{
if (options.LeftOverFileExtensionsToDelete.Length > 0)
{
DeleteLeftOverFiles(path, options.LeftOverFileExtensionsToDelete);
}
DeleteLeftOverFiles(path, options.LeftOverFileExtensionsToDelete);
}
if (options.DeleteEmptyFolders)
{
DeleteEmptyFolders(path);
}
if (options.DeleteEmptyFolders)
{
DeleteEmptyFolders(path);
}
}
@ -153,16 +150,24 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
var season = TVUtils.GetSeasonNumberFromEpisodeFile(path);
result.ExtractedSeasonNumber = season;
if (season.HasValue)
{
// Passing in true will include a few extra regex's
var episode = TVUtils.GetEpisodeNumberFromFile(path, true);
result.ExtractedEpisodeNumber = episode;
if (episode.HasValue)
{
_logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, season, episode);
SortFile(path, seriesName, season.Value, episode.Value, options, allSeries, result);
var endingEpisodeNumber = TVUtils.GetEndingEpisodeNumberFromFile(path);
result.ExtractedEndingEpisodeNumber = endingEpisodeNumber;
SortFile(path, seriesName, season.Value, episode.Value, endingEpisodeNumber, options, allSeries, result);
}
else
{
@ -200,10 +205,11 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
/// <param name="seriesName">Name of the series.</param>
/// <param name="seasonNumber">The season number.</param>
/// <param name="episodeNumber">The episode number.</param>
/// <param name="endingEpiosdeNumber">The ending epiosde number.</param>
/// <param name="options">The options.</param>
/// <param name="allSeries">All series.</param>
/// <param name="result">The result.</param>
private void SortFile(string path, string seriesName, int seasonNumber, int episodeNumber, TvFileOrganizationOptions options, IEnumerable<Series> allSeries, FileOrganizationResult result)
private void SortFile(string path, string seriesName, int seasonNumber, int episodeNumber, int? endingEpiosdeNumber, TvFileOrganizationOptions options, IEnumerable<Series> allSeries, FileOrganizationResult result)
{
var series = GetMatchingSeries(seriesName, allSeries, result);
@ -219,7 +225,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
_logger.Info("Sorting file {0} into series {1}", path, series.Path);
// Proceed to sort the file
var newPath = GetNewPath(path, series, seasonNumber, episodeNumber, options);
var newPath = GetNewPath(path, series, seasonNumber, episodeNumber, endingEpiosdeNumber, options);
if (string.IsNullOrEmpty(newPath))
{
@ -233,12 +239,6 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
_logger.Info("Sorting file {0} to new path {1}", path, newPath);
result.TargetPath = newPath;
if (options.EnableTrialMode)
{
result.Status = FileSortingStatus.SkippedTrial;
return;
}
var targetExists = File.Exists(result.TargetPath);
if (!options.OverwriteExistingEpisodes && targetExists)
{
@ -315,12 +315,17 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
/// <param name="series">The series.</param>
/// <param name="seasonNumber">The season number.</param>
/// <param name="episodeNumber">The episode number.</param>
/// <param name="endingEpisodeNumber">The ending episode number.</param>
/// <param name="options">The options.</param>
/// <returns>System.String.</returns>
private string GetNewPath(string sourcePath, Series series, int seasonNumber, int episodeNumber, TvFileOrganizationOptions options)
private string GetNewPath(string sourcePath, Series series, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, TvFileOrganizationOptions options)
{
// If season and episode numbers match
var currentEpisodes = series.RecursiveChildren.OfType<Episode>()
.Where(i => i.IndexNumber.HasValue && i.IndexNumber.Value == episodeNumber && i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber)
.Where(i => i.IndexNumber.HasValue &&
i.IndexNumber.Value == episodeNumber &&
i.ParentIndexNumber.HasValue &&
i.ParentIndexNumber.Value == seasonNumber)
.ToList();
if (currentEpisodes.Count == 0)
@ -328,33 +333,27 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
return null;
}
var newPath = currentEpisodes
.Where(i => i.LocationType == LocationType.FileSystem)
.Select(i => i.Path)
.FirstOrDefault();
var newPath = GetSeasonFolderPath(series, seasonNumber, options);
if (string.IsNullOrEmpty(newPath))
{
newPath = GetSeasonFolderPath(series, seasonNumber, options);
var episode = currentEpisodes.First();
var episode = currentEpisodes.First();
var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber, episodeNumber, endingEpisodeNumber, episode.Name, options);
var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber, episodeNumber, episode.Name, options);
newPath = Path.Combine(newPath, episodeFileName);
}
newPath = Path.Combine(newPath, episodeFileName);
return newPath;
}
private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, string episodeTitle, TvFileOrganizationOptions options)
private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, string episodeTitle, TvFileOrganizationOptions options)
{
seriesName = _fileSystem.GetValidFilename(seriesName);
episodeTitle = _fileSystem.GetValidFilename(episodeTitle);
var sourceExtension = (Path.GetExtension(sourcePath) ?? string.Empty).TrimStart('.');
return options.EpisodeNamePattern.Replace("%sn", seriesName)
var pattern = endingEpisodeNumber.HasValue ? options.MultiEpisodeNamePattern : options.EpisodeNamePattern;
var result = pattern.Replace("%sn", seriesName)
.Replace("%s.n", seriesName.Replace(" ", "."))
.Replace("%s_n", seriesName.Replace(" ", "_"))
.Replace("%s", seasonNumber.ToString(UsCulture))
@ -363,8 +362,16 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
.Replace("%ext", sourceExtension)
.Replace("%en", episodeTitle)
.Replace("%e.n", episodeTitle.Replace(" ", "."))
.Replace("%e_n", episodeTitle.Replace(" ", "_"))
.Replace("%e", episodeNumber.ToString(UsCulture))
.Replace("%e_n", episodeTitle.Replace(" ", "_"));
if (endingEpisodeNumber.HasValue)
{
result = result.Replace("%ed", endingEpisodeNumber.Value.ToString(UsCulture))
.Replace("%0ed", endingEpisodeNumber.Value.ToString("00", UsCulture))
.Replace("%00ed", endingEpisodeNumber.Value.ToString("000", UsCulture));
}
return result.Replace("%e", episodeNumber.ToString(UsCulture))
.Replace("%0e", episodeNumber.ToString("00", UsCulture))
.Replace("%00e", episodeNumber.ToString("000", UsCulture));
}

View File

@ -47,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
string[] queries = {
"create table if not exists organizationresults (ResultId GUID PRIMARY KEY, OriginalPath TEXT, TargetPath TEXT, OrganizationDate datetime, Status TEXT, OrganizationType TEXT, StatusMessage TEXT, ExtractedName TEXT, ExtractedYear int null)",
"create table if not exists organizationresults (ResultId GUID PRIMARY KEY, OriginalPath TEXT, TargetPath TEXT, OrganizationDate datetime, Status TEXT, OrganizationType TEXT, StatusMessage TEXT, ExtractedName TEXT, ExtractedYear int null, ExtractedSeasonNumber int null, ExtractedEpisodeNumber int null, ExtractedEndingEpisodeNumber int null)",
"create index if not exists idx_organizationresults on organizationresults(ResultId)",
//pragmas
@ -66,7 +66,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
private void PrepareStatements()
{
_saveResultCommand = _connection.CreateCommand();
_saveResultCommand.CommandText = "replace into organizationresults (ResultId, OriginalPath, TargetPath, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear) values (@ResultId, @OriginalPath, @TargetPath, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear)";
_saveResultCommand.CommandText = "replace into organizationresults (ResultId, OriginalPath, TargetPath, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber) values (@ResultId, @OriginalPath, @TargetPath, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear, @ExtractedSeasonNumber, @ExtractedEpisodeNumber, @ExtractedEndingEpisodeNumber)";
_saveResultCommand.Parameters.Add(_saveResultCommand, "@ResultId");
_saveResultCommand.Parameters.Add(_saveResultCommand, "@OriginalPath");
@ -77,6 +77,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveResultCommand.Parameters.Add(_saveResultCommand, "@StatusMessage");
_saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedName");
_saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedYear");
_saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedSeasonNumber");
_saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedEpisodeNumber");
_saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedEndingEpisodeNumber");
_deleteResultCommand = _connection.CreateCommand();
_deleteResultCommand.CommandText = "delete from organizationresults where ResultId = @ResultId";
@ -110,6 +113,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveResultCommand.GetParameter(6).Value = result.StatusMessage;
_saveResultCommand.GetParameter(7).Value = result.ExtractedName;
_saveResultCommand.GetParameter(8).Value = result.ExtractedYear;
_saveResultCommand.GetParameter(9).Value = result.ExtractedSeasonNumber;
_saveResultCommand.GetParameter(10).Value = result.ExtractedEpisodeNumber;
_saveResultCommand.GetParameter(11).Value = result.ExtractedEndingEpisodeNumber;
_saveResultCommand.Transaction = transaction;
@ -211,7 +217,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand())
{
cmd.CommandText = "SELECT ResultId, OriginalPath, TargetPath, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear from organizationresults";
cmd.CommandText = "SELECT ResultId, OriginalPath, TargetPath, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber from organizationresults";
if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
{
@ -263,7 +269,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand())
{
cmd.CommandText = "select ResultId, OriginalPath, TargetPath, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear from organizationresults where ResultId=@Id";
cmd.CommandText = "select ResultId, OriginalPath, TargetPath, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber from organizationresults where ResultId=@Id";
cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
@ -317,6 +323,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
result.ExtractedYear = reader.GetInt32(8);
}
if (!reader.IsDBNull(9))
{
result.ExtractedSeasonNumber = reader.GetInt32(9);
}
if (!reader.IsDBNull(10))
{
result.ExtractedEpisodeNumber = reader.GetInt32(10);
}
if (!reader.IsDBNull(11))
{
result.ExtractedEndingEpisodeNumber = reader.GetInt32(11);
}
return result;
}