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/Readarr.Api.V1/BookFiles/BookFileController.cs

191 lines
7.1 KiB

using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using NzbDrone.Core.Books;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Http.REST.Attributes;
using NzbDrone.SignalR;
using Readarr.Http;
using Readarr.Http.REST;
using BadRequestException = NzbDrone.Core.Exceptions.BadRequestException;
using HttpStatusCode = System.Net.HttpStatusCode;
namespace Readarr.Api.V1.BookFiles
{
[V1ApiController]
public class BookFileController : RestControllerWithSignalR<BookFileResource, BookFile>,
IHandle<BookFileAddedEvent>,
IHandle<BookFileDeletedEvent>
{
private readonly IMediaFileService _mediaFileService;
private readonly IDeleteMediaFiles _mediaFileDeletionService;
private readonly IMetadataTagService _metadataTagService;
private readonly IAuthorService _authorService;
private readonly IBookService _bookService;
private readonly IUpgradableSpecification _upgradableSpecification;
public BookFileController(IBroadcastSignalRMessage signalRBroadcaster,
IMediaFileService mediaFileService,
IDeleteMediaFiles mediaFileDeletionService,
IMetadataTagService metadataTagService,
IAuthorService authorService,
IBookService bookService,
IUpgradableSpecification upgradableSpecification)
: base(signalRBroadcaster)
{
_mediaFileService = mediaFileService;
_mediaFileDeletionService = mediaFileDeletionService;
_metadataTagService = metadataTagService;
_authorService = authorService;
_bookService = bookService;
_upgradableSpecification = upgradableSpecification;
}
private BookFileResource MapToResource(BookFile bookFile)
{
if (bookFile.EditionId > 0 && bookFile.Author != null && bookFile.Author.Value != null)
{
return bookFile.ToResource(bookFile.Author.Value, _upgradableSpecification);
}
else
{
return bookFile.ToResource();
}
}
protected override BookFileResource GetResourceById(int id)
{
var resource = MapToResource(_mediaFileService.Get(id));
resource.AudioTags = _metadataTagService.ReadTags((FileInfoBase)new FileInfo(resource.Path));
return resource;
}
[HttpGet]
public List<BookFileResource> GetBookFiles(int? authorId, [FromQuery]List<int> bookFileIds, [FromQuery(Name="bookId")]List<int> bookIds, bool? unmapped)
{
if (!authorId.HasValue && !bookFileIds.Any() && !bookIds.Any() && !unmapped.HasValue)
{
throw new BadRequestException("authorId, bookId, bookFileIds or unmapped must be provided");
}
if (unmapped.HasValue && unmapped.Value)
{
var files = _mediaFileService.GetUnmappedFiles();
return files.ConvertAll(f => MapToResource(f));
}
if (authorId.HasValue && !bookIds.Any())
{
var author = _authorService.GetAuthor(authorId.Value);
return _mediaFileService.GetFilesByAuthor(authorId.Value).ConvertAll(f => f.ToResource(author, _upgradableSpecification));
}
if (bookIds.Any())
{
var result = new List<BookFileResource>();
foreach (var bookId in bookIds)
{
var book = _bookService.GetBook(bookId);
var bookAuthor = _authorService.GetAuthor(book.AuthorId);
result.AddRange(_mediaFileService.GetFilesByBook(book.Id).ConvertAll(f => f.ToResource(bookAuthor, _upgradableSpecification)));
}
return result;
}
else
{
// trackfiles will come back with the author already populated
var bookFiles = _mediaFileService.Get(bookFileIds);
return bookFiles.ConvertAll(e => MapToResource(e));
}
}
[RestPutById]
public ActionResult<BookFileResource> SetQuality(BookFileResource bookFileResource)
{
var bookFile = _mediaFileService.Get(bookFileResource.Id);
bookFile.Quality = bookFileResource.Quality;
_mediaFileService.Update(bookFile);
return Accepted(bookFile.Id);
}
[HttpPut("editor")]
public IActionResult SetQuality([FromBody] BookFileListResource resource)
{
var bookFiles = _mediaFileService.Get(resource.BookFileIds);
foreach (var bookFile in bookFiles)
{
if (resource.Quality != null)
{
bookFile.Quality = resource.Quality;
}
}
_mediaFileService.Update(bookFiles);
return Accepted(bookFiles.ConvertAll(f => f.ToResource(bookFiles.First().Author.Value, _upgradableSpecification)));
}
[RestDeleteById]
public void DeleteBookFile(int id)
{
var bookFile = _mediaFileService.Get(id);
if (bookFile == null)
{
throw new NzbDroneClientException(HttpStatusCode.NotFound, "Book file not found");
}
if (bookFile.EditionId > 0 && bookFile.Author != null && bookFile.Author.Value != null)
{
_mediaFileDeletionService.DeleteTrackFile(bookFile.Author.Value, bookFile);
}
else
{
_mediaFileDeletionService.DeleteTrackFile(bookFile, "Unmapped_Files");
}
}
[HttpDelete("bulk")]
public object DeleteTrackFiles([FromBody] BookFileListResource resource)
{
var bookFiles = _mediaFileService.Get(resource.BookFileIds);
foreach (var bookFile in bookFiles)
{
if (bookFile.EditionId > 0 && bookFile.Author != null && bookFile.Author.Value != null)
{
_mediaFileDeletionService.DeleteTrackFile(bookFile.Author.Value, bookFile);
}
else
{
_mediaFileDeletionService.DeleteTrackFile(bookFile, "Unmapped_Files");
}
}
return new { };
}
[NonAction]
public void Handle(BookFileAddedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, MapToResource(message.BookFile));
}
[NonAction]
public void Handle(BookFileDeletedEvent message)
{
BroadcastResourceChange(ModelAction.Deleted, MapToResource(message.BookFile));
}
}
}