Skip to content

Commit

Permalink
Merge pull request #682 from Stirling-Tools/ebook
Browse files Browse the repository at this point in the history
Ebook
  • Loading branch information
Frooodle authored Jan 10, 2024
2 parents 362a7ff + 1924dfb commit 50ee829
Show file tree
Hide file tree
Showing 23 changed files with 652 additions and 48 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ plugins {
import com.github.jk1.license.render.*

group = 'stirling.software'
version = '0.19.0'
version = '0.19.1'
sourceCompatibility = '17'

repositories {
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/stirling/software/SPDF/config/AppConfig.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package stirling.software.SPDF.config;

import java.nio.file.Files;
import java.nio.file.Paths;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -57,4 +60,22 @@ public boolean rateLimit() {
if (appName == null) appName = System.getenv("rateLimit");
return (appName != null) ? Boolean.valueOf(appName) : false;
}

@Bean(name = "RunningInDocker")
public boolean runningInDocker() {
return Files.exists(Paths.get("/.dockerenv"));
}

@Bean(name = "bookFormatsInstalled")
public boolean bookFormatsInstalled() {
return applicationProperties.getSystem().getCustomApplications().isInstallBookFormats();
}

@Bean(name = "htmlFormatsInstalled")
public boolean htmlFormatsInstalled() {
return applicationProperties
.getSystem()
.getCustomApplications()
.isInstallAdvancedHtmlToPDF();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,29 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;

import stirling.software.SPDF.model.ApplicationProperties;

@Service
@DependsOn({"bookFormatsInstalled"})
public class EndpointConfiguration {
private static final Logger logger = LoggerFactory.getLogger(EndpointConfiguration.class);
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();

private final ApplicationProperties applicationProperties;

private boolean bookFormatsInstalled;

@Autowired
public EndpointConfiguration(ApplicationProperties applicationProperties) {
public EndpointConfiguration(
ApplicationProperties applicationProperties,
@Qualifier("bookFormatsInstalled") boolean bookFormatsInstalled) {
this.applicationProperties = applicationProperties;
this.bookFormatsInstalled = bookFormatsInstalled;
init();
processEnvironmentConfigs();
}
Expand Down Expand Up @@ -145,6 +153,12 @@ public void init() {
addEndpointToGroup("CLI", "ocr-pdf");
addEndpointToGroup("CLI", "html-to-pdf");
addEndpointToGroup("CLI", "url-to-pdf");
addEndpointToGroup("CLI", "book-to-pdf");
addEndpointToGroup("CLI", "pdf-to-book");

// Calibre
addEndpointToGroup("Calibre", "book-to-pdf");
addEndpointToGroup("Calibre", "pdf-to-book");

// python
addEndpointToGroup("Python", "extract-image-scans");
Expand Down Expand Up @@ -215,7 +229,9 @@ public void init() {
private void processEnvironmentConfigs() {
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();

if (!bookFormatsInstalled) {
groupsToRemove.add("Calibre");
}
if (endpointsToRemove != null) {
for (String endpoint : endpointsToRemove) {
disableEndpoint(endpoint.trim());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package stirling.software.SPDF.config;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.utils.ProcessExecutor;
import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult;

@Component
public class PostStartupProcesses {

@Autowired ApplicationProperties applicationProperties;

@Autowired
@Qualifier("RunningInDocker")
private boolean runningInDocker;

@Autowired
@Qualifier("bookFormatsInstalled")
private boolean bookFormatsInstalled;

@Autowired
@Qualifier("htmlFormatsInstalled")
private boolean htmlFormatsInstalled;

private static final Logger logger = LoggerFactory.getLogger(PostStartupProcesses.class);

@PostConstruct
public void runInstallCommandBasedOnEnvironment() throws IOException, InterruptedException {
List<List<String>> commands = new ArrayList<>();
// Checking for DOCKER_INSTALL_BOOK_FORMATS environment variable
if (bookFormatsInstalled) {
List<String> tmpList = new ArrayList<>();
// Set up the timezone configuration commands
tmpList.addAll(
Arrays.asList(
"sh",
"-c",
"echo 'tzdata tzdata/Areas select Europe' | debconf-set-selections; "
+ "echo 'tzdata tzdata/Zones/Europe select Berlin' | debconf-set-selections"));
commands.add(tmpList);

// Install calibre with DEBIAN_FRONTEND set to noninteractive
tmpList = new ArrayList<>();
tmpList.addAll(
Arrays.asList(
"sh",
"-c",
"DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends calibre"));
commands.add(tmpList);
}

// Checking for DOCKER_INSTALL_HTML_FORMATS environment variable
if (htmlFormatsInstalled) {
List<String> tmpList = new ArrayList<>();
// Add -y flag for automatic yes to prompts and --no-install-recommends to reduce size
tmpList.addAll(
Arrays.asList(
"apt-get", "install", "wkhtmltopdf", "-y", "--no-install-recommends"));
commands.add(tmpList);
}

if (!commands.isEmpty()) {
// Run the command
if (runningInDocker) {
List<String> tmpList = new ArrayList<>();
tmpList.addAll(Arrays.asList("apt-get", "update"));
commands.add(0, tmpList);

for (List<String> list : commands) {
ProcessExecutorResult returnCode =
ProcessExecutor.getInstance(ProcessExecutor.Processes.INSTALL_APP, true)
.runCommandWithOutputHandling(list);
logger.info("RC for app installs {}", returnCode.getRc());
}
} else {

logger.info(
"Not running inside Docker so skipping automated install process with command.");
}

} else {
if (runningInDocker) {
logger.info("No custom apps to install.");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,4 @@ protected boolean shouldNotFilter(HttpServletRequest request) throws ServletExce

return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package stirling.software.SPDF.controller.api.converters;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;

import stirling.software.SPDF.model.api.GeneralFile;
import stirling.software.SPDF.utils.FileToPdf;
import stirling.software.SPDF.utils.WebResponseUtils;

@RestController
@Tag(name = "Convert", description = "Convert APIs")
@RequestMapping("/api/v1/convert")
public class ConvertBookToPDFController {

@Autowired
@Qualifier("bookFormatsInstalled")
private boolean bookFormatsInstalled;

@PostMapping(consumes = "multipart/form-data", value = "/book/pdf")
@Operation(
summary =
"Convert a BOOK/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx) to PDF",
description =
"(Requires bookFormatsInstalled flag and Calibre installed) This endpoint takes an BOOK/comic (*.epub | *.mobi | *.azw3 | *.fb2 | *.txt | *.docx) input and converts it to PDF format.")
public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute GeneralFile request) throws Exception {
MultipartFile fileInput = request.getFileInput();

if (!bookFormatsInstalled) {
throw new IllegalArgumentException(
"bookFormatsInstalled flag is False, this functionality is not avaiable");
}

if (fileInput == null) {
throw new IllegalArgumentException("Please provide a file for conversion.");
}

String originalFilename = fileInput.getOriginalFilename();

if (originalFilename != null) {
String originalFilenameLower = originalFilename.toLowerCase();
if (!originalFilenameLower.endsWith(".epub")
&& !originalFilenameLower.endsWith(".mobi")
&& !originalFilenameLower.endsWith(".azw3")
&& !originalFilenameLower.endsWith(".fb2")
&& !originalFilenameLower.endsWith(".txt")
&& !originalFilenameLower.endsWith(".docx")) {
throw new IllegalArgumentException(
"File must be in .epub, .mobi, .azw3, .fb2, .txt, or .docx format.");
}
}
byte[] pdfBytes = FileToPdf.convertBookTypeToPdf(fileInput.getBytes(), originalFilename);

String outputFilename =
originalFilename.replaceFirst("[.][^.]+$", "")
+ ".pdf"; // Remove file extension and append .pdf

return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.api.converters;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -19,6 +21,10 @@
@RequestMapping("/api/v1/convert")
public class ConvertHtmlToPDF {

@Autowired
@Qualifier("htmlFormatsInstalled")
private boolean htmlFormatsInstalled;

@PostMapping(consumes = "multipart/form-data", value = "/html/pdf")
@Operation(
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
Expand All @@ -37,7 +43,9 @@ public ResponseEntity<byte[]> HtmlToPdf(@ModelAttribute GeneralFile request) thr
|| (!originalFilename.endsWith(".html") && !originalFilename.endsWith(".zip"))) {
throw new IllegalArgumentException("File must be either .html or .zip format.");
}
byte[] pdfBytes = FileToPdf.convertHtmlToPdf(fileInput.getBytes(), originalFilename);
byte[] pdfBytes =
FileToPdf.convertHtmlToPdf(
fileInput.getBytes(), originalFilename, htmlFormatsInstalled);

String outputFilename =
originalFilename.replaceFirst("[.][^.]+$", "")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -22,6 +24,10 @@
@RequestMapping("/api/v1/convert")
public class ConvertMarkdownToPdf {

@Autowired
@Qualifier("htmlFormatsInstalled")
private boolean htmlFormatsInstalled;

@PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
@Operation(
summary = "Convert a Markdown file to PDF",
Expand All @@ -46,7 +52,9 @@ public ResponseEntity<byte[]> markdownToPdf(@ModelAttribute GeneralFile request)
HtmlRenderer renderer = HtmlRenderer.builder().build();
String htmlContent = renderer.render(document);

byte[] pdfBytes = FileToPdf.convertHtmlToPdf(htmlContent.getBytes(), "converted.html");
byte[] pdfBytes =
FileToPdf.convertHtmlToPdf(
htmlContent.getBytes(), "converted.html", htmlFormatsInstalled);

String outputFilename =
originalFilename.replaceFirst("[.][^.]+$", "")
Expand Down
Loading

0 comments on commit 50ee829

Please sign in to comment.