Added upload function

pull/3344/head
adechant 6 months ago
parent 8a737e6ba0
commit a18b37fd53

@ -27,6 +27,7 @@ namespace NzbDrone.Core.MediaFiles.BookImport.Manual
public interface IManualImportService
{
List<ManualImportItem> GetMediaFiles(string path, string downloadId, Author author, FilterFilesType filter, bool replaceExistingFiles);
List<ManualImportItem> ProcessFile(string path, Book book, Author author, FilterFilesType filter, bool replaceExistingFiles);
List<ManualImportItem> UpdateItems(List<ManualImportItem> item);
}
@ -87,6 +88,41 @@ namespace NzbDrone.Core.MediaFiles.BookImport.Manual
_logger = logger;
}
public List<ManualImportItem> ProcessFile(string path, Book book, Author author, FilterFilesType filter, bool replaceExistingFiles)
{
if (!_diskProvider.FolderExists(path))
{
if (!_diskProvider.FileExists(path))
{
return new List<ManualImportItem>();
}
var files = new List<IFileInfo> { _diskProvider.GetFileInfo(path) };
var config = new ImportDecisionMakerConfig
{
Filter = FilterFilesType.None,
NewDownload = true,
SingleRelease = false,
IncludeExisting = !replaceExistingFiles,
AddNewAuthors = false,
KeepAllEditions = true
};
var idOverrides = new IdentificationOverrides();
idOverrides.Book = book;
idOverrides.Author = author;
var decision = _importDecisionMaker.GetImportDecisions(files, idOverrides, null, config);
var result = MapItem(decision.First(), null, replaceExistingFiles, false);
_importApprovedBooks.Import(decision, false);
return new List<ManualImportItem> { result };
}
return new List<ManualImportItem>();
}
public List<ManualImportItem> GetMediaFiles(string path, string downloadId, Author author, FilterFilesType filter, bool replaceExistingFiles)
{
if (downloadId.IsNotNullOrWhiteSpace())

@ -2,14 +2,18 @@ using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
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.BookImport.Manual;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Http.REST.Attributes;
@ -33,8 +37,12 @@ namespace Readarr.Api.V1.BookFiles
private readonly IBookService _bookService;
private readonly IUpgradableSpecification _upgradableSpecification;
private readonly IContentTypeProvider _mimeTypeProvider;
private readonly IDiskProvider _diskProvider;
private readonly IManualImportService _manualImportService;
public BookFileController(IBroadcastSignalRMessage signalRBroadcaster,
public BookFileController(IManualImportService manualImportService,
IDiskProvider diskProvider,
IBroadcastSignalRMessage signalRBroadcaster,
IMediaFileService mediaFileService,
IDeleteMediaFiles mediaFileDeletionService,
IMetadataTagService metadataTagService,
@ -43,6 +51,8 @@ namespace Readarr.Api.V1.BookFiles
IUpgradableSpecification upgradableSpecification)
: base(signalRBroadcaster)
{
_diskProvider = diskProvider;
_manualImportService = manualImportService;
_mediaFileService = mediaFileService;
_mediaFileDeletionService = mediaFileDeletionService;
_metadataTagService = metadataTagService;
@ -127,6 +137,60 @@ namespace Readarr.Api.V1.BookFiles
return new PhysicalFileResult(filePath, GetContentType(filePath));
}
[HttpPost("upload/{id:int}")]
public async Task<IActionResult> PutBookFileAsync(int id, IFormFile file)
{
if (file == null || file.Length == 0)
{
throw new NzbDroneClientException(HttpStatusCode.UnprocessableEntity, "no file selected for upload");
}
else if (file.Length > 2.5e+7)
{
throw new NzbDroneClientException(HttpStatusCode.UnprocessableEntity, "file is too large for upload. max file size is 25 MB.");
}
var contentType = file.ContentType;
var book = _bookService.GetBook(id);
var title = book.Title;
var bookAuthor = _authorService.GetAuthor(book.AuthorId);
var extension = GetExtension(Path.GetFileName(file.FileName));
if (!MediaFileExtensions.AllExtensions.Contains(extension))
{
throw new NzbDroneClientException(HttpStatusCode.UnprocessableEntity, "invalid content type for upload.");
}
//create a tmpdirectory with the given id
var directory = Path.Join(Path.GetTempPath(), book.Title);
if (!_diskProvider.FolderExists(directory))
{
_diskProvider.CreateFolder(directory);
}
//don't use the uploaded files name in case it is intentionally malformed
var fileName = string.Format("{0}{1}", title, extension);
var combined = Path.Combine(directory, fileName);
using (var fileStream = new FileStream(combined, FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
var list = _manualImportService.ProcessFile(combined, book, bookAuthor, FilterFilesType.None, false);
if (list.Empty())
{
throw new NzbDroneClientException(HttpStatusCode.UnprocessableEntity, "import failed.");
}
else if (!list.First().Rejections.Empty())
{
throw new NzbDroneClientException(HttpStatusCode.UnprocessableEntity, "import failed.");
}
//delete the directory after manual import
_diskProvider.DeleteFolder(directory, true);
return Accepted();
}
[RestPutById]
public ActionResult<BookFileResource> SetQuality(BookFileResource bookFileResource)
{
@ -229,5 +293,21 @@ namespace Readarr.Api.V1.BookFiles
return contentType;
}
private static string GetExtension(string path)
{
if (string.IsNullOrWhiteSpace(path))
{
return null;
}
var index = path.LastIndexOf('.');
if (index < 0)
{
return null;
}
return path.Substring(index);
}
}
}

@ -25,6 +25,7 @@ namespace Readarr.Api.V1.OPDS
public class OPDSPublicationMetadataResource : IEmbeddedDocument
{
public int Id { get; set; }
public string Title { get; set; }
public string @Type { get; set; }
public string Author { get; set; }
@ -144,6 +145,7 @@ namespace Readarr.Api.V1.OPDS
var edition = book.Editions?.Value.Where(x => x.Monitored).SingleOrDefault();
return new OPDSPublicationMetadataResource
{
Id = book.Id,
Title = book.Title,
@Type = "http://schema.org/Book",
Author = book.Author.Value?.Metadata?.Value?.SortNameLastFirst ?? book.Author.Value.Name,
@ -247,7 +249,7 @@ namespace Readarr.Api.V1.OPDS
private static string GetImageContentType(string ext)
{
var contentType = string.Format("application/{0}", ext);
if (ext.Contains("jpg") || ext.Contains("jepg"))
if (ext.Contains("jpg") || ext.Contains("jpeg"))
{
contentType = "image/jpeg";
}

Loading…
Cancel
Save