mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-08-02 13:48:15 +02:00
Merge branch 'main' into bug/remember-me
This commit is contained in:
commit
e7356a1d38
@ -210,7 +210,7 @@ Stirling-PDF currently supports 36 languages!
|
|||||||
| Spanish (Español) (es_ES) |  |
|
| Spanish (Español) (es_ES) |  |
|
||||||
| Swedish (Svenska) (sv_SE) |  |
|
| Swedish (Svenska) (sv_SE) |  |
|
||||||
| Thai (ไทย) (th_TH) |  |
|
| Thai (ไทย) (th_TH) |  |
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||||
| Turkish (Türkçe) (tr_TR) |  |
|
| Turkish (Türkçe) (tr_TR) |  |
|
||||||
| Ukrainian (Українська) (uk_UA) |  |
|
| Ukrainian (Українська) (uk_UA) |  |
|
||||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||||
|
@ -47,6 +47,7 @@ public class ApplicationProperties {
|
|||||||
private AutomaticallyGenerated automaticallyGenerated = new AutomaticallyGenerated();
|
private AutomaticallyGenerated automaticallyGenerated = new AutomaticallyGenerated();
|
||||||
private EnterpriseEdition enterpriseEdition = new EnterpriseEdition();
|
private EnterpriseEdition enterpriseEdition = new EnterpriseEdition();
|
||||||
private AutoPipeline autoPipeline = new AutoPipeline();
|
private AutoPipeline autoPipeline = new AutoPipeline();
|
||||||
|
private ProcessExecutor processExecutor = new ProcessExecutor();
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class AutoPipeline {
|
public static class AutoPipeline {
|
||||||
@ -309,4 +310,98 @@ public class ApplicationProperties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ProcessExecutor {
|
||||||
|
private SessionLimit sessionLimit = new SessionLimit();
|
||||||
|
private TimeoutMinutes timeoutMinutes = new TimeoutMinutes();
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class SessionLimit {
|
||||||
|
private int libreOfficeSessionLimit;
|
||||||
|
private int pdfToHtmlSessionLimit;
|
||||||
|
private int ocrMyPdfSessionLimit;
|
||||||
|
private int pythonOpenCvSessionLimit;
|
||||||
|
private int ghostScriptSessionLimit;
|
||||||
|
private int weasyPrintSessionLimit;
|
||||||
|
private int installAppSessionLimit;
|
||||||
|
private int calibreSessionLimit;
|
||||||
|
|
||||||
|
public int getLibreOfficeSessionLimit() {
|
||||||
|
return libreOfficeSessionLimit > 0 ? libreOfficeSessionLimit : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPdfToHtmlSessionLimit() {
|
||||||
|
return pdfToHtmlSessionLimit > 0 ? pdfToHtmlSessionLimit : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOcrMyPdfSessionLimit() {
|
||||||
|
return ocrMyPdfSessionLimit > 0 ? ocrMyPdfSessionLimit : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPythonOpenCvSessionLimit() {
|
||||||
|
return pythonOpenCvSessionLimit > 0 ? pythonOpenCvSessionLimit : 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGhostScriptSessionLimit() {
|
||||||
|
return ghostScriptSessionLimit > 0 ? ghostScriptSessionLimit : 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWeasyPrintSessionLimit() {
|
||||||
|
return weasyPrintSessionLimit > 0 ? weasyPrintSessionLimit : 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInstallAppSessionLimit() {
|
||||||
|
return installAppSessionLimit > 0 ? installAppSessionLimit : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCalibreSessionLimit() {
|
||||||
|
return calibreSessionLimit > 0 ? calibreSessionLimit : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class TimeoutMinutes {
|
||||||
|
private long libreOfficeTimeoutMinutes;
|
||||||
|
private long pdfToHtmlTimeoutMinutes;
|
||||||
|
private long ocrMyPdfTimeoutMinutes;
|
||||||
|
private long pythonOpenCvTimeoutMinutes;
|
||||||
|
private long ghostScriptTimeoutMinutes;
|
||||||
|
private long weasyPrintTimeoutMinutes;
|
||||||
|
private long installAppTimeoutMinutes;
|
||||||
|
private long calibreTimeoutMinutes;
|
||||||
|
|
||||||
|
public long getLibreOfficeTimeoutMinutes() {
|
||||||
|
return libreOfficeTimeoutMinutes > 0 ? libreOfficeTimeoutMinutes : 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPdfToHtmlTimeoutMinutes() {
|
||||||
|
return pdfToHtmlTimeoutMinutes > 0 ? pdfToHtmlTimeoutMinutes : 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getOcrMyPdfTimeoutMinutes() {
|
||||||
|
return ocrMyPdfTimeoutMinutes > 0 ? ocrMyPdfTimeoutMinutes : 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPythonOpenCvTimeoutMinutes() {
|
||||||
|
return pythonOpenCvTimeoutMinutes > 0 ? pythonOpenCvTimeoutMinutes : 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getGhostScriptTimeoutMinutes() {
|
||||||
|
return ghostScriptTimeoutMinutes > 0 ? ghostScriptTimeoutMinutes : 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getWeasyPrintTimeoutMinutes() {
|
||||||
|
return weasyPrintTimeoutMinutes > 0 ? weasyPrintTimeoutMinutes : 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getInstallAppTimeoutMinutes() {
|
||||||
|
return installAppTimeoutMinutes > 0 ? installAppTimeoutMinutes : 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCalibreTimeoutMinutes() {
|
||||||
|
return calibreTimeoutMinutes > 0 ? calibreTimeoutMinutes : 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,14 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import io.github.pixee.security.BoundedLineReader;
|
import io.github.pixee.security.BoundedLineReader;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
public class ProcessExecutor {
|
public class ProcessExecutor {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ProcessExecutor.class);
|
private static final Logger logger = LoggerFactory.getLogger(ProcessExecutor.class);
|
||||||
|
|
||||||
|
private static ApplicationProperties applicationProperties = new ApplicationProperties();
|
||||||
|
|
||||||
public enum Processes {
|
public enum Processes {
|
||||||
LIBRE_OFFICE,
|
LIBRE_OFFICE,
|
||||||
PDFTOHTML,
|
PDFTOHTML,
|
||||||
@ -45,26 +49,90 @@ public class ProcessExecutor {
|
|||||||
key -> {
|
key -> {
|
||||||
int semaphoreLimit =
|
int semaphoreLimit =
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case LIBRE_OFFICE -> 1;
|
case LIBRE_OFFICE ->
|
||||||
case PDFTOHTML -> 1;
|
applicationProperties
|
||||||
case OCR_MY_PDF -> 2;
|
.getProcessExecutor()
|
||||||
case PYTHON_OPENCV -> 8;
|
.getSessionLimit()
|
||||||
case GHOSTSCRIPT -> 16;
|
.getLibreOfficeSessionLimit();
|
||||||
case WEASYPRINT -> 16;
|
case PDFTOHTML ->
|
||||||
case INSTALL_APP -> 1;
|
applicationProperties
|
||||||
case CALIBRE -> 1;
|
.getProcessExecutor()
|
||||||
|
.getSessionLimit()
|
||||||
|
.getPdfToHtmlSessionLimit();
|
||||||
|
case OCR_MY_PDF ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getSessionLimit()
|
||||||
|
.getOcrMyPdfSessionLimit();
|
||||||
|
case PYTHON_OPENCV ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getSessionLimit()
|
||||||
|
.getPythonOpenCvSessionLimit();
|
||||||
|
case GHOSTSCRIPT ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getSessionLimit()
|
||||||
|
.getGhostScriptSessionLimit();
|
||||||
|
case WEASYPRINT ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getSessionLimit()
|
||||||
|
.getWeasyPrintSessionLimit();
|
||||||
|
case INSTALL_APP ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getSessionLimit()
|
||||||
|
.getInstallAppSessionLimit();
|
||||||
|
case CALIBRE ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getSessionLimit()
|
||||||
|
.getCalibreSessionLimit();
|
||||||
};
|
};
|
||||||
|
|
||||||
long timeoutMinutes =
|
long timeoutMinutes =
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case LIBRE_OFFICE -> 30;
|
case LIBRE_OFFICE ->
|
||||||
case PDFTOHTML -> 20;
|
applicationProperties
|
||||||
case OCR_MY_PDF -> 30;
|
.getProcessExecutor()
|
||||||
case PYTHON_OPENCV -> 30;
|
.getTimeoutMinutes()
|
||||||
case GHOSTSCRIPT -> 30;
|
.getLibreOfficeTimeoutMinutes();
|
||||||
case WEASYPRINT -> 30;
|
case PDFTOHTML ->
|
||||||
case INSTALL_APP -> 60;
|
applicationProperties
|
||||||
case CALIBRE -> 30;
|
.getProcessExecutor()
|
||||||
|
.getTimeoutMinutes()
|
||||||
|
.getPdfToHtmlTimeoutMinutes();
|
||||||
|
case OCR_MY_PDF ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getTimeoutMinutes()
|
||||||
|
.getOcrMyPdfTimeoutMinutes();
|
||||||
|
case PYTHON_OPENCV ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getTimeoutMinutes()
|
||||||
|
.getPythonOpenCvTimeoutMinutes();
|
||||||
|
case GHOSTSCRIPT ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getTimeoutMinutes()
|
||||||
|
.getGhostScriptTimeoutMinutes();
|
||||||
|
case WEASYPRINT ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getTimeoutMinutes()
|
||||||
|
.getWeasyPrintTimeoutMinutes();
|
||||||
|
case INSTALL_APP ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getTimeoutMinutes()
|
||||||
|
.getInstallAppTimeoutMinutes();
|
||||||
|
case CALIBRE ->
|
||||||
|
applicationProperties
|
||||||
|
.getProcessExecutor()
|
||||||
|
.getTimeoutMinutes()
|
||||||
|
.getCalibreTimeoutMinutes();
|
||||||
};
|
};
|
||||||
return new ProcessExecutor(semaphoreLimit, liveUpdates, timeoutMinutes);
|
return new ProcessExecutor(semaphoreLimit, liveUpdates, timeoutMinutes);
|
||||||
});
|
});
|
||||||
|
@ -50,4 +50,4 @@ springdoc.swagger-ui.url=/v1/api-docs
|
|||||||
|
|
||||||
|
|
||||||
posthog.api.key=phc_fiR65u5j6qmXTYL56MNrLZSWqLaDW74OrZH0Insd2xq
|
posthog.api.key=phc_fiR65u5j6qmXTYL56MNrLZSWqLaDW74OrZH0Insd2xq
|
||||||
posthog.host=https://eu.i.posthog.com
|
posthog.host=https://eu.i.posthog.com
|
||||||
|
@ -79,8 +79,8 @@ info=資訊
|
|||||||
pro=專業版
|
pro=專業版
|
||||||
page=頁面
|
page=頁面
|
||||||
pages=頁面
|
pages=頁面
|
||||||
loading=Loading...
|
loading=載入中...
|
||||||
addToDoc=Add to Document
|
addToDoc=新增至文件
|
||||||
|
|
||||||
legal.privacy=隱私權政策
|
legal.privacy=隱私權政策
|
||||||
legal.terms=使用條款
|
legal.terms=使用條款
|
||||||
@ -140,7 +140,7 @@ navbar.darkmode=深色模式
|
|||||||
navbar.language=語言
|
navbar.language=語言
|
||||||
navbar.settings=設定
|
navbar.settings=設定
|
||||||
navbar.allTools=工具
|
navbar.allTools=工具
|
||||||
navbar.multiTool=多功能工具
|
navbar.multiTool=複合工具
|
||||||
navbar.sections.organize=整理
|
navbar.sections.organize=整理
|
||||||
navbar.sections.convertTo=轉換為 PDF
|
navbar.sections.convertTo=轉換為 PDF
|
||||||
navbar.sections.convertFrom=從 PDF 轉換
|
navbar.sections.convertFrom=從 PDF 轉換
|
||||||
@ -246,7 +246,7 @@ database.fileNullOrEmpty=檔案不得為空或空白
|
|||||||
database.failedImportFile=匯入檔案失敗
|
database.failedImportFile=匯入檔案失敗
|
||||||
|
|
||||||
session.expired=您的工作階段已過期。請重新整理頁面並再試一次。
|
session.expired=您的工作階段已過期。請重新整理頁面並再試一次。
|
||||||
session.refreshPage=Refresh Page
|
session.refreshPage=重新整理頁面
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# HOME-PAGE #
|
# HOME-PAGE #
|
||||||
@ -751,7 +751,7 @@ certSign.showSig=顯示簽章
|
|||||||
certSign.reason=原因
|
certSign.reason=原因
|
||||||
certSign.location=位置
|
certSign.location=位置
|
||||||
certSign.name=名稱
|
certSign.name=名稱
|
||||||
certSign.showLogo=Show Logo
|
certSign.showLogo=顯示 Logo
|
||||||
certSign.submit=簽章 PDF
|
certSign.submit=簽章 PDF
|
||||||
|
|
||||||
|
|
||||||
@ -786,9 +786,9 @@ compare.highlightColor.2=標示顏色 2:
|
|||||||
compare.document.1=文件 1
|
compare.document.1=文件 1
|
||||||
compare.document.2=文件 2
|
compare.document.2=文件 2
|
||||||
compare.submit=比較
|
compare.submit=比較
|
||||||
compare.complex.message=One or both of the provided documents are large files, accuracy of comparison may be reduced
|
compare.complex.message=選擇的檔案大小太大(其中一個或兩者皆是),可能會影響比較的精確度
|
||||||
compare.large.file.message=One or Both of the provided documents are too large to process
|
compare.large.file.message=選擇的檔案大小超出系統限制(其中一個或兩者皆是),無法處理
|
||||||
compare.no.text.message=One or both of the selected PDFs have no text content. Please choose PDFs with text for comparison.
|
compare.no.text.message=選擇的 PDF 檔案未包含文字(其中一個或兩者皆是)。請選擇含有文字的 PDF 進行比較
|
||||||
|
|
||||||
#BookToPDF
|
#BookToPDF
|
||||||
BookToPDF.title=電子書和漫畫轉 PDF
|
BookToPDF.title=電子書和漫畫轉 PDF
|
||||||
@ -805,17 +805,17 @@ PDFToBook.submit=轉換
|
|||||||
|
|
||||||
#sign
|
#sign
|
||||||
sign.title=簽章
|
sign.title=簽章
|
||||||
sign.header=簽章 PDF
|
sign.header=簽署 PDF
|
||||||
sign.upload=上傳影像
|
sign.upload=上傳影像
|
||||||
sign.draw=繪製簽章
|
sign.draw=繪製簽章
|
||||||
sign.text=文字輸入
|
sign.text=文字輸入
|
||||||
sign.clear=清除
|
sign.clear=清除
|
||||||
sign.add=新增
|
sign.add=新增
|
||||||
sign.saved=Saved Signatures
|
sign.saved=已儲存的簽章
|
||||||
sign.save=Save Signature
|
sign.save=儲存簽章
|
||||||
sign.personalSigs=Personal Signatures
|
sign.personalSigs=個人簽章
|
||||||
sign.sharedSigs=Shared Signatures
|
sign.sharedSigs=共用簽章
|
||||||
sign.noSavedSigs=No saved signatures found
|
sign.noSavedSigs=尚未儲存任何簽章
|
||||||
|
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
|
@ -102,3 +102,22 @@ metrics:
|
|||||||
AutomaticallyGenerated:
|
AutomaticallyGenerated:
|
||||||
key: example
|
key: example
|
||||||
UUID: example
|
UUID: example
|
||||||
|
|
||||||
|
processExecutor:
|
||||||
|
sessionLimit: # Process executor instances limits
|
||||||
|
libreOfficeSessionLimit: 1
|
||||||
|
pdfToHtmlSessionLimit: 1
|
||||||
|
ocrMyPdfSessionLimit: 2
|
||||||
|
pythonOpenCvSessionLimit: 8
|
||||||
|
ghostScriptSessionLimit: 16
|
||||||
|
weasyPrintSessionLimit: 16
|
||||||
|
installAppSessionLimit: 1
|
||||||
|
calibreSessionLimit: 1
|
||||||
|
timeoutMinutes: # Process executor timeout in minutes
|
||||||
|
libreOfficetimeoutMinutes: 30
|
||||||
|
pdfToHtmltimeoutMinutes: 20
|
||||||
|
pythonOpenCvtimeoutMinutes: 30
|
||||||
|
ghostScripttimeoutMinutes: 30
|
||||||
|
weasyPrinttimeoutMinutes: 30
|
||||||
|
installApptimeoutMinutes: 60
|
||||||
|
calibretimeoutMinutes: 30
|
||||||
|
@ -21,27 +21,55 @@ async function displayFiles(files) {
|
|||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
const pageCount = await getPDFPageCount(files[i]);
|
const pageCount = await getPDFPageCount(files[i]);
|
||||||
const pageLabel = pageCount === 1 ? pageTranslation : pagesTranslation;
|
const pageLabel = pageCount === 1 ? pageTranslation : pagesTranslation;
|
||||||
|
|
||||||
|
// Create list item
|
||||||
const item = document.createElement("li");
|
const item = document.createElement("li");
|
||||||
item.className = "list-group-item";
|
item.className = "list-group-item";
|
||||||
item.innerHTML = `
|
|
||||||
<div class="d-flex justify-content-between align-items-center w-100">
|
// Create filename div and set textContent to sanitize
|
||||||
<div class="filename">${files[i].name}</div>
|
const fileNameDiv = document.createElement("div");
|
||||||
<div class="page-info">
|
fileNameDiv.className = "filename";
|
||||||
<span class="page-count">${pageCount} ${pageLabel}</span>
|
fileNameDiv.textContent = files[i].name;
|
||||||
</div>
|
|
||||||
<div class="arrows d-flex">
|
// Create page info div and set textContent to sanitize
|
||||||
<button class="btn btn-secondary move-up"><span>↑</span></button>
|
const pageInfoDiv = document.createElement("div");
|
||||||
<button class="btn btn-secondary move-down"><span>↓</span></button>
|
pageInfoDiv.className = "page-info";
|
||||||
<button class="btn btn-danger remove-file"><span>×</span></button>
|
const pageCountSpan = document.createElement("span");
|
||||||
</div>
|
pageCountSpan.className = "page-count";
|
||||||
</div>
|
pageCountSpan.textContent = `${pageCount} ${pageLabel}`;
|
||||||
`;
|
pageInfoDiv.appendChild(pageCountSpan);
|
||||||
|
|
||||||
|
// Create arrows div with buttons
|
||||||
|
const arrowsDiv = document.createElement("div");
|
||||||
|
arrowsDiv.className = "arrows d-flex";
|
||||||
|
|
||||||
|
const moveUpButton = document.createElement("button");
|
||||||
|
moveUpButton.className = "btn btn-secondary move-up";
|
||||||
|
moveUpButton.innerHTML = "<span>↑</span>";
|
||||||
|
|
||||||
|
const moveDownButton = document.createElement("button");
|
||||||
|
moveDownButton.className = "btn btn-secondary move-down";
|
||||||
|
moveDownButton.innerHTML = "<span>↓</span>";
|
||||||
|
|
||||||
|
const removeButton = document.createElement("button");
|
||||||
|
removeButton.className = "btn btn-danger remove-file";
|
||||||
|
removeButton.innerHTML = "<span>×</span>";
|
||||||
|
|
||||||
|
arrowsDiv.append(moveUpButton, moveDownButton, removeButton);
|
||||||
|
|
||||||
|
// Append elements to item and then to list
|
||||||
|
const itemContainer = document.createElement("div");
|
||||||
|
itemContainer.className = "d-flex justify-content-between align-items-center w-100";
|
||||||
|
itemContainer.append(fileNameDiv, pageInfoDiv, arrowsDiv);
|
||||||
|
|
||||||
|
item.appendChild(itemContainer);
|
||||||
list.appendChild(item);
|
list.appendChild(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
attachMoveButtons();
|
attachMoveButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function getPDFPageCount(file) {
|
async function getPDFPageCount(file) {
|
||||||
const blobUrl = URL.createObjectURL(file);
|
const blobUrl = URL.createObjectURL(file);
|
||||||
const pdf = await pdfjsLib.getDocument(blobUrl).promise;
|
const pdf = await pdfjsLib.getDocument(blobUrl).promise;
|
||||||
|
Loading…
Reference in New Issue
Block a user