mirror of
				https://github.com/Kareadita/Kavita.git
				synced 2025-11-03 19:17:05 -05:00 
			
		
		
		
	Merge branch 'develop' of https://github.com/Kareadita/Kavita into develop
This commit is contained in:
		
						commit
						a349f16ed4
					
				@ -215,4 +215,8 @@
 | 
				
			|||||||
    <_ContentIncludedByDefault Remove="wwwroot\vendor.6b2a0912ae80e6fd297f.js.map" />
 | 
					    <_ContentIncludedByDefault Remove="wwwroot\vendor.6b2a0912ae80e6fd297f.js.map" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <Reference Include="System.Drawing.Common" />
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</Project>
 | 
					</Project>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using API.DTOs;
 | 
					using API.DTOs;
 | 
				
			||||||
@ -18,14 +19,16 @@ namespace API.Controllers
 | 
				
			|||||||
        private readonly ILogger<BookController> _logger;
 | 
					        private readonly ILogger<BookController> _logger;
 | 
				
			||||||
        private readonly IBookService _bookService;
 | 
					        private readonly IBookService _bookService;
 | 
				
			||||||
        private readonly IUnitOfWork _unitOfWork;
 | 
					        private readonly IUnitOfWork _unitOfWork;
 | 
				
			||||||
 | 
					        private readonly ICacheService _cacheService;
 | 
				
			||||||
        private static readonly string BookApiUrl = "book-resources?file=";
 | 
					        private static readonly string BookApiUrl = "book-resources?file=";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public BookController(ILogger<BookController> logger, IBookService bookService, IUnitOfWork unitOfWork)
 | 
					        public BookController(ILogger<BookController> logger, IBookService bookService, IUnitOfWork unitOfWork, ICacheService cacheService)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _logger = logger;
 | 
					            _logger = logger;
 | 
				
			||||||
            _bookService = bookService;
 | 
					            _bookService = bookService;
 | 
				
			||||||
            _unitOfWork = unitOfWork;
 | 
					            _unitOfWork = unitOfWork;
 | 
				
			||||||
 | 
					            _cacheService = cacheService;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [HttpGet("{chapterId}/book-info")]
 | 
					        [HttpGet("{chapterId}/book-info")]
 | 
				
			||||||
@ -169,9 +172,11 @@ namespace API.Controllers
 | 
				
			|||||||
        [HttpGet("{chapterId}/book-page")]
 | 
					        [HttpGet("{chapterId}/book-page")]
 | 
				
			||||||
        public async Task<ActionResult<string>> GetBookPage(int chapterId, [FromQuery] int page)
 | 
					        public async Task<ActionResult<string>> GetBookPage(int chapterId, [FromQuery] int page)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(chapterId);
 | 
					            var chapter = await _cacheService.Ensure(chapterId);
 | 
				
			||||||
 | 
					            var path = _cacheService.GetCachedEpubFile(chapter.Id, chapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            using var book = await EpubReader.OpenBookAsync(chapter.Files.ElementAt(0).FilePath);
 | 
					
 | 
				
			||||||
 | 
					            using var book = await EpubReader.OpenBookAsync(path);
 | 
				
			||||||
            var mappings = await _bookService.CreateKeyToPageMappingAsync(book);
 | 
					            var mappings = await _bookService.CreateKeyToPageMappingAsync(book);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var counter = 0;
 | 
					            var counter = 0;
 | 
				
			||||||
@ -196,12 +201,7 @@ namespace API.Controllers
 | 
				
			|||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        if (doc.ParseErrors.Any())
 | 
					                        if (doc.ParseErrors.Any())
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            _logger.LogError("{FilePath} has an invalid html file (Page {PageName})", book.FilePath, contentFileRef.FileName);
 | 
					                            LogBookErrors(book, contentFileRef, doc);
 | 
				
			||||||
                            foreach (var error in doc.ParseErrors)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                _logger.LogError("Line {LineNumber}, Reason: {Reason}", error.Line, error.Reason);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            return BadRequest("The file is malformed! Cannot read.");
 | 
					                            return BadRequest("The file is malformed! Cannot read.");
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        _logger.LogError("{FilePath} has no body tag! Generating one for support. Book may be skewed", book.FilePath);
 | 
					                        _logger.LogError("{FilePath} has no body tag! Generating one for support. Book may be skewed", book.FilePath);
 | 
				
			||||||
@ -322,5 +322,14 @@ namespace API.Controllers
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return BadRequest("Could not find the appropriate html for that page");
 | 
					            return BadRequest("Could not find the appropriate html for that page");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void LogBookErrors(EpubBookRef book, EpubTextContentFileRef contentFileRef, HtmlDocument doc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _logger.LogError("{FilePath} has an invalid html file (Page {PageName})", book.FilePath, contentFileRef.FileName);
 | 
				
			||||||
 | 
					            foreach (var error in doc.ParseErrors)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _logger.LogError("Line {LineNumber}, Reason: {Reason}", error.Line, error.Reason);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -35,5 +35,6 @@ namespace API.Interfaces.Services
 | 
				
			|||||||
        Task<(string path, MangaFile file)> GetCachedPagePath(Chapter chapter, int page);
 | 
					        Task<(string path, MangaFile file)> GetCachedPagePath(Chapter chapter, int page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void EnsureCacheDirectory();
 | 
					        void EnsureCacheDirectory();
 | 
				
			||||||
 | 
					        string GetCachedEpubFile(int chapterId, Chapter chapter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -21,8 +21,6 @@ using HtmlAgilityPack;
 | 
				
			|||||||
using Microsoft.Extensions.Logging;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
using Microsoft.IO;
 | 
					using Microsoft.IO;
 | 
				
			||||||
using VersOne.Epub;
 | 
					using VersOne.Epub;
 | 
				
			||||||
using Image = NetVips.Image;
 | 
					 | 
				
			||||||
using Point = System.Drawing.Point;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace API.Services
 | 
					namespace API.Services
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -409,7 +407,7 @@ namespace API.Services
 | 
				
			|||||||
                if (!createThumbnail) return coverImageContent.ReadContent();
 | 
					                if (!createThumbnail) return coverImageContent.ReadContent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                using var stream = StreamManager.GetStream("BookService.GetCoverImage", coverImageContent.ReadContent());
 | 
					                using var stream = StreamManager.GetStream("BookService.GetCoverImage", coverImageContent.ReadContent());
 | 
				
			||||||
                using var thumbnail = Image.ThumbnailStream(stream, MetadataService.ThumbnailWidth);
 | 
					                using var thumbnail = NetVips.Image.ThumbnailStream(stream, MetadataService.ThumbnailWidth);
 | 
				
			||||||
                return thumbnail.WriteToBuffer(".jpg");
 | 
					                return thumbnail.WriteToBuffer(".jpg");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -433,7 +431,7 @@ namespace API.Services
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
               if (!createThumbnail) return stream.ToArray();
 | 
					               if (!createThumbnail) return stream.ToArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
               using var thumbnail = Image.ThumbnailStream(stream, MetadataService.ThumbnailWidth);
 | 
					               using var thumbnail = NetVips.Image.ThumbnailStream(stream, MetadataService.ThumbnailWidth);
 | 
				
			||||||
               return thumbnail.WriteToBuffer(".png");
 | 
					               return thumbnail.WriteToBuffer(".png");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
           }
 | 
					           }
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ using API.Entities.Enums;
 | 
				
			|||||||
using API.Extensions;
 | 
					using API.Extensions;
 | 
				
			||||||
using API.Interfaces;
 | 
					using API.Interfaces;
 | 
				
			||||||
using API.Interfaces.Services;
 | 
					using API.Interfaces.Services;
 | 
				
			||||||
 | 
					using Kavita.Common;
 | 
				
			||||||
using Microsoft.Extensions.Logging;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace API.Services
 | 
					namespace API.Services
 | 
				
			||||||
@ -42,6 +43,23 @@ namespace API.Services
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Returns the full path to the cached epub file. If the file does not exist, will fallback to the original.
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="chapterId"></param>
 | 
				
			||||||
 | 
					        /// <param name="chapter"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        public string GetCachedEpubFile(int chapterId, Chapter chapter)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var extractPath = GetCachePath(chapterId);
 | 
				
			||||||
 | 
					            var path = Path.Join(extractPath, Path.GetFileName(chapter.Files.First().FilePath));
 | 
				
			||||||
 | 
					            if (!(new FileInfo(path).Exists))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path = chapter.Files.First().FilePath;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return path;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public async Task<Chapter> Ensure(int chapterId)
 | 
					        public async Task<Chapter> Ensure(int chapterId)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            EnsureCacheDirectory();
 | 
					            EnsureCacheDirectory();
 | 
				
			||||||
@ -50,6 +68,7 @@ namespace API.Services
 | 
				
			|||||||
            var fileCount = files.Count;
 | 
					            var fileCount = files.Count;
 | 
				
			||||||
            var extractPath = GetCachePath(chapterId);
 | 
					            var extractPath = GetCachePath(chapterId);
 | 
				
			||||||
            var extraPath = "";
 | 
					            var extraPath = "";
 | 
				
			||||||
 | 
					            var removeNonImages = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (Directory.Exists(extractPath))
 | 
					            if (Directory.Exists(extractPath))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -83,15 +102,24 @@ namespace API.Services
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
              if (file.Format == MangaFormat.Archive)
 | 
					              if (file.Format == MangaFormat.Archive)
 | 
				
			||||||
              {
 | 
					              {
 | 
				
			||||||
                _archiveService.ExtractArchive(file.FilePath, Path.Join(extractPath, extraPath));
 | 
					                  _archiveService.ExtractArchive(file.FilePath, Path.Join(extractPath, extraPath));
 | 
				
			||||||
              } else if (file.Format == MangaFormat.Pdf)
 | 
					              } else if (file.Format == MangaFormat.Pdf)
 | 
				
			||||||
              {
 | 
					              {
 | 
				
			||||||
                  _bookService.ExtractPdfImages(file.FilePath, Path.Join(extractPath, extraPath));
 | 
					                  _bookService.ExtractPdfImages(file.FilePath, Path.Join(extractPath, extraPath));
 | 
				
			||||||
 | 
					              } else if (file.Format == MangaFormat.Epub)
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                  removeNonImages = false;
 | 
				
			||||||
 | 
					                  DirectoryService.ExistOrCreate(extractPath);
 | 
				
			||||||
 | 
					                  _directoryService.CopyFileToDirectory(files[0].FilePath, extractPath);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            extractDi.Flatten();
 | 
					            extractDi.Flatten();
 | 
				
			||||||
            extractDi.RemoveNonImages();
 | 
					            if (removeNonImages)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                extractDi.RemoveNonImages();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return chapter;
 | 
					            return chapter;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -106,11 +106,18 @@ namespace API.Services
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
       public void CopyFileToDirectory(string fullFilePath, string targetDirectory)
 | 
					       public void CopyFileToDirectory(string fullFilePath, string targetDirectory)
 | 
				
			||||||
       {
 | 
					       {
 | 
				
			||||||
         var fileInfo = new FileInfo(fullFilePath);
 | 
					           try
 | 
				
			||||||
         if (fileInfo.Exists)
 | 
					           {
 | 
				
			||||||
         {
 | 
					               var fileInfo = new FileInfo(fullFilePath);
 | 
				
			||||||
           fileInfo.CopyTo(Path.Join(targetDirectory, fileInfo.Name));
 | 
					               if (fileInfo.Exists)
 | 
				
			||||||
         }
 | 
					               {
 | 
				
			||||||
 | 
					                   fileInfo.CopyTo(Path.Join(targetDirectory, fileInfo.Name), true);
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
 | 
					           catch (Exception ex)
 | 
				
			||||||
 | 
					           {
 | 
				
			||||||
 | 
					               _logger.LogError(ex, "There was a critical error when copying {File} to {Directory}", fullFilePath, targetDirectory);
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
       }
 | 
					       }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
       /// <summary>
 | 
					       /// <summary>
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
        <TargetFramework>net5.0</TargetFramework>
 | 
					        <TargetFramework>net5.0</TargetFramework>
 | 
				
			||||||
        <Company>kavitareader.com</Company>
 | 
					        <Company>kavitareader.com</Company>
 | 
				
			||||||
        <Product>Kavita</Product>
 | 
					        <Product>Kavita</Product>
 | 
				
			||||||
        <AssemblyVersion>0.4.3.2</AssemblyVersion>
 | 
					        <AssemblyVersion>0.4.3.3</AssemblyVersion>
 | 
				
			||||||
        <NeutralLanguage>en</NeutralLanguage>
 | 
					        <NeutralLanguage>en</NeutralLanguage>
 | 
				
			||||||
    </PropertyGroup>
 | 
					    </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user