parent
13701498ce
commit
df101258c5
@ -0,0 +1,129 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Test.CustomFormats;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Qualities
|
||||
{
|
||||
[TestFixture]
|
||||
public class CustomFormatsComparerFixture : CoreTest
|
||||
{
|
||||
private CustomFormat _customFormat1;
|
||||
private CustomFormat _customFormat2;
|
||||
private CustomFormat _customFormat3;
|
||||
private CustomFormat _customFormat4;
|
||||
|
||||
public CustomFormatsComparer Subject { get; set; }
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
}
|
||||
|
||||
private void GivenDefaultProfileWithFormats()
|
||||
{
|
||||
_customFormat1 = new CustomFormat("My Format 1", "L_ENGLISH") { Id = 1 };
|
||||
_customFormat2 = new CustomFormat("My Format 2", "L_FRENCH") { Id = 2 };
|
||||
_customFormat3 = new CustomFormat("My Format 3", "L_SPANISH") { Id = 3 };
|
||||
_customFormat4 = new CustomFormat("My Format 4", "L_ITALIAN") { Id = 4 };
|
||||
|
||||
CustomFormatsFixture.GivenCustomFormats(CustomFormat.None, _customFormat1, _customFormat2, _customFormat3, _customFormat4);
|
||||
|
||||
Subject = new CustomFormatsComparer(new Profile { Items = QualityFixture.GetDefaultQualities(), FormatItems = CustomFormatsFixture.GetSampleFormatItems() });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_lesser_when_first_format_is_worse()
|
||||
{
|
||||
GivenDefaultProfileWithFormats();
|
||||
|
||||
var first = new List<CustomFormat> { _customFormat1 };
|
||||
var second = new List<CustomFormat> { _customFormat2 };
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
compare.Should().BeLessThan(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_zero_when_formats_are_equal()
|
||||
{
|
||||
GivenDefaultProfileWithFormats();
|
||||
|
||||
var first = new List<CustomFormat> { _customFormat2 };
|
||||
var second = new List<CustomFormat> { _customFormat2 };
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
compare.Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_greater_when_first_format_is_better()
|
||||
{
|
||||
GivenDefaultProfileWithFormats();
|
||||
|
||||
var first = new List<CustomFormat> { _customFormat3 };
|
||||
var second = new List<CustomFormat> { _customFormat2 };
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
compare.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_greater_when_multiple_formats_better()
|
||||
{
|
||||
GivenDefaultProfileWithFormats();
|
||||
|
||||
var first = new List<CustomFormat> { _customFormat3, _customFormat4 };
|
||||
var second = new List<CustomFormat> { _customFormat2 };
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
compare.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_greater_when_best_format_is_better()
|
||||
{
|
||||
GivenDefaultProfileWithFormats();
|
||||
|
||||
var first = new List<CustomFormat> { _customFormat1, _customFormat3 };
|
||||
var second = new List<CustomFormat> { _customFormat2 };
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
compare.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_greater_when_best_format_equal_but_more_lower_formats()
|
||||
{
|
||||
GivenDefaultProfileWithFormats();
|
||||
|
||||
var first = new List<CustomFormat> { _customFormat1, _customFormat2 };
|
||||
var second = new List<CustomFormat> { _customFormat2 };
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
compare.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_be_greater_when_best_format_worse_but_more_lower_formats()
|
||||
{
|
||||
GivenDefaultProfileWithFormats();
|
||||
|
||||
var first = new List<CustomFormat> { _customFormat1, _customFormat2, _customFormat3 };
|
||||
var second = new List<CustomFormat> { _customFormat4 };
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
compare.Should().BeLessThan(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dapper;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Migration;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Migration
|
||||
{
|
||||
[TestFixture]
|
||||
public class remove_custom_formats_from_quality_modelFixture : MigrationTest<remove_custom_formats_from_quality_model>
|
||||
{
|
||||
[Test]
|
||||
public void should_remove_custom_format_from_pending_releases()
|
||||
{
|
||||
var db = WithDapperMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("PendingReleases").Row(new
|
||||
{
|
||||
MovieId = 1,
|
||||
Title = "Test Movie",
|
||||
Added = DateTime.UtcNow,
|
||||
ParsedMovieInfo = @"{
|
||||
""movieTitle"": ""Skyfall"",
|
||||
""simpleReleaseTitle"": ""A Movie (2012) \u002B Extras (1080p BluRay x265 HEVC 10bit DTS 5.1 SAMPA) [QxR]"",
|
||||
""quality"": {
|
||||
""quality"": {
|
||||
""id"": 7,
|
||||
""name"": ""Bluray-1080p"",
|
||||
""source"": ""bluray"",
|
||||
""resolution"": 1080,
|
||||
""modifier"": ""none""
|
||||
},
|
||||
""customFormats"": [
|
||||
{
|
||||
""name"": ""Standard High Def Surround Sound Movie"",
|
||||
""formatTags"": [
|
||||
{
|
||||
""raw"": ""R_1080"",
|
||||
""tagType"": ""resolution"",
|
||||
""tagModifier"": 0,
|
||||
""value"": ""r1080p""
|
||||
},
|
||||
{
|
||||
""raw"": ""L_English"",
|
||||
""tagType"": ""language"",
|
||||
""tagModifier"": 0,
|
||||
""value"": {
|
||||
""id"": 1,
|
||||
""name"": ""English""
|
||||
}
|
||||
},
|
||||
{
|
||||
""raw"": ""C_DTS"",
|
||||
""tagType"": ""custom"",
|
||||
""tagModifier"": 0,
|
||||
""value"": ""dts""
|
||||
}
|
||||
],
|
||||
""id"": 1
|
||||
}
|
||||
],
|
||||
""revision"": {
|
||||
""version"": 1,
|
||||
""real"": 0,
|
||||
""isRepack"": false
|
||||
},
|
||||
""hardcodedSubs"": null,
|
||||
""qualityDetectionSource"": ""name""
|
||||
},
|
||||
""releaseGroup"": ""QxR"",
|
||||
""releaseHash"": """",
|
||||
""edition"": """",
|
||||
""year"": 2012,
|
||||
""imdbId"": """"
|
||||
}",
|
||||
Release = "{}",
|
||||
Reason = PendingReleaseReason.Delay
|
||||
});
|
||||
});
|
||||
|
||||
var json = db.Query<string>("SELECT ParsedMovieInfo FROM PendingReleases").First();
|
||||
json.Should().NotContain("customFormats");
|
||||
|
||||
var pending = db.Query<ParsedMovieInfo>("SELECT ParsedMovieInfo FROM PendingReleases").First();
|
||||
pending.Quality.Quality.Should().Be(Quality.Bluray1080p);
|
||||
pending.Languages.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_fix_quality_for_pending_releases()
|
||||
{
|
||||
var db = WithDapperMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("PendingReleases").Row(new
|
||||
{
|
||||
MovieId = 1,
|
||||
Title = "Test Movie",
|
||||
Added = DateTime.UtcNow,
|
||||
ParsedMovieInfo = @"{
|
||||
""languages"": [
|
||||
""english""
|
||||
],
|
||||
""movieTitle"": ""Joy"",
|
||||
""simpleReleaseTitle"": ""A Movie.2015.1080p.BluRay.AVC.DTS-HD.MA.5.1-RARBG [f"",
|
||||
""quality"": {
|
||||
""quality"": {
|
||||
""id"": 7,
|
||||
""name"": ""Bluray-1080p"",
|
||||
""source"": ""bluray"",
|
||||
""resolution"": ""r1080P"",
|
||||
""modifier"": ""none""
|
||||
},
|
||||
""customFormats"": [],
|
||||
""revision"": {
|
||||
""version"": 1,
|
||||
""real"": 0
|
||||
}
|
||||
},
|
||||
""releaseGroup"": ""RARBG"",
|
||||
""edition"": """",
|
||||
""year"": 2015,
|
||||
""imdbId"": """"
|
||||
}",
|
||||
Release = "{}",
|
||||
Reason = PendingReleaseReason.Delay
|
||||
});
|
||||
});
|
||||
|
||||
var json = db.Query<string>("SELECT ParsedMovieInfo FROM PendingReleases").First();
|
||||
json.Should().NotContain("customFormats");
|
||||
json.Should().NotContain("resolution");
|
||||
|
||||
var pending = db.Query<ParsedMovieInfo>("SELECT ParsedMovieInfo FROM PendingReleases").First();
|
||||
pending.Quality.Quality.Should().Be(Quality.Bluray1080p);
|
||||
pending.Languages.Should().BeEquivalentTo(new List<Language> { Language.English });
|
||||
}
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Commands;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles
|
||||
{
|
||||
[TestFixture]
|
||||
public class UpdateMovieFileQualityServiceFixture : CoreTest<UpdateMovieFileQualityService>
|
||||
{
|
||||
private MovieFile _movieFile;
|
||||
private QualityModel _oldQuality;
|
||||
private QualityModel _newQuality;
|
||||
|
||||
private ParsedMovieInfo _newInfo;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_movieFile = Builder<MovieFile>.CreateNew().With(m => m.MovieId = 0).Build();
|
||||
|
||||
_oldQuality = new QualityModel(Quality.Bluray720p);
|
||||
|
||||
_movieFile.Quality = _oldQuality;
|
||||
|
||||
_newQuality = _oldQuality.JsonClone();
|
||||
var format = new CustomFormat("Awesome Format");
|
||||
format.Id = 1;
|
||||
_newQuality.CustomFormats = new List<CustomFormat> { format };
|
||||
|
||||
_newInfo = new ParsedMovieInfo
|
||||
{
|
||||
Quality = _newQuality
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileService>().Setup(s => s.GetMovies(It.IsAny<IEnumerable<int>>()))
|
||||
.Returns(new List<MovieFile> { _movieFile });
|
||||
|
||||
Mocker.GetMock<IHistoryService>().Setup(s => s.GetByMovieId(It.IsAny<int>(), null))
|
||||
.Returns(new List<History.History>());
|
||||
}
|
||||
|
||||
private void ExecuteCommand()
|
||||
{
|
||||
Subject.Execute(new UpdateMovieFileQualityCommand(new List<int> { 0 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_if_unable_to_parse()
|
||||
{
|
||||
ExecuteCommand();
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
|
||||
Mocker.GetMock<IMediaFileService>().Verify(s => s.Update(It.IsAny<MovieFile>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_with_new_formats()
|
||||
{
|
||||
Mocker.GetMock<IParsingService>().Setup(s => s.ParseMovieInfo(It.IsAny<string>(), It.IsAny<List<object>>()))
|
||||
.Returns(_newInfo);
|
||||
|
||||
ExecuteCommand();
|
||||
|
||||
Mocker.GetMock<IMediaFileService>().Verify(s => s.Update(It.Is<MovieFile>(f => f.Quality.CustomFormats == _newQuality.CustomFormats)), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_imported_history_title()
|
||||
{
|
||||
var imported = Builder<History.History>.CreateNew()
|
||||
.With(h => h.EventType = HistoryEventType.DownloadFolderImported)
|
||||
.With(h => h.SourceTitle = "My Movie 2018.mkv").Build();
|
||||
|
||||
Mocker.GetMock<IHistoryService>().Setup(s => s.GetByMovieId(It.IsAny<int>(), null))
|
||||
.Returns(new List<History.History> { imported });
|
||||
|
||||
Mocker.GetMock<IParsingService>().Setup(s => s.ParseMovieInfo("My Movie 2018.mkv", It.IsAny<List<object>>()))
|
||||
.Returns(_newInfo);
|
||||
|
||||
ExecuteCommand();
|
||||
|
||||
Mocker.GetMock<IParsingService>().Verify(s => s.ParseMovieInfo("My Movie 2018.mkv", It.IsAny<List<object>>()));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Blacklisting;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.CustomFormats
|
||||
{
|
||||
public interface ICustomFormatCalculationService
|
||||
{
|
||||
List<CustomFormat> ParseCustomFormat(ParsedMovieInfo movieInfo);
|
||||
List<CustomFormat> ParseCustomFormat(MovieFile movieFile);
|
||||
List<CustomFormat> ParseCustomFormat(Blacklist blacklist);
|
||||
List<CustomFormat> ParseCustomFormat(History.History history);
|
||||
List<CustomFormatMatchResult> MatchFormatTags(ParsedMovieInfo movieInfo);
|
||||
}
|
||||
|
||||
public class CustomFormatCalculationService : ICustomFormatCalculationService
|
||||
{
|
||||
private readonly ICustomFormatService _formatService;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly IMovieService _movieService;
|
||||
|
||||
public CustomFormatCalculationService(ICustomFormatService formatService,
|
||||
IParsingService parsingService,
|
||||
IMovieService movieService)
|
||||
{
|
||||
_formatService = formatService;
|
||||
_parsingService = parsingService;
|
||||
_movieService = movieService;
|
||||
}
|
||||
|
||||
public List<CustomFormat> ParseCustomFormat(ParsedMovieInfo movieInfo)
|
||||
{
|
||||
return MatchFormatTags(movieInfo)
|
||||
.Where(m => m.GoodMatch)
|
||||
.Select(r => r.CustomFormat)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public List<CustomFormat> ParseCustomFormat(MovieFile movieFile)
|
||||
{
|
||||
return MatchFormatTags(movieFile)
|
||||
.Where(m => m.GoodMatch)
|
||||
.Select(r => r.CustomFormat)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public List<CustomFormat> ParseCustomFormat(Blacklist blacklist)
|
||||
{
|
||||
return MatchFormatTags(blacklist)
|
||||
.Where(m => m.GoodMatch)
|
||||
.Select(r => r.CustomFormat)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public List<CustomFormat> ParseCustomFormat(History.History history)
|
||||
{
|
||||
return MatchFormatTags(history)
|
||||
.Where(m => m.GoodMatch)
|
||||
.Select(r => r.CustomFormat)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public List<CustomFormatMatchResult> MatchFormatTags(ParsedMovieInfo movieInfo)
|
||||
{
|
||||
var formats = _formatService.All();
|
||||
|
||||
var matches = new List<CustomFormatMatchResult>();
|
||||
|
||||
foreach (var customFormat in formats)
|
||||
{
|
||||
var tagTypeMatches = customFormat.FormatTags
|
||||
.GroupBy(t => t.TagType)
|
||||
.Select(g => new FormatTagMatchesGroup
|
||||
{
|
||||
Type = g.Key,
|
||||
Matches = g.ToDictionary(t => t, t => t.DoesItMatch(movieInfo))
|
||||
})
|
||||
.ToList();
|
||||
|
||||
matches.Add(new CustomFormatMatchResult
|
||||
{
|
||||
CustomFormat = customFormat,
|
||||
GroupMatches = tagTypeMatches
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
private List<CustomFormatMatchResult> MatchFormatTags(MovieFile file)
|
||||
{
|
||||
var info = new ParsedMovieInfo
|
||||
{
|
||||
MovieTitle = file.Movie.Title,
|
||||
SimpleReleaseTitle = file.GetSceneOrFileName().SimplifyReleaseTitle(),
|
||||
Quality = file.Quality,
|
||||
Languages = file.Languages,
|
||||
ReleaseGroup = file.ReleaseGroup,
|
||||
Edition = file.Edition,
|
||||
Year = file.Movie.Year,
|
||||
ImdbId = file.Movie.ImdbId,
|
||||
ExtraInfo = new Dictionary<string, object>
|
||||
{
|
||||
{ "IndexerFlags", file.IndexerFlags },
|
||||
{ "Size", file.Size },
|
||||
{ "Filename", System.IO.Path.GetFileName(file.RelativePath) }
|
||||
}
|
||||
};
|
||||
|
||||
return MatchFormatTags(info);
|
||||
}
|
||||
|
||||
private List<CustomFormatMatchResult> MatchFormatTags(Blacklist blacklist)
|
||||
{
|
||||
var parsed = _parsingService.ParseMovieInfo(blacklist.SourceTitle, null);
|
||||
|
||||
var info = new ParsedMovieInfo
|
||||
{
|
||||
MovieTitle = blacklist.Movie.Title,
|
||||
SimpleReleaseTitle = parsed?.SimpleReleaseTitle ?? blacklist.SourceTitle.SimplifyReleaseTitle(),
|
||||
Quality = blacklist.Quality,
|
||||
Languages = blacklist.Languages,
|
||||
ReleaseGroup = parsed?.ReleaseGroup,
|
||||
Edition = parsed?.Edition,
|
||||
Year = blacklist.Movie.Year,
|
||||
ImdbId = blacklist.Movie.ImdbId,
|
||||
ExtraInfo = new Dictionary<string, object>
|
||||
{
|
||||
{ "IndexerFlags", blacklist.IndexerFlags },
|
||||
{ "Size", blacklist.Size }
|
||||
}
|
||||
};
|
||||
|
||||
return MatchFormatTags(info);
|
||||
}
|
||||
|
||||
private List<CustomFormatMatchResult> MatchFormatTags(History.History history)
|
||||
{
|
||||
var movie = _movieService.GetMovie(history.MovieId);
|
||||
var parsed = _parsingService.ParseMovieInfo(history.SourceTitle, null);
|
||||
|
||||
Enum.TryParse(history.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags);
|
||||
int.TryParse(history.Data.GetValueOrDefault("size"), out var size);
|
||||
|
||||
var info = new ParsedMovieInfo
|
||||
{
|
||||
MovieTitle = movie.Title,
|
||||
SimpleReleaseTitle = parsed?.SimpleReleaseTitle ?? history.SourceTitle.SimplifyReleaseTitle(),
|
||||
Quality = history.Quality,
|
||||
Languages = history.Languages,
|
||||
ReleaseGroup = parsed?.ReleaseGroup,
|
||||
Edition = parsed?.Edition,
|
||||
Year = movie.Year,
|
||||
ImdbId = movie.ImdbId,
|
||||
ExtraInfo = new Dictionary<string, object>
|
||||
{
|
||||
{ "IndexerFlags", flags },
|
||||
{ "Size", size }
|
||||
}
|
||||
};
|
||||
|
||||
return MatchFormatTags(info);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.CustomFormats
|
||||
{
|
||||
public class CustomFormatDefinition : ModelBase
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<FormatTag> FormatTags { get; set; }
|
||||
|
||||
public static implicit operator CustomFormat(CustomFormatDefinition def) => new CustomFormat { Id = def.Id, Name = def.Name, FormatTags = def.FormatTags };
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Core.Profiles;
|
||||
|
||||
namespace NzbDrone.Core.CustomFormats
|
||||
{
|
||||
public class CustomFormatsComparer : IComparer<List<CustomFormat>>
|
||||
{
|
||||
private readonly Profile _profile;
|
||||
|
||||
public CustomFormatsComparer(Profile profile)
|
||||
{
|
||||
Ensure.That(profile, () => profile).IsNotNull();
|
||||
Ensure.That(profile.Items, () => profile.Items).HasItems();
|
||||
|
||||
_profile = profile;
|
||||
}
|
||||
|
||||
public int Compare(List<CustomFormat> left, List<CustomFormat> right)
|
||||
{
|
||||
var leftIndicies = _profile.GetIndices(left);
|
||||
var rightIndicies = _profile.GetIndices(right);
|
||||
|
||||
// Summing powers of two ensures last format always trumps, but we order correctly if we
|
||||
// have extra formats lower down the list
|
||||
var leftTotal = leftIndicies.Select(x => Math.Pow(2, x)).Sum();
|
||||
var rightTotal = rightIndicies.Select(x => Math.Pow(2, x)).Sum();
|
||||
|
||||
return leftTotal.CompareTo(rightTotal);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Core.CustomFormats
|
||||
{
|
||||
public class FormatTagMatchesGroup
|
||||
{
|
||||
public TagType Type { get; set; }
|
||||
|
||||
public Dictionary<FormatTag, bool> Matches { get; set; }
|
||||
|
||||
public bool DidMatch => !(Matches.Any(m => m.Key.TagModifier.HasFlag(TagModifier.AbsolutelyRequired) && m.Value == false) ||
|
||||
Matches.All(m => m.Value == false));
|
||||
}
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using Dapper;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(165)]
|
||||
public class remove_custom_formats_from_quality_model : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("Blacklist").AddColumn("IndexerFlags").AsInt32().WithDefaultValue(0);
|
||||
Alter.Table("MovieFiles").AddColumn("IndexerFlags").AsInt32().WithDefaultValue(0);
|
||||
|
||||
// Switch Quality and Language to int in pending releases, remove custom formats
|
||||
Execute.WithConnection(FixPendingReleases);
|
||||
|
||||
// Remove Custom Formats from QualityModel
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<QualityModel165>());
|
||||
Execute.WithConnection((conn, tran) => RemoveCustomFormatFromQuality(conn, tran, "Blacklist"));
|
||||
Execute.WithConnection((conn, tran) => RemoveCustomFormatFromQuality(conn, tran, "History"));
|
||||
Execute.WithConnection((conn, tran) => RemoveCustomFormatFromQuality(conn, tran, "MovieFiles"));
|
||||
|
||||
// Fish out indexer flags from history
|
||||
Execute.WithConnection(AddIndexerFlagsToBlacklist);
|
||||
Execute.WithConnection(AddIndexerFlagsToMovieFiles);
|
||||
}
|
||||
|
||||
private void FixPendingReleases(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<ParsedMovieInfo164>());
|
||||
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<ParsedMovieInfo165>());
|
||||
var rows = conn.Query<ParsedMovieInfoData164>("SELECT Id, ParsedMovieInfo from PendingReleases");
|
||||
|
||||
var newRows = new List<ParsedMovieInfoData165>();
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var old = row.ParsedMovieInfo;
|
||||
|
||||
var newQuality = new QualityModel165
|
||||
{
|
||||
Quality = old.Quality.Quality.Id,
|
||||
Revision = old.Quality.Revision,
|
||||
HardcodedSubs = old.Quality.HardcodedSubs
|
||||
};
|
||||
|
||||
var languages = old.Languages?.Select(x => (Language)x).Select(x => x.Id).ToList();
|
||||
|
||||
var correct = new ParsedMovieInfo165
|
||||
{
|
||||
MovieTitle = old.MovieTitle,
|
||||
SimpleReleaseTitle = old.SimpleReleaseTitle,
|
||||
Quality = newQuality,
|
||||
Languages = languages,
|
||||
ReleaseGroup = old.ReleaseGroup,
|
||||
ReleaseHash = old.ReleaseHash,
|
||||
Edition = old.Edition,
|
||||
Year = old.Year,
|
||||
ImdbId = old.ImdbId
|
||||
};
|
||||
|
||||
newRows.Add(new ParsedMovieInfoData165
|
||||
{
|
||||
Id = row.Id,
|
||||
ParsedMovieInfo = correct
|
||||
});
|
||||
}
|
||||
|
||||
var sql = $"UPDATE PendingReleases SET ParsedMovieInfo = @ParsedMovieInfo WHERE Id = @Id";
|
||||
|
||||
conn.Execute(sql, newRows, transaction: tran);
|
||||
}
|
||||
|
||||
private void RemoveCustomFormatFromQuality(IDbConnection conn, IDbTransaction tran, string table)
|
||||
{
|
||||
var rows = conn.Query<QualityRow>($"SELECT Id, Quality from {table}");
|
||||
|
||||
var sql = $"UPDATE {table} SET Quality = @Quality WHERE Id = @Id";
|
||||
|
||||
conn.Execute(sql, rows, transaction: tran);
|
||||
}
|
||||
|
||||
private void AddIndexerFlagsToBlacklist(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
var blacklists = conn.Query<BlacklistData>("SELECT Blacklist.Id, Blacklist.TorrentInfoHash, History.Data " +
|
||||
"FROM Blacklist " +
|
||||
"JOIN History ON Blacklist.MovieId = History.MovieId " +
|
||||
"WHERE History.EventType = 1");
|
||||
|
||||
var toUpdate = new List<IndexerFlagsItem>();
|
||||
|
||||
foreach (var item in blacklists)
|
||||
{
|
||||
var dict = Json.Deserialize<Dictionary<string, string>>(item.Data);
|
||||
|
||||
if (dict.GetValueOrDefault("torrentInfoHash") == item.TorrentInfoHash &&
|
||||
Enum.TryParse(dict.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags))
|
||||
{
|
||||
if (flags != 0)
|
||||
{
|
||||
toUpdate.Add(new IndexerFlagsItem
|
||||
{
|
||||
Id = item.Id,
|
||||
IndexerFlags = (int)flags
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var updateSql = "UPDATE Blacklist SET IndexerFlags = @IndexerFlags WHERE Id = @Id";
|
||||
conn.Execute(updateSql, toUpdate, transaction: tran);
|
||||
}
|
||||
|
||||
private void AddIndexerFlagsToMovieFiles(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
var movieFiles = conn.Query<MovieFileData>("SELECT MovieFiles.Id, MovieFiles.SceneName, History.SourceTitle, History.Data " +
|
||||
"FROM MovieFiles " +
|
||||
"JOIN History ON MovieFiles.MovieId = History.MovieId " +
|
||||
"WHERE History.EventType = 1");
|
||||
|
||||
var toUpdate = new List<IndexerFlagsItem>();
|
||||
|
||||
foreach (var item in movieFiles)
|
||||
{
|
||||
var dict = Json.Deserialize<Dictionary<string, string>>(item.Data);
|
||||
|
||||
if (item.SourceTitle == item.SceneName &&
|
||||
Enum.TryParse(dict.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags))
|
||||
{
|
||||
if (flags != 0)
|
||||
{
|
||||
toUpdate.Add(new IndexerFlagsItem
|
||||
{
|
||||
Id = item.Id,
|
||||
IndexerFlags = (int)flags
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var updateSql = "UPDATE MovieFiles SET IndexerFlags = @IndexerFlags WHERE Id = @Id";
|
||||
conn.Execute(updateSql, toUpdate, transaction: tran);
|
||||
}
|
||||
|
||||
private class ParsedMovieInfoData164 : ModelBase
|
||||
{
|
||||
public ParsedMovieInfo164 ParsedMovieInfo { get; set; }
|
||||
}
|
||||
|
||||
private class ParsedMovieInfo164
|
||||
{
|
||||
public string MovieTitle { get; set; }
|
||||
public string SimpleReleaseTitle { get; set; }
|
||||
public QualityModel164 Quality { get; set; }
|
||||
public List<string> Languages { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
public string ReleaseHash { get; set; }
|
||||
public string Edition { get; set; }
|
||||
public int Year { get; set; }
|
||||
public string ImdbId { get; set; }
|
||||
}
|
||||
|
||||
private class QualityModel164
|
||||
{
|
||||
public Quality164 Quality { get; set; }
|
||||
public Revision165 Revision { get; set; }
|
||||
public string HardcodedSubs { get; set; }
|
||||
}
|
||||
|
||||
private class Quality164
|
||||
{
|
||||
public int Id { get; set; }
|
||||
}
|
||||
|
||||
private class ParsedMovieInfoData165 : ModelBase
|
||||
{
|
||||
public ParsedMovieInfo165 ParsedMovieInfo { get; set; }
|
||||
}
|
||||
|
||||
private class ParsedMovieInfo165
|
||||
{
|
||||
public string MovieTitle { get; set; }
|
||||
public string SimpleReleaseTitle { get; set; }
|
||||
public QualityModel165 Quality { get; set; }
|
||||
public List<int> Languages { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
public string ReleaseHash { get; set; }
|
||||
public string Edition { get; set; }
|
||||
public int Year { get; set; }
|
||||
public string ImdbId { get; set; }
|
||||
}
|
||||
|
||||
private class BlacklistData : ModelBase
|
||||
{
|
||||
public string TorrentInfoHash { get; set; }
|
||||
public string Data { get; set; }
|
||||
}
|
||||
|
||||
private class MovieFileData : ModelBase
|
||||
{
|
||||
public string SceneName { get; set; }
|
||||
public string SourceTitle { get; set; }
|
||||
public string Data { get; set; }
|
||||
}
|
||||
|
||||
private class IndexerFlagsItem : ModelBase
|
||||
{
|
||||
public int IndexerFlags { get; set; }
|
||||
}
|
||||
|
||||
private class QualityRow : ModelBase
|
||||
{
|
||||
public QualityModel165 Quality { get; set; }
|
||||
}
|
||||
|
||||
private class QualityModel165
|
||||
{
|
||||
public int Quality { get; set; }
|
||||
public Revision165 Revision { get; set; }
|
||||
public string HardcodedSubs { get; set; }
|
||||
}
|
||||
|
||||
private class Revision165
|
||||
{
|
||||
public int Version { get; set; }
|
||||
public int Real { get; set; }
|
||||
public bool IsRepack { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.MediaFiles.Commands;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public interface IUpdateMovieFileQualityService
|
||||
{
|
||||
}
|
||||
|
||||
public class UpdateMovieFileQualityService : IUpdateMovieFileQualityService, IExecute<UpdateMovieFileQualityCommand>
|
||||
{
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IHistoryService _historyService;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public UpdateMovieFileQualityService(IMediaFileService mediaFileService,
|
||||
IHistoryService historyService,
|
||||
IParsingService parsingService,
|
||||
IEventAggregator eventAggregator,
|
||||
Logger logger)
|
||||
{
|
||||
_mediaFileService = mediaFileService;
|
||||
_historyService = historyService;
|
||||
_parsingService = parsingService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
//TODO add some good tests for this!
|
||||
public void Execute(UpdateMovieFileQualityCommand command)
|
||||
{
|
||||
var movieFiles = _mediaFileService.GetMovies(command.MovieFileIds);
|
||||
|
||||
var count = 1;
|
||||
|
||||
foreach (var movieFile in movieFiles)
|
||||
{
|
||||
_logger.ProgressInfo("Updating quality for {0}/{1} files.", count, movieFiles.Count);
|
||||
|
||||
var history = _historyService.GetByMovieId(movieFile.MovieId, null).OrderByDescending(h => h.Date);
|
||||
var latestImported = history.FirstOrDefault(h => h.EventType == HistoryEventType.DownloadFolderImported);
|
||||
var latestImportedName = latestImported?.SourceTitle;
|
||||
var latestGrabbed = history.FirstOrDefault(h => h.EventType == HistoryEventType.Grabbed);
|
||||
var sizeMovie = new LocalMovie();
|
||||
sizeMovie.Size = movieFile.Size;
|
||||
|
||||
var helpers = new List<object> { sizeMovie };
|
||||
|
||||
if (movieFile.MediaInfo != null)
|
||||
{
|
||||
helpers.Add(movieFile.MediaInfo);
|
||||
}
|
||||
|
||||
if (latestGrabbed != null)
|
||||
{
|
||||
helpers.Add(latestGrabbed);
|
||||
}
|
||||
|
||||
ParsedMovieInfo parsedMovieInfo = null;
|
||||
|
||||
if (latestImportedName?.IsNotNullOrWhiteSpace() == true)
|
||||
{
|
||||
parsedMovieInfo = _parsingService.ParseMovieInfo(latestImportedName, helpers);
|
||||
}
|
||||
|
||||
if (parsedMovieInfo == null)
|
||||
{
|
||||
_logger.Debug("Could not parse movie info from history source title, using current path instead: {0}.", movieFile.RelativePath);
|
||||
parsedMovieInfo = _parsingService.ParseMovieInfo(movieFile.RelativePath, helpers);
|
||||
}
|
||||
|
||||
//Only update Custom formats for now.
|
||||
if (parsedMovieInfo != null)
|
||||
{
|
||||
movieFile.Quality.CustomFormats = parsedMovieInfo.Quality.CustomFormats;
|
||||
_mediaFileService.Update(movieFile);
|
||||
_eventAggregator.PublishEvent(new MovieFileUpdatedEvent(movieFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warn("Could not update custom formats for {0}, since it's title could not be parsed!", movieFile);
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public enum Modifier
|
||||
{
|
||||
NONE = 0,
|
||||
REGIONAL,
|
||||
SCREENER,
|
||||
RAWHD,
|
||||
BRDISK,
|
||||
REMUX
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public enum Source
|
||||
{
|
||||
UNKNOWN = 0,
|
||||
CAM,
|
||||
TELESYNC,
|
||||
TELECINE,
|
||||
WORKPRINT,
|
||||
DVD,
|
||||
TV,
|
||||
WEBDL,
|
||||
WEBRIP,
|
||||
BLURAY
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue