mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-04 10:02:40 +01:00
Fixed: When refreshing info about a movie, the alt titles should now correctly be deleted / updated, even from TMDB. (#3603)
* Fixed: When refreshing info about a movie, the alt titles should now correctly be deleted / updated, even from TMDB. Fixes #3542 * Fixed: Small things fixup.
This commit is contained in:
parent
bd374825f1
commit
be3152e630
@ -0,0 +1,32 @@
|
|||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.MovieTests.AlternativeTitleServiceTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class AlternativeTitleFixture : CoreTest
|
||||||
|
{
|
||||||
|
private AlternativeTitle CreateFakeTitle(SourceType source, int votes)
|
||||||
|
{
|
||||||
|
return Builder<AlternativeTitle>.CreateNew().With(t => t.SourceType = source).With(t => t.Votes = votes)
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(SourceType.TMDB, -1, true)]
|
||||||
|
[TestCase(SourceType.TMDB, 1000, true)]
|
||||||
|
[TestCase(SourceType.Mappings, 0, false)]
|
||||||
|
[TestCase(SourceType.Mappings, 4, true)]
|
||||||
|
[TestCase(SourceType.Mappings, -1, false)]
|
||||||
|
[TestCase(SourceType.Indexer, 0, true)]
|
||||||
|
[TestCase(SourceType.User, 0, true)]
|
||||||
|
public void should_be_trusted(SourceType source, int votes, bool trusted)
|
||||||
|
{
|
||||||
|
var fakeTitle = CreateFakeTitle(source, votes);
|
||||||
|
|
||||||
|
fakeTitle.IsTrusted().Should().Be(trusted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Movies;
|
||||||
|
using NzbDrone.Core.Movies.AlternativeTitles;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.MovieTests.AlternativeTitleServiceTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class AlternativeTitleServiceFixture : CoreTest<AlternativeTitleService>
|
||||||
|
{
|
||||||
|
private AlternativeTitle _title1;
|
||||||
|
private AlternativeTitle _title2;
|
||||||
|
private AlternativeTitle _title3;
|
||||||
|
|
||||||
|
private Movie _movie;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
var titles = Builder<AlternativeTitle>.CreateListOfSize(3).All().With(t => t.MovieId = 0).Build();
|
||||||
|
_title1 = titles[0];
|
||||||
|
_title2 = titles[1];
|
||||||
|
_title3 = titles[2];
|
||||||
|
_movie = Builder<Movie>.CreateNew().With(m => m.CleanTitle = "myothertitle").With(m => m.Id = 1).Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenExistingTitles(params AlternativeTitle[] titles)
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IAlternativeTitleRepository>().Setup(r => r.FindByMovieId(_movie.Id))
|
||||||
|
.Returns(titles.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_update_insert_remove_titles()
|
||||||
|
{
|
||||||
|
var titles = new List<AlternativeTitle> {_title2, _title3};
|
||||||
|
var updates = new List<AlternativeTitle> {_title2};
|
||||||
|
var deletes = new List<AlternativeTitle> {_title1};
|
||||||
|
var inserts = new List<AlternativeTitle> {_title3};
|
||||||
|
GivenExistingTitles(_title1, _title2);
|
||||||
|
|
||||||
|
Subject.UpdateTitles(titles, _movie);
|
||||||
|
|
||||||
|
Mocker.GetMock<IAlternativeTitleRepository>().Verify(r => r.InsertMany(inserts), Times.Once());
|
||||||
|
Mocker.GetMock<IAlternativeTitleRepository>().Verify(r => r.UpdateMany(updates), Times.Once());
|
||||||
|
Mocker.GetMock<IAlternativeTitleRepository>().Verify(r => r.DeleteMany(deletes), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_insert_duplicates()
|
||||||
|
{
|
||||||
|
GivenExistingTitles();
|
||||||
|
var titles = new List<AlternativeTitle> {_title1, _title1};
|
||||||
|
var inserts = new List<AlternativeTitle>{ _title1 };
|
||||||
|
|
||||||
|
Subject.UpdateTitles(titles, _movie);
|
||||||
|
|
||||||
|
Mocker.GetMock<IAlternativeTitleRepository>().Verify(r => r.InsertMany(inserts), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_insert_main_title()
|
||||||
|
{
|
||||||
|
GivenExistingTitles();
|
||||||
|
var titles = new List<AlternativeTitle>{_title1};
|
||||||
|
var movie = Builder<Movie>.CreateNew().With(m => m.CleanTitle = _title1.CleanTitle).Build();
|
||||||
|
|
||||||
|
Subject.UpdateTitles(titles, movie);
|
||||||
|
|
||||||
|
Mocker.GetMock<IAlternativeTitleRepository>().Verify(r => r.InsertMany(new List<AlternativeTitle>()), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_update_movie_id()
|
||||||
|
{
|
||||||
|
GivenExistingTitles();
|
||||||
|
var titles = new List<AlternativeTitle> {_title1, _title2};
|
||||||
|
|
||||||
|
Subject.UpdateTitles(titles, _movie);
|
||||||
|
|
||||||
|
_title1.MovieId.Should().Be(_movie.Id);
|
||||||
|
_title2.MovieId.Should().Be(_movie.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_update_with_correct_id()
|
||||||
|
{
|
||||||
|
var existingTitle = Builder<AlternativeTitle>.CreateNew().With(t => t.Id = 2).Build();
|
||||||
|
GivenExistingTitles(existingTitle);
|
||||||
|
var updateTitle = existingTitle.JsonClone();
|
||||||
|
updateTitle.Id = 0;
|
||||||
|
|
||||||
|
Subject.UpdateTitles(new List<AlternativeTitle> {updateTitle}, _movie);
|
||||||
|
|
||||||
|
Mocker.GetMock<IAlternativeTitleRepository>().Verify(r => r.UpdateMany(It.Is<IList<AlternativeTitle>>(list => list.First().Id == existingTitle.Id)), Times.Once());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,15 +33,15 @@ public AlternativeTitle(string title, SourceType sourceType = SourceType.TMDB, i
|
|||||||
Language = language ?? Language.English;
|
Language = language ?? Language.English;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsTrusted(int minVotes = 3)
|
public bool IsTrusted(int minVotes = 4)
|
||||||
{
|
{
|
||||||
switch (SourceType)
|
switch (SourceType)
|
||||||
{
|
{
|
||||||
case SourceType.TMDB:
|
case SourceType.Mappings:
|
||||||
return Votes >= minVotes;
|
return Votes >= minVotes;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Marr.Data;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Movies.Events;
|
using NzbDrone.Core.Movies.Events;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Movies.AlternativeTitles
|
namespace NzbDrone.Core.Movies.AlternativeTitles
|
||||||
@ -14,7 +15,7 @@ public interface IAlternativeTitleService
|
|||||||
List<AlternativeTitle> AddAltTitles(List<AlternativeTitle> titles, Movie movie);
|
List<AlternativeTitle> AddAltTitles(List<AlternativeTitle> titles, Movie movie);
|
||||||
AlternativeTitle GetById(int id);
|
AlternativeTitle GetById(int id);
|
||||||
List<AlternativeTitle> GetAllTitles();
|
List<AlternativeTitle> GetAllTitles();
|
||||||
void DeleteNotEnoughVotes(List<AlternativeTitle> mappingsTitles);
|
List<AlternativeTitle> UpdateTitles(List<AlternativeTitle> titles, Movie movie);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AlternativeTitleService : IAlternativeTitleService, IHandleAsync<MovieDeletedEvent>
|
public class AlternativeTitleService : IAlternativeTitleService, IHandleAsync<MovieDeletedEvent>
|
||||||
@ -69,11 +70,28 @@ public void RemoveTitle(AlternativeTitle title)
|
|||||||
_titleRepo.Delete(title);
|
_titleRepo.Delete(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteNotEnoughVotes(List<AlternativeTitle> mappingsTitles)
|
public List<AlternativeTitle> UpdateTitles(List<AlternativeTitle> titles, Movie movie)
|
||||||
{
|
{
|
||||||
var toRemove = mappingsTitles.Where(t => t.SourceType == SourceType.Mappings && t.Votes < 4);
|
int movieId = movie.Id;
|
||||||
var realT = _titleRepo.FindBySourceIds(toRemove.Select(t => t.SourceId).ToList());
|
// First update the movie ids so we can correlate them later.
|
||||||
_titleRepo.DeleteMany(realT);
|
titles.ForEach(t => t.MovieId = movieId);
|
||||||
|
// Then make sure none of them are the same as the main title.
|
||||||
|
titles = titles.Where(t => t.CleanTitle != movie.CleanTitle).ToList();
|
||||||
|
// Then make sure they are all distinct titles
|
||||||
|
titles = titles.DistinctBy(t => t.CleanTitle).ToList();
|
||||||
|
|
||||||
|
// Now find titles to delete, update and insert.
|
||||||
|
var existingTitles = _titleRepo.FindByMovieId(movieId);
|
||||||
|
|
||||||
|
var insert = titles.Where(t => !existingTitles.Contains(t));
|
||||||
|
var update = existingTitles.Where(t => titles.Contains(t));
|
||||||
|
var delete = existingTitles.Where(t => !titles.Contains(t));
|
||||||
|
|
||||||
|
_titleRepo.DeleteMany(delete.ToList());
|
||||||
|
_titleRepo.UpdateMany(update.ToList());
|
||||||
|
_titleRepo.InsertMany(insert.ToList());
|
||||||
|
|
||||||
|
return titles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleAsync(MovieDeletedEvent message)
|
public void HandleAsync(MovieDeletedEvent message)
|
||||||
|
@ -104,26 +104,16 @@ private void RefreshMovieInfo(Movie movie)
|
|||||||
_logger.Warn(e, "Couldn't update movie path for " + movie.Path);
|
_logger.Warn(e, "Couldn't update movie path for " + movie.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
movieInfo.AlternativeTitles = movieInfo.AlternativeTitles.Where(t => t.CleanTitle != movie.CleanTitle)
|
|
||||||
.DistinctBy(t => t.CleanTitle)
|
|
||||||
.ExceptBy(t => t.CleanTitle, movie.AlternativeTitles, t => t.CleanTitle, EqualityComparer<string>.Default).ToList();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
movie.AlternativeTitles.AddRange(_titleService.AddAltTitles(movieInfo.AlternativeTitles, movie));
|
|
||||||
|
|
||||||
var mappings = _apiClient.AlternativeTitlesAndYearForMovie(movieInfo.TmdbId);
|
var mappings = _apiClient.AlternativeTitlesAndYearForMovie(movieInfo.TmdbId);
|
||||||
var mappingsTitles = mappings.Item1;
|
var mappingsTitles = mappings.Item1;
|
||||||
|
|
||||||
_titleService.DeleteNotEnoughVotes(mappingsTitles);
|
mappingsTitles = mappingsTitles.Where(t => t.IsTrusted()).ToList();
|
||||||
|
|
||||||
mappingsTitles = mappingsTitles.ExceptBy(t => t.CleanTitle, movie.AlternativeTitles,
|
movieInfo.AlternativeTitles.AddRange(mappingsTitles);
|
||||||
t => t.CleanTitle, EqualityComparer<string>.Default).ToList();
|
|
||||||
|
movie.AlternativeTitles = _titleService.UpdateTitles(movieInfo.AlternativeTitles, movie);
|
||||||
|
|
||||||
mappingsTitles = mappingsTitles.Where(t => t.Votes > 3).ToList();
|
|
||||||
|
|
||||||
movie.AlternativeTitles.AddRange(_titleService.AddAltTitles(mappingsTitles, movie));
|
|
||||||
|
|
||||||
if (mappings.Item2 != null)
|
if (mappings.Item2 != null)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user