You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Readarr/src/NzbDrone.Core/Books/Services/AddBookService.cs

137 lines
4.9 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation;
using FluentValidation.Results;
using NLog;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.ImportLists.Exclusions;
using NzbDrone.Core.MetadataSource;
namespace NzbDrone.Core.Books
{
public interface IAddBookService
{
Book AddBook(Book book, bool doRefresh = true);
List<Book> AddBooks(List<Book> books, bool doRefresh = true);
}
public class AddBookService : IAddBookService
{
private readonly IAuthorService _authorService;
private readonly IAddAuthorService _addAuthorService;
private readonly IBookService _bookService;
private readonly IProvideBookInfo _bookInfo;
private readonly IImportListExclusionService _importListExclusionService;
private readonly Logger _logger;
public AddBookService(IAuthorService authorService,
IAddAuthorService addAuthorService,
IBookService bookService,
IProvideBookInfo bookInfo,
IImportListExclusionService importListExclusionService,
Logger logger)
{
_authorService = authorService;
_addAuthorService = addAuthorService;
_bookService = bookService;
_bookInfo = bookInfo;
_importListExclusionService = importListExclusionService;
_logger = logger;
}
public Book AddBook(Book book, bool doRefresh = true)
{
_logger.Debug($"Adding book {book}");
book = AddSkyhookData(book);
// we allow adding extra editions, so check if the book already exists
var dbBook = _bookService.FindById(book.ForeignBookId);
if (dbBook != null)
{
book.UseDbFieldsFrom(dbBook);
}
// Remove any import list exclusions preventing addition
_importListExclusionService.Delete(book.ForeignBookId);
_importListExclusionService.Delete(book.AuthorMetadata.Value.ForeignAuthorId);
// Note it's a manual addition so it's not deleted on next refresh
book.AddOptions.AddType = BookAddType.Manual;
book.Editions.Value.Single(x => x.Monitored).ManualAdd = true;
// Add the author if necessary
var dbAuthor = _authorService.FindById(book.AuthorMetadata.Value.ForeignAuthorId);
if (dbAuthor == null)
{
var author = book.Author.Value;
author.Metadata.Value.ForeignAuthorId = book.AuthorMetadata.Value.ForeignAuthorId;
dbAuthor = _addAuthorService.AddAuthor(author, false);
}
book.Author = dbAuthor;
book.AuthorMetadataId = dbAuthor.AuthorMetadataId;
_bookService.AddBook(book, doRefresh);
return book;
}
public List<Book> AddBooks(List<Book> books, bool doRefresh = true)
{
var added = DateTime.UtcNow;
var addedBooks = new List<Book>();
foreach (var a in books)
{
a.Added = added;
try
{
addedBooks.Add(AddBook(a, doRefresh));
}
catch (Exception ex)
{
// Could be a bad id from an import list
_logger.Error(ex, "Failed to import id: {0} - {1}", a.ForeignBookId, a.Title);
}
}
return addedBooks;
}
private Book AddSkyhookData(Book newBook)
{
var editionId = newBook.Editions.Value.Single(x => x.Monitored).ForeignEditionId;
Tuple<string, Book, List<AuthorMetadata>> tuple = null;
try
{
tuple = _bookInfo.GetBookInfo(newBook.ForeignBookId);
}
catch (BookNotFoundException)
{
_logger.Error("Book with Foreign Id {0} was not found, it may have been removed from Goodreads.", newBook.ForeignBookId);
throw new ValidationException(new List<ValidationFailure>
{
new ValidationFailure("GoodreadsId", "A book with this ID was not found", newBook.ForeignBookId)
});
}
newBook.UseMetadataFrom(tuple.Item2);
newBook.Added = DateTime.UtcNow;
newBook.Editions = tuple.Item2.Editions.Value;
newBook.Editions.Value.ForEach(x => x.Monitored = false);
newBook.Editions.Value.Single(x => x.ForeignEditionId == editionId).Monitored = true;
var metadata = tuple.Item3.FirstOrDefault(x => x.ForeignAuthorId == tuple.Item1);
newBook.AuthorMetadata = metadata;
return newBook;
}
}
}