mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 11:23:10 +02:00
Add zip (#3075)
# Description of Changes - Made a recursive function that checks if a file is a zip, then scans its contents. If the content is a zip, or an accepted file type (non-folder, size > 0), add it and repeat the check for zips - Change all convert fragment to accept application/zip - Slightly modified the input file styling to include an ID for appending the "Extracting" text - Added language translation for the "Extracting..." text - (Edit March 3) Removed recursive function, zip file inside target zip file is excluded - For decrypt function after uploading the file, i reused one webworker to handle the decryption , since in the previous code the workers are created but not detroyed for every single file, this caused a huge slow down for uploading large files due to creation of threads and thus this proposal. - Closes #2951 --- ### General - [ ✅] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [✅ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [✅ ] I have performed a self-review of my own code - [✅ ] My changes generate no new warnings ### UI Changes (if applicable)  Added extracting text (for all language). ### Testing (if applicable) - [ ✅] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details. --------- Co-authored-by: Ludy <[email protected]> Co-authored-by: reecebrowne <[email protected]> Co-authored-by: Reece Browne <[email protected]> Co-authored-by: Anthony Stirling <[email protected]> Co-authored-by: swanemar <[email protected]> Co-authored-by: stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
Ludy
reecebrowne
Reece Browne
Anthony Stirling
swanemar
stirlingbot[bot] <195170888+stirlingbot[bot]@users.noreply.github.com>
parent
b6b49762f6
commit
b0836d0bd7
@@ -1,5 +1,11 @@
|
||||
export class DecryptFile {
|
||||
|
||||
constructor(){
|
||||
this.decryptWorker = null
|
||||
}
|
||||
|
||||
async decryptFile(file, requiresPassword) {
|
||||
|
||||
try {
|
||||
async function getCsrfToken() {
|
||||
const cookieValue = document.cookie
|
||||
@@ -81,12 +87,23 @@ export class DecryptFile {
|
||||
}
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdfjs-legacy/pdf.worker.mjs';
|
||||
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const arrayBufferForPdfLib = arrayBuffer.slice(0);
|
||||
var loadingTask;
|
||||
|
||||
const loadingTask = pdfjsLib.getDocument({
|
||||
data: arrayBuffer,
|
||||
});
|
||||
if(this.decryptWorker == null){
|
||||
loadingTask = pdfjsLib.getDocument({
|
||||
data: arrayBuffer,
|
||||
});
|
||||
this.decryptWorker = loadingTask._worker
|
||||
|
||||
}else {
|
||||
loadingTask = pdfjsLib.getDocument({
|
||||
data: arrayBuffer,
|
||||
worker: this.decryptWorker
|
||||
});
|
||||
}
|
||||
|
||||
await loadingTask.promise;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import FileIconFactory from './file-icon-factory.js';
|
||||
import FileUtils from './file-utils.js';
|
||||
import UUID from './uuid.js';
|
||||
import {DecryptFile} from './DecryptFiles.js';
|
||||
import { DecryptFile } from './DecryptFiles.js';
|
||||
|
||||
let isScriptExecuted = false;
|
||||
if (!isScriptExecuted) {
|
||||
isScriptExecuted = true;
|
||||
@@ -11,6 +12,23 @@ if (!isScriptExecuted) {
|
||||
}
|
||||
let hasDroppedImage = false;
|
||||
|
||||
const zipTypes = [
|
||||
'application/zip',
|
||||
'multipart/x-zip',
|
||||
'application/zip-compressed',
|
||||
'application/x-zip-compressed',
|
||||
];
|
||||
|
||||
const mimeTypes = {
|
||||
"png": "image/png",
|
||||
"jpg": "image/jpeg",
|
||||
"jpeg": "image/jpeg",
|
||||
"gif": "image/gif",
|
||||
"bmp": "image/bmp",
|
||||
"svg": "image/svg+xml",
|
||||
"pdf": "application/pdf",
|
||||
};
|
||||
|
||||
function setupFileInput(chooser) {
|
||||
const elementId = chooser.getAttribute('data-bs-element-id');
|
||||
const filesSelected = chooser.getAttribute('data-bs-files-selected');
|
||||
@@ -55,6 +73,7 @@ function setupFileInput(chooser) {
|
||||
overlay = false;
|
||||
}
|
||||
|
||||
|
||||
const dropListener = function (e) {
|
||||
e.preventDefault();
|
||||
// Drag and Drop shall only affect the target file chooser
|
||||
@@ -83,7 +102,7 @@ function setupFileInput(chooser) {
|
||||
|
||||
dragCounter = 0;
|
||||
|
||||
fileInput.dispatchEvent(new CustomEvent('change', {bubbles: true, detail: {source: 'drag-drop'}}));
|
||||
fileInput.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { source: 'drag-drop' } }));
|
||||
};
|
||||
|
||||
function pushFileListTo(fileList, container) {
|
||||
@@ -114,18 +133,44 @@ function setupFileInput(chooser) {
|
||||
} else {
|
||||
allFiles = Array.from(isDragAndDrop ? allFiles : [element.files[0]]);
|
||||
}
|
||||
|
||||
async function checkZipFile() {
|
||||
|
||||
const promises = allFiles.map(async (file, index) => {
|
||||
try {
|
||||
if (zipTypes.includes(file.type)) {
|
||||
await extractZipFiles(file, element.accept);
|
||||
allFiles.splice(index, 1);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error extracting ZIP file (${file.name}):`, error);
|
||||
allFiles.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
}
|
||||
const originalText = inputContainer.querySelector('#fileInputText').innerHTML;
|
||||
const decryptFile = new DecryptFile();
|
||||
|
||||
inputContainer.querySelector('#fileInputText').innerHTML = window.fileInput.extractPDF;
|
||||
|
||||
await checkZipFile();
|
||||
|
||||
allFiles = await Promise.all(
|
||||
allFiles.map(async (file) => {
|
||||
let decryptedFile = file;
|
||||
|
||||
try {
|
||||
const decryptFile = new DecryptFile();
|
||||
const {isEncrypted, requiresPassword} = await decryptFile.checkFileEncrypted(file);
|
||||
const { isEncrypted, requiresPassword } = await decryptFile.checkFileEncrypted(file);
|
||||
if (file.type === 'application/pdf' && isEncrypted) {
|
||||
decryptedFile = await decryptFile.decryptFile(file, requiresPassword);
|
||||
if (!decryptedFile) throw new Error('File decryption failed.');
|
||||
}
|
||||
decryptedFile.uniqueId = UUID.uuidv4();
|
||||
return decryptedFile;
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error decrypting file: ${file.name}`, error);
|
||||
if (!file.uniqueId) file.uniqueId = UUID.uuidv4();
|
||||
@@ -133,13 +178,15 @@ function setupFileInput(chooser) {
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
inputContainer.querySelector('#fileInputText').innerHTML = originalText;
|
||||
if (!isDragAndDrop) {
|
||||
let dataTransfer = toDataTransfer(allFiles);
|
||||
element.files = dataTransfer.files;
|
||||
}
|
||||
|
||||
handleFileInputChange(this);
|
||||
this.dispatchEvent(new CustomEvent('file-input-change', {bubbles: true, detail: {elementId, allFiles}}));
|
||||
this.dispatchEvent(new CustomEvent('file-input-change', { bubbles: true, detail: { elementId, allFiles } }));
|
||||
});
|
||||
|
||||
function toDataTransfer(files) {
|
||||
@@ -147,17 +194,79 @@ function setupFileInput(chooser) {
|
||||
files.forEach((file) => dataTransfer.items.add(file));
|
||||
return dataTransfer;
|
||||
}
|
||||
|
||||
async function extractZipFiles(zipFile, acceptedFileType) {
|
||||
const jszip = new JSZip();
|
||||
var counter = 0;
|
||||
|
||||
// do an overall count, then proceed to make the pdf files
|
||||
await jszip.loadAsync(zipFile)
|
||||
.then(function (zip) {
|
||||
|
||||
zip.forEach(function (relativePath, zipEntry) {
|
||||
counter+=1;
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
if (counter >= 1000) {
|
||||
throw Error("Maximum file reached");
|
||||
}
|
||||
|
||||
return jszip.loadAsync(zipFile)
|
||||
.then(function (zip) {
|
||||
var extractionPromises = [];
|
||||
|
||||
zip.forEach(function (relativePath, zipEntry) {
|
||||
|
||||
const promise = zipEntry.async('blob').then(function (content) {
|
||||
// Assuming that folders have size zero
|
||||
if (content.size > 0) {
|
||||
const extension = zipEntry.name.split('.').pop().toLowerCase();
|
||||
const mimeType = mimeTypes[extension];
|
||||
|
||||
// Check for file extension
|
||||
if (mimeType && (mimeType.startsWith(acceptedFileType.split('/')[0]) || acceptedFileType === mimeType)) {
|
||||
|
||||
var file = new File([content], zipEntry.name, { type: mimeType });
|
||||
file.uniqueId = UUID.uuidv4();
|
||||
allFiles.push(file);
|
||||
|
||||
} else {
|
||||
console.log(`File ${zipEntry.name} skipped. MIME type (${mimeType}) does not match accepted type (${acceptedFileType})`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
extractionPromises.push(promise);
|
||||
});
|
||||
|
||||
return Promise.all(extractionPromises);
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error("Error extracting ZIP file:", err);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
function handleFileInputChange(inputElement) {
|
||||
|
||||
const files = allFiles;
|
||||
|
||||
showOrHideSelectedFilesContainer(files);
|
||||
|
||||
const filesInfo = files.map((f) => ({
|
||||
name: f.name,
|
||||
size: f.size,
|
||||
uniqueId: f.uniqueId,
|
||||
type: f.type,
|
||||
url: URL.createObjectURL(f),
|
||||
}));
|
||||
const filesInfo = files.map((f) => {
|
||||
|
||||
const url = URL.createObjectURL(f);
|
||||
|
||||
return {
|
||||
name: f.name,
|
||||
size: f.size,
|
||||
uniqueId: f.uniqueId,
|
||||
type: f.type,
|
||||
url: url,
|
||||
};
|
||||
});
|
||||
|
||||
const selectedFilesContainer = $(inputContainer).siblings('.selected-files');
|
||||
selectedFilesContainer.empty();
|
||||
@@ -171,6 +280,8 @@ function setupFileInput(chooser) {
|
||||
let fileIconContainer = document.createElement('div');
|
||||
const isDragAndDropEnabled =
|
||||
window.location.pathname.includes('add-image') || window.location.pathname.includes('sign');
|
||||
|
||||
// add image thumbnail to it
|
||||
if (info.type.startsWith('image/')) {
|
||||
let imgPreview = document.createElement('img');
|
||||
imgPreview.src = info.url;
|
||||
@@ -283,7 +394,7 @@ function setupFileInput(chooser) {
|
||||
|
||||
showOrHideSelectedFilesContainer(allFiles);
|
||||
|
||||
inputElement.dispatchEvent(new CustomEvent('file-input-change', {bubbles: true}));
|
||||
inputElement.dispatchEvent(new CustomEvent('file-input-change', { bubbles: true }));
|
||||
}
|
||||
|
||||
function removeFileById(fileId, inputElement) {
|
||||
|
||||
Reference in New Issue
Block a user