mirror of
https://github.com/Readarr/Readarr
synced 2026-01-22 15:31:29 +01:00
Merge cefa4ddbbc into 0b79d3000d
This commit is contained in:
commit
3fccf1197f
8 changed files with 59 additions and 30 deletions
|
|
@ -54,7 +54,7 @@ public void should_be_able_to_monitor_author_without_changing_books()
|
|||
Subject.SetBookMonitoredStatus(_author, null);
|
||||
|
||||
Mocker.GetMock<IAuthorService>()
|
||||
.Verify(v => v.UpdateAuthor(It.IsAny<Author>()), Times.Once());
|
||||
.Verify(v => v.UpdateAuthor(It.IsAny<Author>(), It.IsAny<bool>()), Times.Once());
|
||||
|
||||
Mocker.GetMock<IBookService>()
|
||||
.Verify(v => v.UpdateMany(It.IsAny<List<Book>>()), Times.Never());
|
||||
|
|
@ -68,7 +68,7 @@ public void should_be_able_to_monitor_books_when_passed_in_author()
|
|||
Subject.SetBookMonitoredStatus(_author, new MonitoringOptions { Monitored = true, BooksToMonitor = booksToMonitor });
|
||||
|
||||
Mocker.GetMock<IAuthorService>()
|
||||
.Verify(v => v.UpdateAuthor(It.IsAny<Author>()), Times.Once());
|
||||
.Verify(v => v.UpdateAuthor(It.IsAny<Author>(), It.IsAny<bool>()), Times.Once());
|
||||
|
||||
VerifyMonitored(e => e.ForeignBookId == _books.First().ForeignBookId);
|
||||
VerifyNotMonitored(e => e.ForeignBookId != _books.First().ForeignBookId);
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ public void should_revert_author_path_on_error()
|
|||
ExceptionVerification.ExpectedErrors(1);
|
||||
|
||||
Mocker.GetMock<IAuthorService>()
|
||||
.Verify(v => v.UpdateAuthor(It.IsAny<Author>()), Times.Once());
|
||||
.Verify(v => v.UpdateAuthor(It.IsAny<Author>(), It.IsAny<bool>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
|||
|
|
@ -113,8 +113,8 @@ private void GivenBooksForRefresh(List<Book> books)
|
|||
private void AllowAuthorUpdate()
|
||||
{
|
||||
Mocker.GetMock<IAuthorService>(MockBehavior.Strict)
|
||||
.Setup(x => x.UpdateAuthor(It.IsAny<Author>()))
|
||||
.Returns((Author a) => a);
|
||||
.Setup(x => x.UpdateAuthor(It.IsAny<Author>(), It.IsAny<bool>()))
|
||||
.Returns((Author a, bool b) => a);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
@ -187,7 +187,7 @@ public void should_log_error_and_delete_if_musicbrainz_id_not_found_and_author_h
|
|||
Subject.Execute(new RefreshAuthorCommand(_author.Id));
|
||||
|
||||
Mocker.GetMock<IAuthorService>()
|
||||
.Verify(v => v.UpdateAuthor(It.IsAny<Author>()), Times.Never());
|
||||
.Verify(v => v.UpdateAuthor(It.IsAny<Author>(), It.IsAny<bool>()), Times.Never());
|
||||
|
||||
Mocker.GetMock<IAuthorService>()
|
||||
.Verify(v => v.DeleteAuthor(It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Once());
|
||||
|
|
@ -205,7 +205,7 @@ public void should_log_error_but_not_delete_if_musicbrainz_id_not_found_and_auth
|
|||
Subject.Execute(new RefreshAuthorCommand(_author.Id));
|
||||
|
||||
Mocker.GetMock<IAuthorService>()
|
||||
.Verify(v => v.UpdateAuthor(It.IsAny<Author>()), Times.Never());
|
||||
.Verify(v => v.UpdateAuthor(It.IsAny<Author>(), It.IsAny<bool>()), Times.Never());
|
||||
|
||||
Mocker.GetMock<IAuthorService>()
|
||||
.Verify(v => v.DeleteAuthor(It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Never());
|
||||
|
|
@ -233,8 +233,8 @@ public void should_update_if_musicbrainz_id_changed_and_no_clash()
|
|||
// Make sure that the author is updated before we refresh the books
|
||||
Mocker.GetMock<IAuthorService>(MockBehavior.Strict)
|
||||
.InSequence(seq)
|
||||
.Setup(x => x.UpdateAuthor(It.IsAny<Author>()))
|
||||
.Returns((Author a) => a);
|
||||
.Setup(x => x.UpdateAuthor(It.IsAny<Author>(), It.IsAny<bool>()))
|
||||
.Returns((Author a, bool b) => a);
|
||||
|
||||
Mocker.GetMock<IBookService>(MockBehavior.Strict)
|
||||
.InSequence(seq)
|
||||
|
|
@ -244,13 +244,13 @@ public void should_update_if_musicbrainz_id_changed_and_no_clash()
|
|||
// Update called twice for a move/merge
|
||||
Mocker.GetMock<IAuthorService>(MockBehavior.Strict)
|
||||
.InSequence(seq)
|
||||
.Setup(x => x.UpdateAuthor(It.IsAny<Author>()))
|
||||
.Returns((Author a) => a);
|
||||
.Setup(x => x.UpdateAuthor(It.IsAny<Author>(), It.IsAny<bool>()))
|
||||
.Returns((Author a, bool b) => a);
|
||||
|
||||
Subject.Execute(new RefreshAuthorCommand(_author.Id));
|
||||
|
||||
Mocker.GetMock<IAuthorService>()
|
||||
.Verify(v => v.UpdateAuthor(It.Is<Author>(s => s.AuthorMetadataId == 100 && s.ForeignAuthorId == newAuthorInfo.ForeignAuthorId)),
|
||||
.Verify(v => v.UpdateAuthor(It.Is<Author>(s => s.AuthorMetadataId == 100 && s.ForeignAuthorId == newAuthorInfo.ForeignAuthorId), It.IsAny<bool>()),
|
||||
Times.Exactly(2));
|
||||
}
|
||||
|
||||
|
|
@ -293,8 +293,8 @@ public void should_merge_if_musicbrainz_id_changed_and_new_id_already_exists()
|
|||
|
||||
Mocker.GetMock<IAuthorService>(MockBehavior.Strict)
|
||||
.InSequence(seq)
|
||||
.Setup(x => x.UpdateAuthor(It.Is<Author>(a => a.Id == clash.Id)))
|
||||
.Returns((Author a) => a);
|
||||
.Setup(x => x.UpdateAuthor(It.Is<Author>(a => a.Id == clash.Id), It.IsAny<bool>()))
|
||||
.Returns((Author a, bool b) => a);
|
||||
|
||||
Mocker.GetMock<IBookService>(MockBehavior.Strict)
|
||||
.InSequence(seq)
|
||||
|
|
@ -304,14 +304,14 @@ public void should_merge_if_musicbrainz_id_changed_and_new_id_already_exists()
|
|||
// Update called twice for a move/merge
|
||||
Mocker.GetMock<IAuthorService>(MockBehavior.Strict)
|
||||
.InSequence(seq)
|
||||
.Setup(x => x.UpdateAuthor(It.IsAny<Author>()))
|
||||
.Returns((Author a) => a);
|
||||
.Setup(x => x.UpdateAuthor(It.IsAny<Author>(), It.IsAny<bool>()))
|
||||
.Returns((Author a, bool b) => a);
|
||||
|
||||
Subject.Execute(new RefreshAuthorCommand(_author.Id));
|
||||
|
||||
// the retained author gets updated
|
||||
Mocker.GetMock<IAuthorService>()
|
||||
.Verify(v => v.UpdateAuthor(It.Is<Author>(s => s.Id == clash.Id)), Times.Exactly(2));
|
||||
.Verify(v => v.UpdateAuthor(It.Is<Author>(s => s.Id == clash.Id), It.IsAny<bool>()), Times.Exactly(2));
|
||||
|
||||
// the old one gets removed
|
||||
Mocker.GetMock<IAuthorService>()
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public interface IAuthorService
|
|||
List<Author> GetAllAuthors();
|
||||
Dictionary<int, List<int>> GetAllAuthorTags();
|
||||
List<Author> AllForTag(int tagId);
|
||||
Author UpdateAuthor(Author author);
|
||||
Author UpdateAuthor(Author author, bool publishUpdatedEvent = true);
|
||||
List<Author> UpdateAuthors(List<Author> authors, bool useExistingRelativeFolder);
|
||||
Dictionary<int, string> AllAuthorPaths();
|
||||
bool AuthorPathExists(string folder);
|
||||
|
|
@ -222,7 +222,7 @@ public void RemoveAddOptions(Author author)
|
|||
_authorRepository.SetFields(author, s => s.AddOptions);
|
||||
}
|
||||
|
||||
public Author UpdateAuthor(Author author)
|
||||
public Author UpdateAuthor(Author author, bool publishUpdatedEvent = true)
|
||||
{
|
||||
_cache.Clear();
|
||||
|
||||
|
|
@ -232,7 +232,10 @@ public Author UpdateAuthor(Author author)
|
|||
author.AddOptions = storedAuthor.AddOptions;
|
||||
|
||||
var updatedAuthor = _authorRepository.Update(author);
|
||||
_eventAggregator.PublishEvent(new AuthorEditedEvent(updatedAuthor, storedAuthor));
|
||||
if (publishUpdatedEvent)
|
||||
{
|
||||
_eventAggregator.PublishEvent(new AuthorEditedEvent(updatedAuthor, storedAuthor));
|
||||
}
|
||||
|
||||
return updatedAuthor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ protected override Author GetEntityByForeignId(Author local)
|
|||
|
||||
protected override void SaveEntity(Author local)
|
||||
{
|
||||
_authorService.UpdateAuthor(local);
|
||||
_authorService.UpdateAuthor(local, publishUpdatedEvent: false);
|
||||
}
|
||||
|
||||
protected override void DeleteEntity(Author local, bool deleteFiles)
|
||||
|
|
|
|||
|
|
@ -20,11 +20,12 @@ public interface IMapCoversToLocal
|
|||
{
|
||||
void ConvertToLocalUrls(int entityId, MediaCoverEntity coverEntity, IEnumerable<MediaCover> covers);
|
||||
string GetCoverPath(int entityId, MediaCoverEntity coverEntity, MediaCoverTypes coverType, string extension, int? height = null);
|
||||
void EnsureBookCovers(Book book);
|
||||
bool EnsureBookCovers(Book book);
|
||||
}
|
||||
|
||||
public class MediaCoverService :
|
||||
IHandleAsync<AuthorRefreshCompleteEvent>,
|
||||
IHandleAsync<BookAddedEvent>,
|
||||
IHandleAsync<AuthorDeletedEvent>,
|
||||
IHandleAsync<BookDeletedEvent>,
|
||||
IMapCoversToLocal
|
||||
|
|
@ -135,8 +136,9 @@ private string GetBookCoverPath(int bookId)
|
|||
return Path.Combine(_coverRootFolder, "Books", bookId.ToString());
|
||||
}
|
||||
|
||||
private void EnsureAuthorCovers(Author author)
|
||||
private bool EnsureAuthorCovers(Author author)
|
||||
{
|
||||
var updated = false;
|
||||
var toResize = new List<Tuple<MediaCover, bool>>();
|
||||
|
||||
foreach (var cover in author.Metadata.Value.Images)
|
||||
|
|
@ -158,6 +160,7 @@ private void EnsureAuthorCovers(Author author)
|
|||
if (!alreadyExists)
|
||||
{
|
||||
DownloadCover(author, cover, serverFileHeaders.LastModified ?? DateTime.Now);
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
catch (HttpException e)
|
||||
|
|
@ -189,10 +192,13 @@ private void EnsureAuthorCovers(Author author)
|
|||
{
|
||||
_semaphore.Release();
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
public void EnsureBookCovers(Book book)
|
||||
public bool EnsureBookCovers(Book book)
|
||||
{
|
||||
var updated = false;
|
||||
foreach (var cover in book.Editions.Value.Single(x => x.Monitored).Images.Where(e => e.CoverType == MediaCoverTypes.Cover))
|
||||
{
|
||||
if (cover.CoverType == MediaCoverTypes.Unknown)
|
||||
|
|
@ -212,6 +218,7 @@ public void EnsureBookCovers(Book book)
|
|||
if (!alreadyExists)
|
||||
{
|
||||
DownloadBookCover(book, cover, serverFileHeaders.LastModified ?? DateTime.Now);
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
catch (HttpException e)
|
||||
|
|
@ -227,6 +234,8 @@ public void EnsureBookCovers(Book book)
|
|||
_logger.Error(e, "Couldn't download media cover for {0}", book);
|
||||
}
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
private void DownloadCover(Author author, MediaCover cover, DateTime lastModified)
|
||||
|
|
@ -354,15 +363,26 @@ private HttpHeader GetServerHeaders(string url)
|
|||
|
||||
public void HandleAsync(AuthorRefreshCompleteEvent message)
|
||||
{
|
||||
EnsureAuthorCovers(message.Author);
|
||||
var updated = EnsureAuthorCovers(message.Author);
|
||||
|
||||
var books = _bookService.GetBooksByAuthor(message.Author.Id);
|
||||
|
||||
foreach (var book in books)
|
||||
{
|
||||
EnsureBookCovers(book);
|
||||
updated |= EnsureBookCovers(book);
|
||||
}
|
||||
|
||||
_eventAggregator.PublishEvent(new MediaCoversUpdatedEvent(message.Author));
|
||||
_eventAggregator.PublishEvent(new MediaCoversUpdatedEvent(message.Author, updated));
|
||||
}
|
||||
|
||||
public void HandleAsync(BookAddedEvent message)
|
||||
{
|
||||
if (message.DoRefresh)
|
||||
{
|
||||
var updated = EnsureBookCovers(message.Book);
|
||||
|
||||
_eventAggregator.PublishEvent(new MediaCoversUpdatedEvent(message.Book, updated));
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleAsync(AuthorDeletedEvent message)
|
||||
|
|
|
|||
|
|
@ -7,15 +7,18 @@ public class MediaCoversUpdatedEvent : IEvent
|
|||
{
|
||||
public Author Author { get; set; }
|
||||
public Book Book { get; set; }
|
||||
public bool Updated { get; set; }
|
||||
|
||||
public MediaCoversUpdatedEvent(Author author)
|
||||
public MediaCoversUpdatedEvent(Author author, bool updated)
|
||||
{
|
||||
Author = author;
|
||||
Updated = updated;
|
||||
}
|
||||
|
||||
public MediaCoversUpdatedEvent(Book book)
|
||||
public MediaCoversUpdatedEvent(Book book, bool updated)
|
||||
{
|
||||
Book = book;
|
||||
Updated = updated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -286,7 +286,10 @@ public void Handle(AuthorRenamedEvent message)
|
|||
[NonAction]
|
||||
public void Handle(MediaCoversUpdatedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, GetAuthorResource(message.Author));
|
||||
if (message.Updated)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, GetAuthorResource(message.Author));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue