Compare commits
34 Commits
bug/rememb
...
Frooodle-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d19d87b8f0 | ||
|
|
a22ce69bc3 | ||
|
|
59b60ebfb8 | ||
|
|
a6ae3734ca | ||
|
|
b9a014b5c7 | ||
|
|
9e30918aae | ||
|
|
c239d95131 | ||
|
|
d591874da6 | ||
|
|
6c623d8d84 | ||
|
|
e059caa14e | ||
|
|
8eab35761d | ||
|
|
c43af24ffe | ||
|
|
e1b3cc736c | ||
|
|
0fb9e18636 | ||
|
|
5e1aac0b84 | ||
|
|
60bf649260 | ||
|
|
a58696a38e | ||
|
|
44abc67678 | ||
|
|
d1e690ff8d | ||
|
|
5dc8fa08ee | ||
|
|
db028dfe27 | ||
|
|
c24c504350 | ||
|
|
5dcfe64d1c | ||
|
|
d843696703 | ||
|
|
67de8a9460 | ||
|
|
b26aa3417e | ||
|
|
8dfb5940ca | ||
|
|
0ce479e1e3 | ||
|
|
cca3b6b525 | ||
|
|
03529567ba | ||
|
|
781a52c759 | ||
|
|
be2c103065 | ||
|
|
80fd2eff5f | ||
|
|
65abfd9c7a |
179
.github/workflows/PR-Demo-Comment.yml
vendored
Normal file
179
.github/workflows/PR-Demo-Comment.yml
vendored
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
name: PR Deployment via Comment
|
||||||
|
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-comment:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: |
|
||||||
|
github.event.issue.pull_request &&
|
||||||
|
(
|
||||||
|
contains(github.event.comment.body, 'prdeploy') ||
|
||||||
|
contains(github.event.comment.body, 'deploypr')
|
||||||
|
)
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
github.event.comment.user.login == 'frooodle' ||
|
||||||
|
github.event.comment.user.login == 'sf298' ||
|
||||||
|
github.event.comment.user.login == 'Ludy87' ||
|
||||||
|
github.event.comment.user.login == 'LaserKaspar' ||
|
||||||
|
github.event.comment.user.login == 'sbplat' ||
|
||||||
|
github.event.comment.user.login == 'reecebrowne'
|
||||||
|
)
|
||||||
|
outputs:
|
||||||
|
pr_number: ${{ steps.get-pr.outputs.pr_number }}
|
||||||
|
pr_repository: ${{ steps.get-pr-info.outputs.repository }}
|
||||||
|
pr_ref: ${{ steps.get-pr-info.outputs.ref }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Get PR data
|
||||||
|
id: get-pr
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const prNumber = context.payload.issue.number;
|
||||||
|
console.log(`PR Number: ${prNumber}`);
|
||||||
|
core.setOutput('pr_number', prNumber);
|
||||||
|
|
||||||
|
- name: Get PR repository and ref
|
||||||
|
id: get-pr-info
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { owner, repo } = context.repo;
|
||||||
|
const prNumber = context.payload.issue.number;
|
||||||
|
|
||||||
|
const { data: pr } = await github.rest.pulls.get({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
pull_number: prNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
// For forks, use the full repository name, for internal PRs use the current repo
|
||||||
|
const repository = pr.head.repo.fork ? pr.head.repo.full_name : `${owner}/${repo}`;
|
||||||
|
|
||||||
|
console.log(`PR Repository: ${repository}`);
|
||||||
|
console.log(`PR Branch: ${pr.head.ref}`);
|
||||||
|
|
||||||
|
core.setOutput('repository', repository);
|
||||||
|
core.setOutput('ref', pr.head.ref);
|
||||||
|
|
||||||
|
deploy-pr:
|
||||||
|
needs: check-comment
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout PR
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: ${{ needs.check-comment.outputs.pr_repository }}
|
||||||
|
ref: ${{ needs.check-comment.outputs.pr_ref }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Set up JDK
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: '17'
|
||||||
|
distribution: 'temurin'
|
||||||
|
|
||||||
|
- name: Run Gradle Command
|
||||||
|
run: ./gradlew clean build
|
||||||
|
env:
|
||||||
|
DOCKER_ENABLE_SECURITY: false
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Get version number
|
||||||
|
id: versionNumber
|
||||||
|
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_HUB_API }}
|
||||||
|
|
||||||
|
- name: Build and push PR-specific image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
push: true
|
||||||
|
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }}
|
||||||
|
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
||||||
|
platforms: linux/amd64
|
||||||
|
|
||||||
|
- name: Set up SSH
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh/
|
||||||
|
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
|
||||||
|
sudo chmod 600 ../private.key
|
||||||
|
|
||||||
|
- name: Deploy to VPS
|
||||||
|
run: |
|
||||||
|
# First create the docker-compose content locally
|
||||||
|
cat > docker-compose.yml << 'EOF'
|
||||||
|
version: '3.3'
|
||||||
|
services:
|
||||||
|
stirling-pdf:
|
||||||
|
container_name: stirling-pdf-pr-${{ needs.check-comment.outputs.pr_number }}
|
||||||
|
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }}
|
||||||
|
ports:
|
||||||
|
- "${{ needs.check-comment.outputs.pr_number }}:8080"
|
||||||
|
volumes:
|
||||||
|
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/data:/usr/share/tessdata:rw
|
||||||
|
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/config:/configs:rw
|
||||||
|
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/logs:/logs:rw
|
||||||
|
environment:
|
||||||
|
DOCKER_ENABLE_SECURITY: "false"
|
||||||
|
SECURITY_ENABLELOGIN: "false"
|
||||||
|
SYSTEM_DEFAULTLOCALE: en-GB
|
||||||
|
UI_APPNAME: "Stirling-PDF PR#${{ needs.check-comment.outputs.pr_number }}"
|
||||||
|
UI_HOMEDESCRIPTION: "PR#${{ needs.check-comment.outputs.pr_number }} for Stirling-PDF Latest"
|
||||||
|
UI_APPNAMENAVBAR: "PR#${{ needs.check-comment.outputs.pr_number }}"
|
||||||
|
SYSTEM_MAXFILESIZE: "100"
|
||||||
|
METRICS_ENABLED: "true"
|
||||||
|
SYSTEM_GOOGLEVISIBILITY: "false"
|
||||||
|
restart: on-failure:5
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Then copy the file and execute commands
|
||||||
|
scp -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null docker-compose.yml ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }}:/tmp/docker-compose.yml
|
||||||
|
|
||||||
|
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
|
||||||
|
# Create PR-specific directories
|
||||||
|
mkdir -p /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/{data,config,logs}
|
||||||
|
|
||||||
|
# Move docker-compose file to correct location
|
||||||
|
mv /tmp/docker-compose.yml /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/docker-compose.yml
|
||||||
|
|
||||||
|
# Start or restart the container
|
||||||
|
cd /stirling/PR-${{ needs.check-comment.outputs.pr_number }}
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
ENDSSH
|
||||||
|
|
||||||
|
- name: Post deployment URL to PR
|
||||||
|
if: success()
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { GITHUB_REPOSITORY } = process.env;
|
||||||
|
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
|
||||||
|
const prNumber = ${{ needs.check-comment.outputs.pr_number }};
|
||||||
|
|
||||||
|
const deploymentUrl = `http://${{ secrets.VPS_HOST }}:${prNumber}`;
|
||||||
|
const commentBody = `## 🚀 PR Test Deployment\n\n` +
|
||||||
|
`Your PR has been deployed for testing!\n\n` +
|
||||||
|
`🔗 **Test URL:** [${deploymentUrl}](${deploymentUrl})\n\n` +
|
||||||
|
`This deployment will be automatically cleaned up when the PR is closed.\n\n`;
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: repoOwner,
|
||||||
|
repo: repoName,
|
||||||
|
issue_number: prNumber,
|
||||||
|
body: commentBody
|
||||||
|
});
|
||||||
78
.github/workflows/PR-Demo-cleanup.yml
vendored
Normal file
78
.github/workflows/PR-Demo-cleanup.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
name: PR Deployment cleanup
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened, closed]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
SERVER_IP: ${{ secrets.VPS_IP }} # Add this to your GitHub secrets
|
||||||
|
CLEANUP_PERFORMED: 'false' # Add flag to track if cleanup occurred
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cleanup:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.action == 'closed'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set up SSH
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh/
|
||||||
|
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
|
||||||
|
sudo chmod 600 ../private.key
|
||||||
|
|
||||||
|
- name: Cleanup PR deployment
|
||||||
|
id: cleanup
|
||||||
|
run: |
|
||||||
|
CLEANUP_STATUS=$(ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
|
||||||
|
if [ -d "/stirling/PR-${{ github.event.pull_request.number }}" ]; then
|
||||||
|
echo "Found PR directory, proceeding with cleanup..."
|
||||||
|
|
||||||
|
# Stop and remove containers
|
||||||
|
cd /stirling/PR-${{ github.event.pull_request.number }}
|
||||||
|
docker-compose down || true
|
||||||
|
|
||||||
|
# Go back to root before removal
|
||||||
|
cd /
|
||||||
|
|
||||||
|
# Remove PR-specific directories
|
||||||
|
rm -rf /stirling/PR-${{ github.event.pull_request.number }}
|
||||||
|
|
||||||
|
# Remove the Docker image
|
||||||
|
docker rmi --no-prune ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ github.event.pull_request.number }} || true
|
||||||
|
|
||||||
|
echo "PERFORMED_CLEANUP"
|
||||||
|
else
|
||||||
|
echo "PR directory not found, nothing to clean up"
|
||||||
|
echo "NO_CLEANUP_NEEDED"
|
||||||
|
fi
|
||||||
|
ENDSSH
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ $CLEANUP_STATUS == *"PERFORMED_CLEANUP"* ]]; then
|
||||||
|
echo "cleanup_performed=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "cleanup_performed=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Post cleanup notice to PR
|
||||||
|
if: steps.cleanup.outputs.cleanup_performed == 'true'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { GITHUB_REPOSITORY } = process.env;
|
||||||
|
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
|
||||||
|
const prNumber = context.issue.number;
|
||||||
|
|
||||||
|
const commentBody = `## 🧹 Deployment Cleanup\n\n` +
|
||||||
|
`The test deployment for this PR has been cleaned up.`;
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: repoOwner,
|
||||||
|
repo: repoName,
|
||||||
|
issue_number: prNumber,
|
||||||
|
body: commentBody
|
||||||
|
});
|
||||||
52
.github/workflows/check_properties.yml
vendored
52
.github/workflows/check_properties.yml
vendored
@@ -9,6 +9,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "src/main/resources/messages_en_GB.properties"
|
- "src/main/resources/messages_en_GB.properties"
|
||||||
|
|
||||||
|
# Permissions required for the workflow
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
@@ -18,6 +19,13 @@ jobs:
|
|||||||
if: github.event_name == 'pull_request_target'
|
if: github.event_name == 'pull_request_target'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Checkout main branch first
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: main
|
||||||
|
path: main-branch
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Checkout PR branch
|
- name: Checkout PR branch
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -26,13 +34,6 @@ jobs:
|
|||||||
path: pr-branch
|
path: pr-branch
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Checkout main branch
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
path: main-branch
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
@@ -49,34 +50,46 @@ jobs:
|
|||||||
echo "Fetching PR changed files..."
|
echo "Fetching PR changed files..."
|
||||||
cd pr-branch
|
cd pr-branch
|
||||||
gh repo set-default ${{ github.repository }}
|
gh repo set-default ${{ github.repository }}
|
||||||
gh pr view ${{ github.event.pull_request.number }} --json files -q ".files[].path" > ../changed_files.txt
|
# Store files in a safe way, only allowing valid properties files
|
||||||
|
echo "Getting list of changed files from PR..."
|
||||||
|
gh pr view ${{ github.event.pull_request.number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]+\.properties$' > ../changed_files.txt
|
||||||
cd ..
|
cd ..
|
||||||
echo $(cat changed_files.txt)
|
echo "Setting branch path..."
|
||||||
BRANCH_PATH="pr-branch"
|
BRANCH_PATH="pr-branch"
|
||||||
|
|
||||||
echo "BRANCH_PATH=${BRANCH_PATH}" >> $GITHUB_ENV
|
echo "BRANCH_PATH=${BRANCH_PATH}" >> $GITHUB_ENV
|
||||||
CHANGED_FILES=$(cat changed_files.txt | tr '\n' ' ')
|
echo "Processing changed files..."
|
||||||
echo "CHANGED_FILES=${CHANGED_FILES}" >> $GITHUB_ENV
|
mapfile -t CHANGED_FILES < changed_files.txt
|
||||||
echo "Changed files: ${CHANGED_FILES}"
|
|
||||||
|
CHANGED_FILES_STR="${CHANGED_FILES[*]}"
|
||||||
|
echo "CHANGED_FILES=${CHANGED_FILES_STR}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
echo "Changed files: ${CHANGED_FILES_STR}"
|
||||||
echo "Branch: ${BRANCH_PATH}"
|
echo "Branch: ${BRANCH_PATH}"
|
||||||
|
|
||||||
- name: Determine reference file
|
- name: Determine reference file
|
||||||
id: determine-file
|
id: determine-file
|
||||||
run: |
|
run: |
|
||||||
echo "Determining reference file..."
|
echo "Determining reference file..."
|
||||||
if echo "${{ env.CHANGED_FILES }}" | grep -q 'src/main/resources/messages_en_GB.properties'; then
|
if grep -Fxq "src/main/resources/messages_en_GB.properties" changed_files.txt; then
|
||||||
|
echo "Using PR branch reference file"
|
||||||
echo "REFERENCE_FILE=pr-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV
|
echo "REFERENCE_FILE=pr-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV
|
||||||
else
|
else
|
||||||
|
echo "Using main branch reference file"
|
||||||
echo "REFERENCE_FILE=main-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV
|
echo "REFERENCE_FILE=main-branch/src/main/resources/messages_en_GB.properties" >> $GITHUB_ENV
|
||||||
fi
|
fi
|
||||||
echo "REFERENCE_FILE=${{ env.REFERENCE_FILE }}"
|
|
||||||
|
|
||||||
- name: Show REFERENCE_FILE
|
- name: Show REFERENCE_FILE
|
||||||
run: echo "Reference file is set to ${{ env.REFERENCE_FILE }}"
|
run: echo "Reference file is set to ${REFERENCE_FILE}"
|
||||||
|
|
||||||
- name: Run Python script to check files
|
- name: Run Python script to check files
|
||||||
id: run-check
|
id: run-check
|
||||||
run: |
|
run: |
|
||||||
python main-branch/.github/scripts/check_language_properties.py --reference-file ${{ env.REFERENCE_FILE }} --branch ${{ env.BRANCH_PATH }} --files ${{ env.CHANGED_FILES }} > failure.txt || true
|
echo "Running Python script to check files..."
|
||||||
|
python main-branch/.github/scripts/check_language_properties.py \
|
||||||
|
--reference-file "${REFERENCE_FILE}" \
|
||||||
|
--branch "${BRANCH_PATH}" \
|
||||||
|
--files ${CHANGED_FILES} > failure.txt || true
|
||||||
|
|
||||||
- name: Capture output
|
- name: Capture output
|
||||||
id: capture-output
|
id: capture-output
|
||||||
@@ -87,7 +100,7 @@ jobs:
|
|||||||
echo "ERROR_OUTPUT<<EOF" >> $GITHUB_ENV
|
echo "ERROR_OUTPUT<<EOF" >> $GITHUB_ENV
|
||||||
echo "$ERROR_OUTPUT" >> $GITHUB_ENV
|
echo "$ERROR_OUTPUT" >> $GITHUB_ENV
|
||||||
echo "EOF" >> $GITHUB_ENV
|
echo "EOF" >> $GITHUB_ENV
|
||||||
echo $ERROR_OUTPUT
|
echo "${ERROR_OUTPUT}"
|
||||||
else
|
else
|
||||||
echo "No errors found."
|
echo "No errors found."
|
||||||
echo "ERROR_OUTPUT=" >> $GITHUB_ENV
|
echo "ERROR_OUTPUT=" >> $GITHUB_ENV
|
||||||
@@ -169,7 +182,10 @@ jobs:
|
|||||||
- name: Run Python script to check files
|
- name: Run Python script to check files
|
||||||
id: run-check
|
id: run-check
|
||||||
run: |
|
run: |
|
||||||
python .github/scripts/check_language_properties.py --reference-file src/main/resources/messages_en_GB.properties --branch main
|
echo "Running Python script to check files..."
|
||||||
|
python .github/scripts/check_language_properties.py \
|
||||||
|
--reference-file src/main/resources/messages_en_GB.properties \
|
||||||
|
--branch main
|
||||||
|
|
||||||
- name: Set up git config
|
- name: Set up git config
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
3
.github/workflows/push-docker.yml
vendored
3
.github/workflows/push-docker.yml
vendored
@@ -67,6 +67,7 @@ jobs:
|
|||||||
images: |
|
images: |
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||||
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }},enable=${{ github.ref == 'refs/heads/master' }}
|
||||||
@@ -95,6 +96,7 @@ jobs:
|
|||||||
images: |
|
images: |
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||||
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-ultra-lite,enable=${{ github.ref == 'refs/heads/master' }}
|
||||||
@@ -122,6 +124,7 @@ jobs:
|
|||||||
images: |
|
images: |
|
||||||
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
${{ secrets.DOCKER_HUB_USERNAME }}/s-pdf
|
||||||
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/s-pdf
|
||||||
|
ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf
|
||||||
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
${{ secrets.DOCKER_HUB_ORG_USERNAME }}/stirling-pdf
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat,enable=${{ github.ref == 'refs/heads/master' }}
|
type=raw,value=${{ steps.versionNumber.outputs.versionNumber }}-fat,enable=${{ github.ref == 'refs/heads/master' }}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ These files provide pre-configured setups for different scenarios. For example,
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security
|
container_name: Stirling-PDF-Security
|
||||||
image: frooodle/s-pdf:latest
|
image: stirlingtools/stirling-pdf:latest
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
@@ -173,20 +173,20 @@ Stirling-PDF uses different Docker images for various configurations. The build
|
|||||||
For the latest version:
|
For the latest version:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
|
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest -f ./Dockerfile .
|
||||||
```
|
```
|
||||||
|
|
||||||
For the ultra-lite version:
|
For the ultra-lite version:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
|
||||||
```
|
```
|
||||||
|
|
||||||
For the fat version (with security enabled):
|
For the fat version (with security enabled):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export DOCKER_ENABLE_SECURITY=true
|
export DOCKER_ENABLE_SECURITY=true
|
||||||
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-fat -f ./Dockerfile-fat .
|
docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-fat -f ./Dockerfile-fat .
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: The `--no-cache` and `--pull` flags ensure that the build process uses the latest base images and doesn't use cached layers, which is useful for testing and ensuring reproducible builds. however to improve build times these can often be removed depending on your usecase
|
Note: The `--no-cache` and `--pull` flags ensure that the build process uses the latest base images and doesn't use cached layers, which is useful for testing and ensuring reproducible builds. however to improve build times these can often be removed depending on your usecase
|
||||||
|
|||||||
45
Jenkinsfile
vendored
45
Jenkinsfile
vendored
@@ -1,45 +0,0 @@
|
|||||||
pipeline {
|
|
||||||
agent any
|
|
||||||
stages {
|
|
||||||
stage('Build') {
|
|
||||||
steps {
|
|
||||||
sh 'chmod 755 gradlew'
|
|
||||||
sh './gradlew build'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Docker Build') {
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
def appVersion = sh(returnStdout: true, script: './gradlew printVersion -q').trim()
|
|
||||||
def image = "frooodle/s-pdf:$appVersion"
|
|
||||||
sh "docker build -t $image ."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Docker Push') {
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
def appVersion = sh(returnStdout: true, script: './gradlew printVersion -q').trim()
|
|
||||||
def image = "frooodle/s-pdf:$appVersion"
|
|
||||||
withCredentials([string(credentialsId: 'docker_hub_access_token', variable: 'DOCKER_HUB_ACCESS_TOKEN')]) {
|
|
||||||
sh "docker login --username frooodle --password $DOCKER_HUB_ACCESS_TOKEN"
|
|
||||||
sh "docker push $image"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Helm Push') {
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
//TODO: Read chartVersion from Chart.yaml
|
|
||||||
def chartVersion = '1.0.0'
|
|
||||||
withCredentials([string(credentialsId: 'docker_hub_access_token', variable: 'DOCKER_HUB_ACCESS_TOKEN')]) {
|
|
||||||
sh "docker login --username frooodle --password $DOCKER_HUB_ACCESS_TOKEN"
|
|
||||||
sh "helm package chart/stirling-pdf"
|
|
||||||
sh "helm push stirling-pdf-chart-1.0.0.tgz oci://registry-1.docker.io/frooodle"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
38
README.md
38
README.md
@@ -120,13 +120,13 @@ Please view the [LocalRunGuide](https://github.com/Stirling-Tools/Stirling-PDF/b
|
|||||||
### Docker / Podman
|
### Docker / Podman
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> <https://hub.docker.com/r/frooodle/s-pdf>
|
> <https://hub.docker.com/r/stirlingtools/stirling-pdf>
|
||||||
|
|
||||||
Stirling-PDF has three different versions: a full version, an ultra-lite version, and a 'fat' version. Depending on the types of features you use, you may want a smaller image to save on space. To see what the different versions offer, please look at our [version mapping](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Version-groups.md). For people that don't mind space optimization, just use the latest tag.
|
Stirling-PDF has three different versions: a full version, an ultra-lite version, and a 'fat' version. Depending on the types of features you use, you may want a smaller image to save on space. To see what the different versions offer, please look at our [version mapping](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/Version-groups.md). For people that don't mind space optimization, just use the latest tag.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
Please note in the examples below, you may need to change the volume paths as needed, e.g., `./extraConfigs:/configs` to `/opt/stirlingpdf/extraConfigs:/configs`.
|
Please note in the examples below, you may need to change the volume paths as needed, e.g., `./extraConfigs:/configs` to `/opt/stirlingpdf/extraConfigs:/configs`.
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ docker run -d \
|
|||||||
-e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
|
-e INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
|
||||||
-e LANGS=en_GB \
|
-e LANGS=en_GB \
|
||||||
--name stirling-pdf \
|
--name stirling-pdf \
|
||||||
frooodle/s-pdf:latest
|
stirlingtools/stirling-pdf:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Docker Compose
|
### Docker Compose
|
||||||
@@ -153,7 +153,7 @@ docker run -d \
|
|||||||
version: '3.3'
|
version: '3.3'
|
||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
image: frooodle/s-pdf:latest
|
image: stirlingtools/stirling-pdf:latest
|
||||||
ports:
|
ports:
|
||||||
- '8080:8080'
|
- '8080:8080'
|
||||||
volumes:
|
volumes:
|
||||||
@@ -190,29 +190,29 @@ Stirling-PDF currently supports 36 languages!
|
|||||||
|
|
||||||
| Language | Progress |
|
| Language | Progress |
|
||||||
| -------------------------------------------- | -------------------------------------- |
|
| -------------------------------------------- | -------------------------------------- |
|
||||||
| Arabic (العربية) (ar_AR) |  |
|
| Arabic (العربية) (ar_AR) |  |
|
||||||
| Basque (Euskara) (eu_ES) |  |
|
| Basque (Euskara) (eu_ES) |  |
|
||||||
| Bulgarian (Български) (bg_BG) |  |
|
| Bulgarian (Български) (bg_BG) |  |
|
||||||
| Catalan (Català) (ca_CA) |  |
|
| Catalan (Català) (ca_CA) |  |
|
||||||
| Croatian (Hrvatski) (hr_HR) |  |
|
| Croatian (Hrvatski) (hr_HR) |  |
|
||||||
| Czech (Česky) (cs_CZ) |  |
|
| Czech (Česky) (cs_CZ) |  |
|
||||||
| Danish (Dansk) (da_DK) |  |
|
| Danish (Dansk) (da_DK) |  |
|
||||||
| Dutch (Nederlands) (nl_NL) |  |
|
| Dutch (Nederlands) (nl_NL) |  |
|
||||||
| English (English) (en_GB) |  |
|
| English (English) (en_GB) |  |
|
||||||
| English (US) (en_US) |  |
|
| English (US) (en_US) |  |
|
||||||
| French (Français) (fr_FR) |  |
|
| French (Français) (fr_FR) |  |
|
||||||
| German (Deutsch) (de_DE) |  |
|
| German (Deutsch) (de_DE) |  |
|
||||||
| Greek (Ελληνικά) (el_GR) |  |
|
| Greek (Ελληνικά) (el_GR) |  |
|
||||||
| Hindi (हिंदी) (hi_IN) |  |
|
| Hindi (हिंदी) (hi_IN) |  |
|
||||||
| Hungarian (Magyar) (hu_HU) |  |
|
| Hungarian (Magyar) (hu_HU) |  |
|
||||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||||
| Irish (Gaeilge) (ga_IE) |  |
|
| Irish (Gaeilge) (ga_IE) |  |
|
||||||
| Italian (Italiano) (it_IT) |  |
|
| Italian (Italiano) (it_IT) |  |
|
||||||
| Japanese (日本語) (ja_JP) |  |
|
| Japanese (日本語) (ja_JP) |  |
|
||||||
| Korean (한국어) (ko_KR) |  |
|
| Korean (한국어) (ko_KR) |  |
|
||||||
| Norwegian (Norsk) (no_NB) |  |
|
| Norwegian (Norsk) (no_NB) |  |
|
||||||
| Polish (Polski) (pl_PL) |  |
|
| Polish (Polski) (pl_PL) |  |
|
||||||
| Portuguese (Português) (pt_PT) |  |
|
| Portuguese (Português) (pt_PT) |  |
|
||||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||||
| Romanian (Română) (ro_RO) |  |
|
| Romanian (Română) (ro_RO) |  |
|
||||||
| Russian (Русский) (ru_RU) |  |
|
| Russian (Русский) (ru_RU) |  |
|
||||||
@@ -225,7 +225,7 @@ Stirling-PDF currently supports 36 languages!
|
|||||||
| 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) |  |
|
||||||
|
|
||||||
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
## Contributing (Creating Issues, Translations, Fixing Bugs, etc.)
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ plugins {
|
|||||||
//id "nebula.lint" version "19.0.3"
|
//id "nebula.lint" version "19.0.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import com.github.jk1.license.render.*
|
import com.github.jk1.license.render.*
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
@@ -17,12 +19,12 @@ ext {
|
|||||||
pdfboxVersion = "3.0.3"
|
pdfboxVersion = "3.0.3"
|
||||||
logbackVersion = "1.5.7"
|
logbackVersion = "1.5.7"
|
||||||
imageioVersion = "3.12.0"
|
imageioVersion = "3.12.0"
|
||||||
lombokVersion = "1.18.34"
|
lombokVersion = "1.18.36"
|
||||||
bouncycastleVersion = "1.78.1"
|
bouncycastleVersion = "1.78.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "stirling.software"
|
group = "stirling.software"
|
||||||
version = "0.32.0"
|
version = "0.33.1"
|
||||||
|
|
||||||
java {
|
java {
|
||||||
// 17 is lowest but we support and recommend 21
|
// 17 is lowest but we support and recommend 21
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security-Fat
|
container_name: Stirling-PDF-Security-Fat
|
||||||
image: frooodle/s-pdf:latest-fat
|
image: stirlingtools/stirling-pdf:latest-fat
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security
|
container_name: Stirling-PDF-Security
|
||||||
image: frooodle/s-pdf:latest
|
image: stirlingtools/stirling-pdf:latest
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security
|
container_name: Stirling-PDF-Security
|
||||||
image: frooodle/s-pdf:latest
|
image: stirlingtools/stirling-pdf:latest
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Ultra-Lite-Security
|
container_name: Stirling-PDF-Ultra-Lite-Security
|
||||||
image: frooodle/s-pdf:latest-ultra-lite
|
image: stirlingtools/stirling-pdf:latest-ultra-lite
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Ultra-Lite
|
container_name: Stirling-PDF-Ultra-Lite
|
||||||
image: frooodle/s-pdf:latest-ultra-lite
|
image: stirlingtools/stirling-pdf:latest-ultra-lite
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF
|
container_name: Stirling-PDF
|
||||||
image: frooodle/s-pdf:latest
|
image: stirlingtools/stirling-pdf:latest
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ ignore = [
|
|||||||
ignore = [
|
ignore = [
|
||||||
'AddStampRequest.alphabet',
|
'AddStampRequest.alphabet',
|
||||||
'AddStampRequest.position',
|
'AddStampRequest.position',
|
||||||
'home.pipeline.title'
|
|
||||||
'PDFToBook.selectText.1',
|
'PDFToBook.selectText.1',
|
||||||
'PDFToText.tags',
|
'PDFToText.tags',
|
||||||
'addPageNumbers.selectText.3',
|
'addPageNumbers.selectText.3',
|
||||||
'alphabet',
|
'alphabet',
|
||||||
'certSign.name',
|
'certSign.name',
|
||||||
|
'home.pipeline.title',
|
||||||
'language.direction',
|
'language.direction',
|
||||||
'licenses.version',
|
'licenses.version',
|
||||||
'pipeline.title',
|
'pipeline.title',
|
||||||
@@ -46,7 +46,6 @@ ignore = [
|
|||||||
'sponsor',
|
'sponsor',
|
||||||
'text',
|
'text',
|
||||||
'watermark.type.1',
|
'watermark.type.1',
|
||||||
'certSign.name',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[el_GR]
|
[el_GR]
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
|||||||
@Value("${spring.datasource.url}")
|
@Value("${spring.datasource.url}")
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
|
@Value("${spring.datasource.username}")
|
||||||
|
private String databaseUsername;
|
||||||
|
|
||||||
|
@Value("${spring.datasource.password}")
|
||||||
|
private String databasePassword;
|
||||||
|
|
||||||
private Path backupPath = Paths.get("configs/db/backup/");
|
private Path backupPath = Paths.get("configs/db/backup/");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -134,7 +140,8 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
|||||||
this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql");
|
this.getBackupFilePath("backup_" + dateNow.format(myFormatObj) + ".sql");
|
||||||
String query = "SCRIPT SIMPLE COLUMNS DROP to ?;";
|
String query = "SCRIPT SIMPLE COLUMNS DROP to ?;";
|
||||||
|
|
||||||
try (Connection conn = DriverManager.getConnection(url, "sa", "");
|
try (Connection conn =
|
||||||
|
DriverManager.getConnection(url, databaseUsername, databasePassword);
|
||||||
PreparedStatement stmt = conn.prepareStatement(query)) {
|
PreparedStatement stmt = conn.prepareStatement(query)) {
|
||||||
stmt.setString(1, insertOutputFilePath.toString());
|
stmt.setString(1, insertOutputFilePath.toString());
|
||||||
stmt.execute();
|
stmt.execute();
|
||||||
@@ -147,7 +154,8 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
|||||||
// Retrieves the H2 database version.
|
// Retrieves the H2 database version.
|
||||||
public String getH2Version() {
|
public String getH2Version() {
|
||||||
String version = "Unknown";
|
String version = "Unknown";
|
||||||
try (Connection conn = DriverManager.getConnection(url, "sa", "")) {
|
try (Connection conn =
|
||||||
|
DriverManager.getConnection(url, databaseUsername, databasePassword)) {
|
||||||
try (Statement stmt = conn.createStatement();
|
try (Statement stmt = conn.createStatement();
|
||||||
ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) {
|
ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) {
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
@@ -189,7 +197,8 @@ public class DatabaseBackupHelper implements DatabaseBackupInterface {
|
|||||||
private boolean executeDatabaseScript(Path scriptPath) {
|
private boolean executeDatabaseScript(Path scriptPath) {
|
||||||
String query = "RUNSCRIPT from ?;";
|
String query = "RUNSCRIPT from ?;";
|
||||||
|
|
||||||
try (Connection conn = DriverManager.getConnection(url, "sa", "");
|
try (Connection conn =
|
||||||
|
DriverManager.getConnection(url, databaseUsername, databasePassword);
|
||||||
PreparedStatement stmt = conn.prepareStatement(query)) {
|
PreparedStatement stmt = conn.prepareStatement(query)) {
|
||||||
stmt.setString(1, scriptPath.toString());
|
stmt.setString(1, scriptPath.toString());
|
||||||
stmt.execute();
|
stmt.execute();
|
||||||
|
|||||||
@@ -32,11 +32,19 @@ public class MetricsAggregatorService {
|
|||||||
.counters()
|
.counters()
|
||||||
.forEach(
|
.forEach(
|
||||||
counter -> {
|
counter -> {
|
||||||
String key =
|
String method = counter.getId().getTag("method");
|
||||||
String.format(
|
String uri = counter.getId().getTag("uri");
|
||||||
|
|
||||||
|
// Skip if either method or uri is null
|
||||||
|
if (method == null || uri == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String key = String.format(
|
||||||
"http_requests_%s_%s",
|
"http_requests_%s_%s",
|
||||||
counter.getId().getTag("method"),
|
method,
|
||||||
counter.getId().getTag("uri").replace("/", "_"));
|
uri.replace("/", "_")
|
||||||
|
);
|
||||||
|
|
||||||
double currentCount = counter.count();
|
double currentCount = counter.count();
|
||||||
double lastCount = lastSentMetrics.getOrDefault(key, 0.0);
|
double lastCount = lastSentMetrics.getOrDefault(key, 0.0);
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=صفحة
|
|||||||
pages=صفحات
|
pages=صفحات
|
||||||
loading=جارٍ التحميل...
|
loading=جارٍ التحميل...
|
||||||
addToDoc=إضافة إلى المستند
|
addToDoc=إضافة إلى المستند
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=سياسة الخصوصية
|
legal.privacy=سياسة الخصوصية
|
||||||
legal.terms=شروط الاستخدام
|
legal.terms=شروط الاستخدام
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Страница
|
|||||||
pages=Страници
|
pages=Страници
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Политика за поверителност
|
legal.privacy=Политика за поверителност
|
||||||
legal.terms=Правила и условия
|
legal.terms=Правила и условия
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Pàgina
|
|||||||
pages=Pàgines
|
pages=Pàgines
|
||||||
loading=Carregant...
|
loading=Carregant...
|
||||||
addToDoc=Afegeix al document
|
addToDoc=Afegeix al document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Política de Privacitat
|
legal.privacy=Política de Privacitat
|
||||||
legal.terms=Termes i condicions
|
legal.terms=Termes i condicions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Strana
|
|||||||
pages=Strany
|
pages=Strany
|
||||||
loading=Načítání...
|
loading=Načítání...
|
||||||
addToDoc=Přidat do dokumentu
|
addToDoc=Přidat do dokumentu
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Politika soukromí
|
legal.privacy=Politika soukromí
|
||||||
legal.terms=Podmínky použití
|
legal.terms=Podmínky použití
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Sidenummer
|
|||||||
pages=Sideantal
|
pages=Sideantal
|
||||||
loading=Laster...
|
loading=Laster...
|
||||||
addToDoc=Tilføj til Dokument
|
addToDoc=Tilføj til Dokument
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Vilkår og betingelser
|
legal.terms=Vilkår og betingelser
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Seite
|
|||||||
pages=Seiten
|
pages=Seiten
|
||||||
loading=Laden...
|
loading=Laden...
|
||||||
addToDoc=In Dokument hinzufügen
|
addToDoc=In Dokument hinzufügen
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Datenschutz
|
legal.privacy=Datenschutz
|
||||||
legal.terms=AGB
|
legal.terms=AGB
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Σελίδα
|
|||||||
pages=Σελίδες
|
pages=Σελίδες
|
||||||
loading=Φόρτωση...
|
loading=Φόρτωση...
|
||||||
addToDoc=Πρόσθεση στο Εκπομπώματο
|
addToDoc=Πρόσθεση στο Εκπομπώματο
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Πολιτική Προνομίους
|
legal.privacy=Πολιτική Προνομίους
|
||||||
legal.terms=Φράσεις Υποχρεωτικότητας
|
legal.terms=Φράσεις Υποχρεωτικότητας
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Página
|
|||||||
pages=Páginas
|
pages=Páginas
|
||||||
loading=Cargando...
|
loading=Cargando...
|
||||||
addToDoc=Agregar al Documento
|
addToDoc=Agregar al Documento
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Política de Privacidad
|
legal.privacy=Política de Privacidad
|
||||||
legal.terms=Términos y Condiciones
|
legal.terms=Términos y Condiciones
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Chargement...
|
loading=Chargement...
|
||||||
addToDoc=Ajouter au Document
|
addToDoc=Ajouter au Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Politique de Confidentialité
|
legal.privacy=Politique de Confidentialité
|
||||||
legal.terms=Conditions Générales
|
legal.terms=Conditions Générales
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=पृष्ठ
|
|||||||
pages=पृष्ठों
|
pages=पृष्ठों
|
||||||
loading=डालिंग...
|
loading=डालिंग...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=गुप्तता सूचना
|
legal.privacy=गुप्तता सूचना
|
||||||
legal.terms=शर्तें और प्रवाह
|
legal.terms=शर्तें और प्रवाह
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Stranica
|
|||||||
pages=Stranice
|
pages=Stranice
|
||||||
loading=Učitavanje...
|
loading=Učitavanje...
|
||||||
addToDoc=Dodaj u dokument
|
addToDoc=Dodaj u dokument
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Politika privatnosti
|
legal.privacy=Politika privatnosti
|
||||||
legal.terms=Uspe sodržine
|
legal.terms=Uspe sodržine
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Oldal
|
|||||||
pages=Oldalak
|
pages=Oldalak
|
||||||
loading=Betöltés...
|
loading=Betöltés...
|
||||||
addToDoc=Hozzáadás dokumentumba
|
addToDoc=Hozzáadás dokumentumba
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Adatvédelmi nyilatkozat
|
legal.privacy=Adatvédelmi nyilatkozat
|
||||||
legal.terms=Feltételek és feltételek
|
legal.terms=Feltételek és feltételek
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Halaman
|
|||||||
pages=Halaman-halaman
|
pages=Halaman-halaman
|
||||||
loading=Mengambil data...
|
loading=Mengambil data...
|
||||||
addToDoc=Tambahkan ke Dokumen
|
addToDoc=Tambahkan ke Dokumen
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Kebijakan Privasi
|
legal.privacy=Kebijakan Privasi
|
||||||
legal.terms=Syarat dan Ketentuan
|
legal.terms=Syarat dan Ketentuan
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Pagina
|
|||||||
pages=Pagine
|
pages=Pagine
|
||||||
loading=Caricamento...
|
loading=Caricamento...
|
||||||
addToDoc=Aggiungi al documento
|
addToDoc=Aggiungi al documento
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Informativa sulla privacy
|
legal.privacy=Informativa sulla privacy
|
||||||
legal.terms=Termini e Condizioni
|
legal.terms=Termini e Condizioni
|
||||||
@@ -141,7 +142,7 @@ navbar.language=Lingue
|
|||||||
navbar.settings=Impostazioni
|
navbar.settings=Impostazioni
|
||||||
navbar.allTools=Strumenti
|
navbar.allTools=Strumenti
|
||||||
navbar.multiTool=Strumenti multipli
|
navbar.multiTool=Strumenti multipli
|
||||||
navbar.search=Search
|
navbar.search=Cerca
|
||||||
navbar.sections.organize=Organizza
|
navbar.sections.organize=Organizza
|
||||||
navbar.sections.convertTo=Converti in PDF
|
navbar.sections.convertTo=Converti in PDF
|
||||||
navbar.sections.convertFrom=Converti da PDF
|
navbar.sections.convertFrom=Converti da PDF
|
||||||
@@ -944,7 +945,7 @@ multiTool.downloadAll=Esporta
|
|||||||
multiTool.downloadSelected=Esporta selezionata
|
multiTool.downloadSelected=Esporta selezionata
|
||||||
|
|
||||||
#multiTool-advert
|
#multiTool-advert
|
||||||
multiTool-advert.message=This feature is also available in our <a href="{0}">multi-tool page</a>. Check it out for enhanced page-by-page UI and additional features!
|
multiTool-advert.message=Questa funzione è disponibile anche nella nostra <a href="{0}">pagina multi-strumento</a>. Scoprila per un'interfaccia utente pagina per pagina migliorata e funzionalità aggiuntive!
|
||||||
|
|
||||||
#view pdf
|
#view pdf
|
||||||
viewPdf.title=Visualizza PDF
|
viewPdf.title=Visualizza PDF
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=プライバシーポリシー
|
legal.privacy=プライバシーポリシー
|
||||||
legal.terms=利用規約
|
legal.terms=利用規約
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=페이지
|
|||||||
pages=페이지
|
pages=페이지
|
||||||
loading=로딩 중...
|
loading=로딩 중...
|
||||||
addToDoc=문서에 추가
|
addToDoc=문서에 추가
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=개인 정보 정책
|
legal.privacy=개인 정보 정책
|
||||||
legal.terms=이용 약관
|
legal.terms=이용 약관
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Pagina
|
|||||||
pages=Pagen
|
pages=Pagen
|
||||||
loading=Laden...
|
loading=Laden...
|
||||||
addToDoc=Toevoegen aan document
|
addToDoc=Toevoegen aan document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacybeleid
|
legal.privacy=Privacybeleid
|
||||||
legal.terms=Voorwaarden van gebruik
|
legal.terms=Voorwaarden van gebruik
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Strona
|
|||||||
pages=Strony
|
pages=Strony
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Polityka Prywatności
|
legal.privacy=Polityka Prywatności
|
||||||
legal.terms=Zasady i Postanowienia
|
legal.terms=Zasady i Postanowienia
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Página
|
|||||||
pages=Páginas
|
pages=Páginas
|
||||||
loading=Carregando...
|
loading=Carregando...
|
||||||
addToDoc=Adicionar ao Documento
|
addToDoc=Adicionar ao Documento
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Política de Privacidade
|
legal.privacy=Política de Privacidade
|
||||||
legal.terms=Termos e Condições
|
legal.terms=Termos e Condições
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Página
|
|||||||
pages=Páginas
|
pages=Páginas
|
||||||
loading=A carregar...
|
loading=A carregar...
|
||||||
addToDoc=Adicionar ao Documento
|
addToDoc=Adicionar ao Documento
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Política de Privacidade
|
legal.privacy=Política de Privacidade
|
||||||
legal.terms=Termos e Condições
|
legal.terms=Termos e Condições
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Страница
|
|||||||
pages=Страницы
|
pages=Страницы
|
||||||
loading=Загрузка...
|
loading=Загрузка...
|
||||||
addToDoc=Добавить в документ
|
addToDoc=Добавить в документ
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Политика конфиденциальности
|
legal.privacy=Политика конфиденциальности
|
||||||
legal.terms=Условия использования
|
legal.terms=Условия использования
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Sidan
|
|||||||
pages=Sidor
|
pages=Sidor
|
||||||
loading=Laddar...
|
loading=Laddar...
|
||||||
addToDoc=Lägg till i dokument
|
addToDoc=Lägg till i dokument
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Dataprotektionspolicy
|
legal.privacy=Dataprotektionspolicy
|
||||||
legal.terms=Villkor och betingelser
|
legal.terms=Villkor och betingelser
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=หน้า
|
|||||||
pages=หน้า
|
pages=หน้า
|
||||||
loading=กำลังโหลด...
|
loading=กำลังโหลด...
|
||||||
addToDoc=เพิ่มเข้าสู่เอกสาร
|
addToDoc=เพิ่มเข้าสู่เอกสาร
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=นโยบายความเป็นส่วนตัว
|
legal.privacy=นโยบายความเป็นส่วนตัว
|
||||||
legal.terms=ข้อกำหนดการใช้งาน
|
legal.terms=ข้อกำหนดการใช้งาน
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Gizlilik Politikası
|
legal.privacy=Gizlilik Politikası
|
||||||
legal.terms=Şartlar ve koşullar
|
legal.terms=Şartlar ve koşullar
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=Page
|
|||||||
pages=Pages
|
pages=Pages
|
||||||
loading=Loading...
|
loading=Loading...
|
||||||
addToDoc=Add to Document
|
addToDoc=Add to Document
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=Privacy Policy
|
legal.privacy=Privacy Policy
|
||||||
legal.terms=Terms and Conditions
|
legal.terms=Terms and Conditions
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ page=頁面
|
|||||||
pages=頁面
|
pages=頁面
|
||||||
loading=載入中...
|
loading=載入中...
|
||||||
addToDoc=新增至文件
|
addToDoc=新增至文件
|
||||||
|
reset=Reset
|
||||||
|
|
||||||
legal.privacy=隱私權政策
|
legal.privacy=隱私權政策
|
||||||
legal.terms=使用條款
|
legal.terms=使用條款
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ span.icon-text::after {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip-text {
|
/* .tooltip-text {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
background-color: rgb(71 67 67 / 80%);
|
background-color: rgb(71 67 67 / 80%);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -162,7 +162,7 @@ span.icon-text::after {
|
|||||||
.nav-item:hover .tooltip-text {
|
.nav-item:hover .tooltip-text {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
} */
|
||||||
|
|
||||||
.dropdown-menu.scrollable-y {
|
.dropdown-menu.scrollable-y {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
@@ -324,6 +324,18 @@ span.icon-text::after {
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* .icon-hide {
|
||||||
|
display: none;
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:1199px) {
|
||||||
|
.icon-hide {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width:1200px) {
|
||||||
.icon-hide {
|
.icon-hide {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,14 +96,31 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function getPDFPageCount(file) {
|
||||||
|
try {
|
||||||
|
const arrayBuffer = await file.arrayBuffer();
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdfjs-legacy/pdf.worker.mjs'
|
||||||
|
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
|
||||||
|
return pdf.numPages;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting PDF page count:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSingleDownload(url, formData, isMulti = false, isZip = false) {
|
async function handleSingleDownload(url, formData, isMulti = false, isZip = false) {
|
||||||
|
const startTime = performance.now();
|
||||||
|
const file = formData.get('fileInput');
|
||||||
|
let success = false;
|
||||||
|
let errorMessage = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, { method: "POST", body: formData });
|
const response = await fetch(url, { method: "POST", body: formData });
|
||||||
const contentType = response.headers.get("content-type");
|
const contentType = response.headers.get("content-type");
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
errorMessage = response.status;
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
// Handle 401 Unauthorized error
|
|
||||||
showSessionExpiredPrompt();
|
showSessionExpiredPrompt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -118,6 +135,8 @@
|
|||||||
let filename = getFilenameFromContentDisposition(contentDisposition);
|
let filename = getFilenameFromContentDisposition(contentDisposition);
|
||||||
|
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
|
success = true;
|
||||||
|
|
||||||
if (contentType.includes("application/pdf") || contentType.includes("image/")) {
|
if (contentType.includes("application/pdf") || contentType.includes("image/")) {
|
||||||
clearFileInput();
|
clearFileInput();
|
||||||
return handleResponse(blob, filename, !isMulti, isZip);
|
return handleResponse(blob, filename, !isMulti, isZip);
|
||||||
@@ -127,9 +146,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
success = false;
|
||||||
|
errorMessage = error.message;
|
||||||
clearFileInput();
|
clearFileInput();
|
||||||
console.error("Error in handleSingleDownload:", error);
|
console.error("Error in handleSingleDownload:", error);
|
||||||
throw error;
|
throw error;
|
||||||
|
} finally {
|
||||||
|
const processingTime = performance.now() - startTime;
|
||||||
|
|
||||||
|
// Capture analytics
|
||||||
|
const pageCount = file && file.type === 'application/pdf' ? await getPDFPageCount(file) : null;
|
||||||
|
|
||||||
|
posthog.capture('file_processing', {
|
||||||
|
success: success,
|
||||||
|
file_type: file ? file.type || 'unknown' : 'unknown',
|
||||||
|
file_size: file ? file.size : 0,
|
||||||
|
processing_time: processingTime,
|
||||||
|
error_message: errorMessage,
|
||||||
|
pdf_pages: pageCount
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,14 +343,14 @@
|
|||||||
if(editSectionElement){
|
if(editSectionElement){
|
||||||
editSectionElement.style.display = "none";
|
editSectionElement.style.display = "none";
|
||||||
}
|
}
|
||||||
let cropPdfCanvas = document.querySelector("#crop-pdf-canvas");
|
let cropPdfCanvas = document.querySelector("#cropPdfCanvas");
|
||||||
let overlayCanvas = document.querySelector("#overlayCanvas");
|
let overlayCanvas = document.querySelector("#overlayCanvas");
|
||||||
if(cropPdfCanvas && overlayCanvas){
|
if(cropPdfCanvas && overlayCanvas){
|
||||||
cropPdfCanvas.width = 0;
|
cropPdfCanvas.width = 0;
|
||||||
cropPdfCanvas.heigth = 0;
|
cropPdfCanvas.height = 0;
|
||||||
|
|
||||||
overlayCanvas.width = 0;
|
overlayCanvas.width = 0;
|
||||||
overlayCanvas.heigth = 0;
|
overlayCanvas.height = 0;
|
||||||
}
|
}
|
||||||
} else{
|
} else{
|
||||||
console.log("Disabled for 'Merge'");
|
console.log("Disabled for 'Merge'");
|
||||||
|
|||||||
@@ -308,6 +308,7 @@ const DraggableUtils = {
|
|||||||
const offsetWidth = pagesMap[pageIdx + "-offsetWidth"];
|
const offsetWidth = pagesMap[pageIdx + "-offsetWidth"];
|
||||||
const offsetHeight = pagesMap[pageIdx + "-offsetHeight"];
|
const offsetHeight = pagesMap[pageIdx + "-offsetHeight"];
|
||||||
|
|
||||||
|
|
||||||
for (const draggableData of draggablesData) {
|
for (const draggableData of draggablesData) {
|
||||||
// embed the draggable canvas
|
// embed the draggable canvas
|
||||||
const draggableElement = draggableData.element;
|
const draggableElement = draggableData.element;
|
||||||
@@ -324,6 +325,24 @@ const DraggableUtils = {
|
|||||||
width: draggableData.offsetWidth,
|
width: draggableData.offsetWidth,
|
||||||
height: draggableData.offsetHeight,
|
height: draggableData.offsetHeight,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Auxiliary variables
|
||||||
|
let widthAdjusted = page.getWidth();
|
||||||
|
let heightAdjusted = page.getHeight();
|
||||||
|
const rotation = page.getRotation();
|
||||||
|
|
||||||
|
//Normalizing angle
|
||||||
|
let normalizedAngle = rotation.angle % 360;
|
||||||
|
if (normalizedAngle < 0) {
|
||||||
|
normalizedAngle += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Changing the page dimension if the angle is 90 or 270
|
||||||
|
if (normalizedAngle === 90 || normalizedAngle === 270) {
|
||||||
|
let widthTemp = widthAdjusted;
|
||||||
|
widthAdjusted = heightAdjusted;
|
||||||
|
heightAdjusted = widthTemp;
|
||||||
|
}
|
||||||
const draggablePositionRelative = {
|
const draggablePositionRelative = {
|
||||||
x: draggablePositionPixels.x / offsetWidth,
|
x: draggablePositionPixels.x / offsetWidth,
|
||||||
y: draggablePositionPixels.y / offsetHeight,
|
y: draggablePositionPixels.y / offsetHeight,
|
||||||
@@ -331,18 +350,36 @@ const DraggableUtils = {
|
|||||||
height: draggablePositionPixels.height / offsetHeight,
|
height: draggablePositionPixels.height / offsetHeight,
|
||||||
};
|
};
|
||||||
const draggablePositionPdf = {
|
const draggablePositionPdf = {
|
||||||
x: draggablePositionRelative.x * page.getWidth(),
|
x: draggablePositionRelative.x * widthAdjusted,
|
||||||
y: draggablePositionRelative.y * page.getHeight(),
|
y: draggablePositionRelative.y * heightAdjusted,
|
||||||
width: draggablePositionRelative.width * page.getWidth(),
|
width: draggablePositionRelative.width * widthAdjusted,
|
||||||
height: draggablePositionRelative.height * page.getHeight(),
|
height: draggablePositionRelative.height * heightAdjusted,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Defining the image if the page has a 0-degree angle
|
||||||
|
let x = draggablePositionPdf.x
|
||||||
|
let y = heightAdjusted - draggablePositionPdf.y - draggablePositionPdf.height
|
||||||
|
|
||||||
|
|
||||||
|
//Defining the image position if it is at other angles
|
||||||
|
if (normalizedAngle === 90) {
|
||||||
|
x = draggablePositionPdf.y + draggablePositionPdf.height;
|
||||||
|
y = draggablePositionPdf.x;
|
||||||
|
} else if (normalizedAngle === 180) {
|
||||||
|
x = widthAdjusted - draggablePositionPdf.x;
|
||||||
|
y = draggablePositionPdf.y + draggablePositionPdf.height;
|
||||||
|
} else if (normalizedAngle === 270) {
|
||||||
|
x = heightAdjusted - draggablePositionPdf.y - draggablePositionPdf.height;
|
||||||
|
y = widthAdjusted - draggablePositionPdf.x;
|
||||||
|
}
|
||||||
|
|
||||||
// draw the image
|
// draw the image
|
||||||
page.drawImage(pdfImageObject, {
|
page.drawImage(pdfImageObject, {
|
||||||
x: draggablePositionPdf.x,
|
x: x,
|
||||||
y: page.getHeight() - draggablePositionPdf.y - draggablePositionPdf.height,
|
y: y,
|
||||||
width: draggablePositionPdf.width,
|
width: draggablePositionPdf.width,
|
||||||
height: draggablePositionPdf.height,
|
height: draggablePositionPdf.height,
|
||||||
|
rotate: rotation
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,23 +23,26 @@
|
|||||||
</form>
|
</form>
|
||||||
<p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p>
|
<p id="instruction-text" style="margin: 0; display: none" th:text="#{PDFToCSV.prompt}"></p>
|
||||||
|
|
||||||
<div style="position: relative; display: inline-block;">
|
<div style="position: relative; width: auto;" id="canvasesContainer">
|
||||||
<div>
|
<div>
|
||||||
<div style="display:none ;margin: 3px;position: absolute;top: 0;width: 120px;justify-content:space-between;z-index: 10" id="pagination-button-container">
|
<div style="display:none ;margin: 3px;position: absolute;top: 0;width: 120px;justify-content:space-between;z-index: 10" id="pagination-button-container">
|
||||||
<button id='previous-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> < </button>
|
<button id='previous-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> < </button>
|
||||||
<button id='next-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> > </button>
|
<button id='next-page-btn' style='opacity: 80% ; width: 50px; height: 30px; display: flex;align-items: center;justify-content: center; background: grey; color: #ffffff; ;border: none;outline: none; border-radius: 4px;'> > </button>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="crop-pdf-canvas" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
|
<canvas id="cropPdfCanvas" style="width: 100%"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas>
|
<canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; z-index: 2; width: 100%"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||||
<script>
|
<script>
|
||||||
let pdfCanvas = document.getElementById('crop-pdf-canvas');
|
let pdfCanvas = document.getElementById('cropPdfCanvas');
|
||||||
let overlayCanvas = document.getElementById('overlayCanvas');
|
let overlayCanvas = document.getElementById('overlayCanvas');
|
||||||
|
let canvasesContainer = document.getElementById('canvasesContainer');
|
||||||
|
canvasesContainer.style.display = "none";
|
||||||
// let paginationBtnContainer = ;
|
// let paginationBtnContainer = ;
|
||||||
|
|
||||||
let context = pdfCanvas.getContext('2d');
|
let context = pdfCanvas.getContext('2d');
|
||||||
|
let overlayContext = overlayCanvas.getContext('2d');
|
||||||
|
|
||||||
let btn1Object = document.getElementById('previous-page-btn');
|
let btn1Object = document.getElementById('previous-page-btn');
|
||||||
let btn2Object = document.getElementById('next-page-btn');
|
let btn2Object = document.getElementById('next-page-btn');
|
||||||
@@ -60,6 +63,8 @@
|
|||||||
let rectWidth = 0;
|
let rectWidth = 0;
|
||||||
let rectHeight = 0;
|
let rectHeight = 0;
|
||||||
|
|
||||||
|
let timeId = null; // timeout id for resizing canvases event
|
||||||
|
|
||||||
btn1Object.addEventListener('click',function (e){
|
btn1Object.addEventListener('click',function (e){
|
||||||
if (currentPage !== 1) {
|
if (currentPage !== 1) {
|
||||||
currentPage = currentPage - 1;
|
currentPage = currentPage - 1;
|
||||||
@@ -102,8 +107,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
fileInput.addEventListener('change', function(e) {
|
function renderPageFromFile(file) {
|
||||||
file = e.target.files[0];
|
|
||||||
if (file.type === 'application/pdf') {
|
if (file.type === 'application/pdf') {
|
||||||
let reader = new FileReader();
|
let reader = new FileReader();
|
||||||
reader.onload = function (ev) {
|
reader.onload = function (ev) {
|
||||||
@@ -120,6 +124,34 @@
|
|||||||
document.getElementById("pagination-button-container").style.display = "flex";
|
document.getElementById("pagination-button-container").style.display = "flex";
|
||||||
document.getElementById("instruction-text").style.display = "block";
|
document.getElementById("instruction-text").style.display = "block";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("resize", function() {
|
||||||
|
clearTimeout(timeId);
|
||||||
|
timeId = setTimeout(function () {
|
||||||
|
if (fileInput.files.length == 0) return;
|
||||||
|
let canvasesContainer = document.getElementById('canvasesContainer');
|
||||||
|
let containerRect = canvasesContainer.getBoundingClientRect();
|
||||||
|
|
||||||
|
context.clearRect(0, 0, pdfCanvas.width, pdfCanvas.height);
|
||||||
|
|
||||||
|
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
|
||||||
|
|
||||||
|
pdfCanvas.width = containerRect.width;
|
||||||
|
pdfCanvas.height = containerRect.height;
|
||||||
|
|
||||||
|
overlayCanvas.width = containerRect.width;
|
||||||
|
overlayCanvas.height = containerRect.height;
|
||||||
|
|
||||||
|
let file = fileInput.files[0];
|
||||||
|
renderPageFromFile(file);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
fileInput.addEventListener('change', function(e) {
|
||||||
|
canvasesContainer.style.display = "block"; // set for visual purposes
|
||||||
|
file = e.target.files[0];
|
||||||
|
renderPageFromFile(file);
|
||||||
});
|
});
|
||||||
|
|
||||||
function renderPage(pageNumber) {
|
function renderPage(pageNumber) {
|
||||||
|
|||||||
@@ -201,6 +201,7 @@
|
|||||||
window.stirlingPDF.error = /*[[#{error}]]*/ "Error";
|
window.stirlingPDF.error = /*[[#{error}]]*/ "Error";
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||||
<script th:src="@{'/js/downloader.js'}"></script>
|
<script th:src="@{'/js/downloader.js'}"></script>
|
||||||
|
|
||||||
<div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
|
<div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
|
||||||
|
|||||||
@@ -330,7 +330,7 @@
|
|||||||
<span class="material-symbols-rounded" id="dark-mode-icon">
|
<span class="material-symbols-rounded" id="dark-mode-icon">
|
||||||
dark_mode
|
dark_mode
|
||||||
</span>
|
</span>
|
||||||
<span class="icon-text icon-hide tooltip-text" id="dark-mode-text" th:data-text="#{navbar.darkmode}" th:text="#{navbar.darkmode}"></span>
|
<span class="icon-text icon-hide" id="dark-mode-text" th:data-text="#{navbar.darkmode}" th:text="#{navbar.darkmode}"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
@@ -380,7 +380,7 @@
|
|||||||
<span class="material-symbols-rounded">
|
<span class="material-symbols-rounded">
|
||||||
settings
|
settings
|
||||||
</span>
|
</span>
|
||||||
<span class="icon-text icon-hide tooltip-text" th:data-text="#{navbar.settings}" th:text="#{navbar.settings}"></span>
|
<span class="icon-text icon-hide" th:data-text="#{navbar.settings}" th:text="#{navbar.settings}"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -411,7 +411,7 @@
|
|||||||
th:title="#{visitGithub}">
|
th:title="#{visitGithub}">
|
||||||
<img th:src="@{'/images/github.svg'}" alt="github">
|
<img th:src="@{'/images/github.svg'}" alt="github">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://hub.docker.com/r/frooodle/s-pdf" class="mx-1" role="button" target="_blank"th:title="#{seeDockerHub}">
|
<a href="https://hub.docker.com/r/stirlingtools/stirling-pdf" class="mx-1" role="button" target="_blank"th:title="#{seeDockerHub}">
|
||||||
<img th:src="@{'/images/docker.svg'}" alt="docker">
|
<img th:src="@{'/images/docker.svg'}" alt="docker">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" target="_blank" th:title="#{joinDiscord}">
|
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" target="_blank" th:title="#{joinDiscord}">
|
||||||
|
|||||||
@@ -83,9 +83,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
|
||||||
<button type="button" id="resetFileInputBtn" class="btn btn-danger" onclick="removeAllElements()" th:text="#{reset}">Reset</button>
|
|
||||||
</div>
|
|
||||||
<div id="selected-pages-display" class="selected-pages-container hidden">
|
<div id="selected-pages-display" class="selected-pages-container hidden">
|
||||||
<div style="display:flex; height:3rem; margin-right:1rem">
|
<div style="display:flex; height:3rem; margin-right:1rem">
|
||||||
<h5 th:text="#{multiTool.selectedPages}" style="white-space: nowrap; margin-right: 1rem;">Selected
|
<h5 th:text="#{multiTool.selectedPages}" style="white-space: nowrap; margin-right: 1rem;">Selected
|
||||||
|
|||||||
2
test2.sh
2
test2.sh
@@ -49,7 +49,7 @@ check_health() {
|
|||||||
build_and_test() {
|
build_and_test() {
|
||||||
local version_tag="alpha"
|
local version_tag="alpha"
|
||||||
local dockerfile_name="./Dockerfile"
|
local dockerfile_name="./Dockerfile"
|
||||||
local image_base="frooodle/s-pdf"
|
local image_base="stirlingtools/stirling-pdf"
|
||||||
local security_suffix=""
|
local security_suffix=""
|
||||||
local docker_compose_base="./exampleYmlFiles/docker-compose-latest"
|
local docker_compose_base="./exampleYmlFiles/docker-compose-latest"
|
||||||
local compose_suffix=".yml"
|
local compose_suffix=".yml"
|
||||||
|
|||||||
Reference in New Issue
Block a user