New: Release Type (Single/Multi episode and Season Pack) for Custom Formats
Closes #3562
This commit is contained in:
parent
c99d81e79b
commit
f8a0751775
|
@ -0,0 +1,191 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Datastore.Migration;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Migration
|
||||
{
|
||||
[TestFixture]
|
||||
public class release_typeFixture : MigrationTest<release_type>
|
||||
{
|
||||
[Test]
|
||||
public void should_convert_single_episode_without_folder()
|
||||
{
|
||||
var db = WithMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("EpisodeFiles").Row(new
|
||||
{
|
||||
SeriesId = 1,
|
||||
SeasonNumber = 1,
|
||||
RelativePath = "Season 01/S01E05.mkv",
|
||||
Size = 125.Megabytes(),
|
||||
DateAdded = DateTime.UtcNow.AddDays(-5),
|
||||
OriginalFilePath = "Series.Title.S01E05.720p.HDTV.x265-Sonarr.mkv",
|
||||
ReleaseGroup = "Sonarr",
|
||||
Quality = new QualityModel(Quality.HDTV720p).ToJson(),
|
||||
Languages = "[1]"
|
||||
});
|
||||
});
|
||||
|
||||
var items = db.Query<EpisodeFile203>("SELECT * FROM \"EpisodeFiles\"");
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
|
||||
items.First().ReleaseType.Should().Be((int)ReleaseType.SingleEpisode);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_convert_single_episode_with_folder()
|
||||
{
|
||||
var db = WithMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("EpisodeFiles").Row(new
|
||||
{
|
||||
SeriesId = 1,
|
||||
SeasonNumber = 1,
|
||||
RelativePath = "Season 01/S01E05.mkv",
|
||||
Size = 125.Megabytes(),
|
||||
DateAdded = DateTime.UtcNow.AddDays(-5),
|
||||
OriginalFilePath = "Series.Title.S01E05.720p.HDTV.x265-Sonarr/S01E05.mkv",
|
||||
ReleaseGroup = "Sonarr",
|
||||
Quality = new QualityModel(Quality.HDTV720p).ToJson(),
|
||||
Languages = "[1]"
|
||||
});
|
||||
});
|
||||
|
||||
var items = db.Query<EpisodeFile203>("SELECT * FROM \"EpisodeFiles\"");
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
|
||||
items.First().ReleaseType.Should().Be((int)ReleaseType.SingleEpisode);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_convert_multi_episode_without_folder()
|
||||
{
|
||||
var db = WithMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("EpisodeFiles").Row(new
|
||||
{
|
||||
SeriesId = 1,
|
||||
SeasonNumber = 1,
|
||||
RelativePath = "Season 01/S01E05.mkv",
|
||||
Size = 125.Megabytes(),
|
||||
DateAdded = DateTime.UtcNow.AddDays(-5),
|
||||
OriginalFilePath = "Series.Title.S01E05E06.720p.HDTV.x265-Sonarr.mkv",
|
||||
ReleaseGroup = "Sonarr",
|
||||
Quality = new QualityModel(Quality.HDTV720p).ToJson(),
|
||||
Languages = "[1]"
|
||||
});
|
||||
});
|
||||
|
||||
var items = db.Query<EpisodeFile203>("SELECT * FROM \"EpisodeFiles\"");
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
|
||||
items.First().ReleaseType.Should().Be((int)ReleaseType.MultiEpisode);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_convert_multi_episode_with_folder()
|
||||
{
|
||||
var db = WithMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("EpisodeFiles").Row(new
|
||||
{
|
||||
SeriesId = 1,
|
||||
SeasonNumber = 1,
|
||||
RelativePath = "Season 01/S01E05.mkv",
|
||||
Size = 125.Megabytes(),
|
||||
DateAdded = DateTime.UtcNow.AddDays(-5),
|
||||
OriginalFilePath = "Series.Title.S01E05E06.720p.HDTV.x265-Sonarr/S01E05E06.mkv",
|
||||
ReleaseGroup = "Sonarr",
|
||||
Quality = new QualityModel(Quality.HDTV720p).ToJson(),
|
||||
Languages = "[1]"
|
||||
});
|
||||
});
|
||||
|
||||
var items = db.Query<EpisodeFile203>("SELECT * FROM \"EpisodeFiles\"");
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
|
||||
items.First().ReleaseType.Should().Be((int)ReleaseType.MultiEpisode);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_convert_season_pack_with_folder()
|
||||
{
|
||||
var db = WithMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("EpisodeFiles").Row(new
|
||||
{
|
||||
SeriesId = 1,
|
||||
SeasonNumber = 1,
|
||||
RelativePath = "Season 01/S01E05.mkv",
|
||||
Size = 125.Megabytes(),
|
||||
DateAdded = DateTime.UtcNow.AddDays(-5),
|
||||
OriginalFilePath = "Series.Title.S01.720p.HDTV.x265-Sonarr/S01E05.mkv",
|
||||
ReleaseGroup = "Sonarr",
|
||||
Quality = new QualityModel(Quality.HDTV720p).ToJson(),
|
||||
Languages = "[1]"
|
||||
});
|
||||
});
|
||||
|
||||
var items = db.Query<EpisodeFile203>("SELECT * FROM \"EpisodeFiles\"");
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
|
||||
items.First().ReleaseType.Should().Be((int)ReleaseType.SeasonPack);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_convert_episode_without_original_file_path()
|
||||
{
|
||||
var db = WithMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("EpisodeFiles").Row(new
|
||||
{
|
||||
SeriesId = 1,
|
||||
SeasonNumber = 1,
|
||||
RelativePath = "Season 01/S01E05.mkv",
|
||||
Size = 125.Megabytes(),
|
||||
DateAdded = DateTime.UtcNow.AddDays(-5),
|
||||
ReleaseGroup = "Sonarr",
|
||||
Quality = new QualityModel(Quality.HDTV720p).ToJson(),
|
||||
Languages = "[1]"
|
||||
});
|
||||
});
|
||||
|
||||
var items = db.Query<EpisodeFile203>("SELECT * FROM \"EpisodeFiles\"");
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
|
||||
items.First().ReleaseType.Should().Be((int)ReleaseType.Unknown);
|
||||
}
|
||||
|
||||
public class EpisodeFile203
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int SeriesId { get; set; }
|
||||
public int SeasonNumber { get; set; }
|
||||
public string RelativePath { get; set; }
|
||||
public long Size { get; set; }
|
||||
public DateTime DateAdded { get; set; }
|
||||
public string OriginalFilePath { get; set; }
|
||||
public string SceneName { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public long IndexerFlags { get; set; }
|
||||
public MediaInfoModel MediaInfo { get; set; }
|
||||
public List<int> Languages { get; set; }
|
||||
public long ReleaseType { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,6 +49,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
_rejectedDecisions.Add(new ImportDecision(new LocalEpisode(), new Rejection("Rejected!")));
|
||||
_rejectedDecisions.Add(new ImportDecision(new LocalEpisode(), new Rejection("Rejected!")));
|
||||
_rejectedDecisions.Add(new ImportDecision(new LocalEpisode(), new Rejection("Rejected!")));
|
||||
_rejectedDecisions.ForEach(r => r.LocalEpisode.FileEpisodeInfo = new ParsedEpisodeInfo());
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
|
@ -59,7 +60,8 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
Episodes = new List<Episode> { episode },
|
||||
Path = Path.Combine(series.Path, "30 Rock - S01E01 - Pilot.avi"),
|
||||
Quality = new QualityModel(Quality.Bluray720p),
|
||||
ReleaseGroup = "DRONE"
|
||||
ReleaseGroup = "DRONE",
|
||||
FileEpisodeInfo = new ParsedEpisodeInfo()
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace NzbDrone.Core.Blocklisting
|
|||
public DownloadProtocol Protocol { get; set; }
|
||||
public string Indexer { get; set; }
|
||||
public IndexerFlags IndexerFlags { get; set; }
|
||||
public ReleaseType ReleaseType { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string TorrentInfoHash { get; set; }
|
||||
public List<Language> Languages { get; set; }
|
||||
|
|
|
@ -194,6 +194,11 @@ namespace NzbDrone.Core.Blocklisting
|
|||
blocklist.IndexerFlags = flags;
|
||||
}
|
||||
|
||||
if (Enum.TryParse(message.Data.GetValueOrDefault("releaseType"), true, out ReleaseType releaseType))
|
||||
{
|
||||
blocklist.ReleaseType = releaseType;
|
||||
}
|
||||
|
||||
_blocklistRepository.Insert(blocklist);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,8 @@ namespace NzbDrone.Core.CustomFormats
|
|||
Series = remoteEpisode.Series,
|
||||
Size = size,
|
||||
Languages = remoteEpisode.Languages,
|
||||
IndexerFlags = remoteEpisode.Release?.IndexerFlags ?? 0
|
||||
IndexerFlags = remoteEpisode.Release?.IndexerFlags ?? 0,
|
||||
ReleaseType = remoteEpisode.ParsedEpisodeInfo.ReleaseType
|
||||
};
|
||||
|
||||
return ParseCustomFormat(input);
|
||||
|
@ -76,7 +77,8 @@ namespace NzbDrone.Core.CustomFormats
|
|||
Series = series,
|
||||
Size = blocklist.Size ?? 0,
|
||||
Languages = blocklist.Languages,
|
||||
IndexerFlags = blocklist.IndexerFlags
|
||||
IndexerFlags = blocklist.IndexerFlags,
|
||||
ReleaseType = blocklist.ReleaseType
|
||||
};
|
||||
|
||||
return ParseCustomFormat(input);
|
||||
|
@ -88,6 +90,7 @@ namespace NzbDrone.Core.CustomFormats
|
|||
|
||||
long.TryParse(history.Data.GetValueOrDefault("size"), out var size);
|
||||
Enum.TryParse(history.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags indexerFlags);
|
||||
Enum.TryParse(history.Data.GetValueOrDefault("releaseType"), out ReleaseType releaseType);
|
||||
|
||||
var episodeInfo = new ParsedEpisodeInfo
|
||||
{
|
||||
|
@ -104,7 +107,8 @@ namespace NzbDrone.Core.CustomFormats
|
|||
Series = series,
|
||||
Size = size,
|
||||
Languages = history.Languages,
|
||||
IndexerFlags = indexerFlags
|
||||
IndexerFlags = indexerFlags,
|
||||
ReleaseType = releaseType
|
||||
};
|
||||
|
||||
return ParseCustomFormat(input);
|
||||
|
@ -128,6 +132,7 @@ namespace NzbDrone.Core.CustomFormats
|
|||
Size = localEpisode.Size,
|
||||
Languages = localEpisode.Languages,
|
||||
IndexerFlags = localEpisode.IndexerFlags,
|
||||
ReleaseType = localEpisode.ReleaseType,
|
||||
Filename = Path.GetFileName(localEpisode.Path)
|
||||
};
|
||||
|
||||
|
@ -188,7 +193,7 @@ namespace NzbDrone.Core.CustomFormats
|
|||
ReleaseTitle = releaseTitle,
|
||||
Quality = episodeFile.Quality,
|
||||
Languages = episodeFile.Languages,
|
||||
ReleaseGroup = episodeFile.ReleaseGroup
|
||||
ReleaseGroup = episodeFile.ReleaseGroup,
|
||||
};
|
||||
|
||||
var input = new CustomFormatInput
|
||||
|
@ -198,7 +203,8 @@ namespace NzbDrone.Core.CustomFormats
|
|||
Size = episodeFile.Size,
|
||||
Languages = episodeFile.Languages,
|
||||
IndexerFlags = episodeFile.IndexerFlags,
|
||||
Filename = Path.GetFileName(episodeFile.RelativePath)
|
||||
ReleaseType = episodeFile.ReleaseType,
|
||||
Filename = Path.GetFileName(episodeFile.RelativePath),
|
||||
};
|
||||
|
||||
return ParseCustomFormat(input, allCustomFormats);
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace NzbDrone.Core.CustomFormats
|
|||
public IndexerFlags IndexerFlags { get; set; }
|
||||
public List<Language> Languages { get; set; }
|
||||
public string Filename { get; set; }
|
||||
public ReleaseType ReleaseType { get; set; }
|
||||
|
||||
public CustomFormatInput()
|
||||
{
|
||||
|
|
|
@ -11,11 +11,11 @@ namespace NzbDrone.Core.CustomFormats
|
|||
public IndexerFlagSpecificationValidator()
|
||||
{
|
||||
RuleFor(c => c.Value).NotEmpty();
|
||||
RuleFor(c => c.Value).Custom((qualityValue, context) =>
|
||||
RuleFor(c => c.Value).Custom((flag, context) =>
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(IndexerFlags), qualityValue))
|
||||
if (!Enum.IsDefined(typeof(IndexerFlags), flag))
|
||||
{
|
||||
context.AddFailure($"Invalid indexer flag condition value: {qualityValue}");
|
||||
context.AddFailure($"Invalid indexer flag condition value: {flag}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.CustomFormats
|
||||
{
|
||||
public class SeasonPackSpecificationValidator : AbstractValidator<SeasonPackSpecification>
|
||||
{
|
||||
public SeasonPackSpecificationValidator()
|
||||
{
|
||||
RuleFor(c => c.Value).Custom((releaseType, context) =>
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(ReleaseType), releaseType))
|
||||
{
|
||||
context.AddFailure($"Invalid release type condition value: {releaseType}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class SeasonPackSpecification : CustomFormatSpecificationBase
|
||||
{
|
||||
private static readonly SeasonPackSpecificationValidator Validator = new ();
|
||||
|
||||
public override int Order => 10;
|
||||
public override string ImplementationName => "Release Type";
|
||||
|
||||
[FieldDefinition(1, Label = "ReleaseType", Type = FieldType.Select, SelectOptions = typeof(ReleaseType))]
|
||||
public int Value { get; set; }
|
||||
|
||||
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
|
||||
{
|
||||
return input.ReleaseType == (ReleaseType)Value;
|
||||
}
|
||||
|
||||
public override NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using Dapper;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(203)]
|
||||
public class release_type : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("Blocklist").AddColumn("ReleaseType").AsInt32().WithDefaultValue(0);
|
||||
Alter.Table("EpisodeFiles").AddColumn("ReleaseType").AsInt32().WithDefaultValue(0);
|
||||
|
||||
Execute.WithConnection(UpdateEpisodeFiles);
|
||||
}
|
||||
|
||||
private void UpdateEpisodeFiles(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
var updates = new List<object>();
|
||||
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.Transaction = tran;
|
||||
cmd.CommandText = "SELECT \"Id\", \"OriginalFilePath\" FROM \"EpisodeFiles\" WHERE \"OriginalFilePath\" IS NOT NULL";
|
||||
|
||||
using var reader = cmd.ExecuteReader();
|
||||
while (reader.Read())
|
||||
{
|
||||
var id = reader.GetInt32(0);
|
||||
var originalFilePath = reader.GetString(1);
|
||||
|
||||
var folderName = Path.GetDirectoryName(originalFilePath);
|
||||
var fileName = Path.GetFileNameWithoutExtension(originalFilePath);
|
||||
var title = folderName.IsNullOrWhiteSpace() ? fileName : folderName;
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(title);
|
||||
|
||||
if (parsedEpisodeInfo != null && parsedEpisodeInfo.ReleaseType != ReleaseType.Unknown)
|
||||
{
|
||||
updates.Add(new
|
||||
{
|
||||
Id = id,
|
||||
ReleaseType = (int)parsedEpisodeInfo.ReleaseType
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var updateEpisodeFilesSql = "UPDATE \"EpisodeFiles\" SET \"ReleaseType\" = @ReleaseType WHERE \"Id\" = @Id";
|
||||
conn.Execute(updateEpisodeFilesSql, updates, transaction: tran);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -170,6 +170,7 @@ namespace NzbDrone.Core.History
|
|||
history.Data.Add("SeriesMatchType", message.Episode.SeriesMatchType.ToString());
|
||||
history.Data.Add("ReleaseSource", message.Episode.ReleaseSource.ToString());
|
||||
history.Data.Add("IndexerFlags", message.Episode.Release.IndexerFlags.ToString());
|
||||
history.Data.Add("ReleaseType", message.Episode.ParsedEpisodeInfo.ReleaseType.ToString());
|
||||
|
||||
if (!message.Episode.ParsedEpisodeInfo.ReleaseHash.IsNullOrWhiteSpace())
|
||||
{
|
||||
|
@ -222,6 +223,7 @@ namespace NzbDrone.Core.History
|
|||
history.Data.Add("CustomFormatScore", message.EpisodeInfo.CustomFormatScore.ToString());
|
||||
history.Data.Add("Size", message.EpisodeInfo.Size.ToString());
|
||||
history.Data.Add("IndexerFlags", message.ImportedEpisode.IndexerFlags.ToString());
|
||||
history.Data.Add("ReleaseType", message.ImportedEpisode.ReleaseType.ToString());
|
||||
|
||||
_historyRepository.Insert(history);
|
||||
}
|
||||
|
@ -283,6 +285,7 @@ namespace NzbDrone.Core.History
|
|||
history.Data.Add("ReleaseGroup", message.EpisodeFile.ReleaseGroup);
|
||||
history.Data.Add("Size", message.EpisodeFile.Size.ToString());
|
||||
history.Data.Add("IndexerFlags", message.EpisodeFile.IndexerFlags.ToString());
|
||||
history.Data.Add("ReleaseType", message.EpisodeFile.ReleaseType.ToString());
|
||||
|
||||
_historyRepository.Insert(history);
|
||||
}
|
||||
|
@ -315,6 +318,7 @@ namespace NzbDrone.Core.History
|
|||
history.Data.Add("ReleaseGroup", message.EpisodeFile.ReleaseGroup);
|
||||
history.Data.Add("Size", message.EpisodeFile.Size.ToString());
|
||||
history.Data.Add("IndexerFlags", message.EpisodeFile.IndexerFlags.ToString());
|
||||
history.Data.Add("ReleaseType", message.EpisodeFile.ReleaseType.ToString());
|
||||
|
||||
_historyRepository.Insert(history);
|
||||
}
|
||||
|
@ -343,6 +347,7 @@ namespace NzbDrone.Core.History
|
|||
history.Data.Add("Message", message.Message);
|
||||
history.Data.Add("ReleaseGroup", message.TrackedDownload?.RemoteEpisode?.ParsedEpisodeInfo?.ReleaseGroup);
|
||||
history.Data.Add("Size", message.TrackedDownload?.DownloadItem.TotalSize.ToString());
|
||||
history.Data.Add("ReleaseType", message.TrackedDownload?.RemoteEpisode?.ParsedEpisodeInfo?.ReleaseType.ToString());
|
||||
|
||||
historyToAdd.Add(history);
|
||||
}
|
||||
|
|
|
@ -1597,6 +1597,7 @@
|
|||
"ReleaseSceneIndicatorUnknownMessage": "Numbering varies for this episode and release does not match any known mappings.",
|
||||
"ReleaseSceneIndicatorUnknownSeries": "Unknown episode or series.",
|
||||
"ReleaseTitle": "Release Title",
|
||||
"ReleaseType": "Release Type",
|
||||
"Reload": "Reload",
|
||||
"RemotePath": "Remote Path",
|
||||
"RemotePathMappingBadDockerPathHealthCheckMessage": "You are using docker; download client {downloadClientName} places downloads in {path} but this is not a valid {osName} path. Review your remote path mappings and download client settings.",
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
public LazyLoaded<List<Episode>> Episodes { get; set; }
|
||||
public LazyLoaded<Series> Series { get; set; }
|
||||
public List<Language> Languages { get; set; }
|
||||
public ReleaseType ReleaseType { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
@ -97,6 +97,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
episodeFile.ReleaseGroup = localEpisode.ReleaseGroup;
|
||||
episodeFile.Languages = localEpisode.Languages;
|
||||
|
||||
// Prefer the release type from the download client, folder and finally the file so we have the most accurate information.
|
||||
episodeFile.ReleaseType = localEpisode.DownloadClientEpisodeInfo?.ReleaseType ??
|
||||
localEpisode.FolderEpisodeInfo?.ReleaseType ??
|
||||
localEpisode.FileEpisodeInfo.ReleaseType;
|
||||
|
||||
if (downloadClientItem?.DownloadId.IsNotNullOrWhiteSpace() == true)
|
||||
{
|
||||
var grabHistory = _historyService.FindByDownloadId(downloadClientItem.DownloadId)
|
||||
|
@ -107,12 +112,27 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
{
|
||||
episodeFile.IndexerFlags = flags;
|
||||
}
|
||||
|
||||
// Prefer the release type from the grabbed history
|
||||
if (Enum.TryParse(grabHistory?.Data.GetValueOrDefault("releaseType"), true, out ReleaseType releaseType))
|
||||
{
|
||||
episodeFile.ReleaseType = releaseType;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
episodeFile.IndexerFlags = localEpisode.IndexerFlags;
|
||||
}
|
||||
|
||||
// Fall back to parsed information if history is unavailable or missing
|
||||
if (episodeFile.ReleaseType == ReleaseType.Unknown)
|
||||
{
|
||||
// Prefer the release type from the download client, folder and finally the file so we have the most accurate information.
|
||||
episodeFile.ReleaseType = localEpisode.DownloadClientEpisodeInfo?.ReleaseType ??
|
||||
localEpisode.FolderEpisodeInfo?.ReleaseType ??
|
||||
localEpisode.FileEpisodeInfo.ReleaseType;
|
||||
}
|
||||
|
||||
bool copyOnly;
|
||||
switch (importMode)
|
||||
{
|
||||
|
|
|
@ -119,6 +119,10 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
|
||||
localEpisode.FileEpisodeInfo = fileEpisodeInfo;
|
||||
localEpisode.Size = _diskProvider.GetFileSize(localEpisode.Path);
|
||||
localEpisode.ReleaseType = localEpisode.DownloadClientEpisodeInfo?.ReleaseType ??
|
||||
localEpisode.FolderEpisodeInfo?.ReleaseType ??
|
||||
localEpisode.FileEpisodeInfo?.ReleaseType ??
|
||||
ReleaseType.Unknown;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
|
@ -17,6 +18,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||
public List<Language> Languages { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
public int IndexerFlags { get; set; }
|
||||
public ReleaseType ReleaseType { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
|
||||
public bool Equals(ManualImportFile other)
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Collections.Generic;
|
|||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
|
@ -25,6 +26,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||
public List<CustomFormat> CustomFormats { get; set; }
|
||||
public int CustomFormatScore { get; set; }
|
||||
public int IndexerFlags { get; set; }
|
||||
public ReleaseType ReleaseType { get; set; }
|
||||
public IEnumerable<Rejection> Rejections { get; set; }
|
||||
|
||||
public ManualImportItem()
|
||||
|
|
|
@ -425,6 +425,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||
item.Size = _diskProvider.GetFileSize(decision.LocalEpisode.Path);
|
||||
item.Rejections = decision.Rejections;
|
||||
item.IndexerFlags = (int)decision.LocalEpisode.IndexerFlags;
|
||||
item.ReleaseType = decision.LocalEpisode.ReleaseType;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
@ -444,6 +445,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||
item.Quality = episodeFile.Quality;
|
||||
item.Languages = episodeFile.Languages;
|
||||
item.IndexerFlags = (int)episodeFile.IndexerFlags;
|
||||
item.ReleaseType = episodeFile.ReleaseType;
|
||||
item.Size = _diskProvider.GetFileSize(item.Path);
|
||||
item.Rejections = Enumerable.Empty<Rejection>();
|
||||
item.EpisodeFileId = episodeFile.Id;
|
||||
|
@ -481,6 +483,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||
Quality = file.Quality,
|
||||
Languages = file.Languages,
|
||||
IndexerFlags = (IndexerFlags)file.IndexerFlags,
|
||||
ReleaseType = file.ReleaseType,
|
||||
Series = series,
|
||||
Size = 0
|
||||
};
|
||||
|
@ -510,6 +513,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||
localEpisode.Quality = file.Quality;
|
||||
localEpisode.Languages = file.Languages;
|
||||
localEpisode.IndexerFlags = (IndexerFlags)file.IndexerFlags;
|
||||
localEpisode.ReleaseType = file.ReleaseType;
|
||||
|
||||
// TODO: Cleanup non-tracked downloads
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace NzbDrone.Core.Parser.Model
|
|||
public QualityModel Quality { get; set; }
|
||||
public List<Language> Languages { get; set; }
|
||||
public IndexerFlags IndexerFlags { get; set; }
|
||||
public ReleaseType ReleaseType { get; set; }
|
||||
public MediaInfoModel MediaInfo { get; set; }
|
||||
public bool ExistingFile { get; set; }
|
||||
public bool SceneSource { get; set; }
|
||||
|
|
|
@ -90,6 +90,29 @@ namespace NzbDrone.Core.Parser.Model
|
|||
}
|
||||
}
|
||||
|
||||
public ReleaseType ReleaseType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (EpisodeNumbers.Length > 1 || AbsoluteEpisodeNumbers.Length > 1)
|
||||
{
|
||||
return Model.ReleaseType.MultiEpisode;
|
||||
}
|
||||
|
||||
if (EpisodeNumbers.Length == 1 || AbsoluteEpisodeNumbers.Length == 1)
|
||||
{
|
||||
return Model.ReleaseType.SingleEpisode;
|
||||
}
|
||||
|
||||
if (FullSeason)
|
||||
{
|
||||
return Model.ReleaseType.SeasonPack;
|
||||
}
|
||||
|
||||
return Model.ReleaseType.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var episodeString = "[Unknown Episode]";
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
using NzbDrone.Core.Annotations;
|
||||
|
||||
namespace NzbDrone.Core.Parser.Model
|
||||
{
|
||||
public enum ReleaseType
|
||||
{
|
||||
Unknown = 0,
|
||||
|
||||
[FieldOption(label: "Single Episode")]
|
||||
SingleEpisode = 1,
|
||||
|
||||
[FieldOption(label: "Multi-Episode")]
|
||||
MultiEpisode = 2,
|
||||
|
||||
[FieldOption(label: "Season Pack")]
|
||||
SeasonPack = 3
|
||||
}
|
||||
}
|
|
@ -209,6 +209,11 @@ namespace Sonarr.Api.V3.EpisodeFiles
|
|||
{
|
||||
episodeFile.IndexerFlags = (IndexerFlags)resourceEpisodeFile.IndexerFlags;
|
||||
}
|
||||
|
||||
if (resourceEpisodeFile.ReleaseType != null)
|
||||
{
|
||||
episodeFile.ReleaseType = (ReleaseType)resourceEpisodeFile.ReleaseType;
|
||||
}
|
||||
}
|
||||
|
||||
_mediaFileService.Update(episodeFiles);
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace Sonarr.Api.V3.EpisodeFiles
|
|||
public List<CustomFormatResource> CustomFormats { get; set; }
|
||||
public int CustomFormatScore { get; set; }
|
||||
public int? IndexerFlags { get; set; }
|
||||
public int? ReleaseType { get; set; }
|
||||
public MediaInfoResource MediaInfo { get; set; }
|
||||
|
||||
public bool QualityCutoffNotMet { get; set; }
|
||||
|
@ -33,34 +34,6 @@ namespace Sonarr.Api.V3.EpisodeFiles
|
|||
|
||||
public static class EpisodeFileResourceMapper
|
||||
{
|
||||
private static EpisodeFileResource ToResource(this EpisodeFile model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new EpisodeFileResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
SeriesId = model.SeriesId,
|
||||
SeasonNumber = model.SeasonNumber,
|
||||
RelativePath = model.RelativePath,
|
||||
|
||||
// Path
|
||||
Size = model.Size,
|
||||
DateAdded = model.DateAdded,
|
||||
SceneName = model.SceneName,
|
||||
ReleaseGroup = model.ReleaseGroup,
|
||||
Languages = model.Languages,
|
||||
Quality = model.Quality,
|
||||
MediaInfo = model.MediaInfo.ToResource(model.SceneName)
|
||||
|
||||
// QualityCutoffNotMet
|
||||
};
|
||||
}
|
||||
|
||||
public static EpisodeFileResource ToResource(this EpisodeFile model, NzbDrone.Core.Tv.Series series, IUpgradableSpecification upgradableSpecification, ICustomFormatCalculationService formatCalculationService)
|
||||
{
|
||||
if (model == null)
|
||||
|
@ -90,7 +63,8 @@ namespace Sonarr.Api.V3.EpisodeFiles
|
|||
QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(series.QualityProfile.Value, model.Quality),
|
||||
CustomFormats = customFormats.ToResource(false),
|
||||
CustomFormatScore = customFormatScore,
|
||||
IndexerFlags = (int)model.IndexerFlags
|
||||
IndexerFlags = (int)model.IndexerFlags,
|
||||
ReleaseType = (int)model.ReleaseType,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using NzbDrone.Common.Crypto;
|
|||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Manual;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Sonarr.Api.V3.CustomFormats;
|
||||
using Sonarr.Api.V3.Episodes;
|
||||
|
@ -31,6 +32,7 @@ namespace Sonarr.Api.V3.ManualImport
|
|||
public List<CustomFormatResource> CustomFormats { get; set; }
|
||||
public int CustomFormatScore { get; set; }
|
||||
public int IndexerFlags { get; set; }
|
||||
public ReleaseType ReleaseType { get; set; }
|
||||
public IEnumerable<Rejection> Rejections { get; set; }
|
||||
}
|
||||
|
||||
|
@ -67,6 +69,7 @@ namespace Sonarr.Api.V3.ManualImport
|
|||
// QualityWeight
|
||||
DownloadId = model.DownloadId,
|
||||
IndexerFlags = model.IndexerFlags,
|
||||
ReleaseType = model.ReleaseType,
|
||||
Rejections = model.Rejections
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue