diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..a1046b8 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/generate-pdf.yml b/.github/workflows/generate-pdf.yml new file mode 100644 index 0000000..55b3e1f --- /dev/null +++ b/.github/workflows/generate-pdf.yml @@ -0,0 +1,38 @@ +name: Generate PDF Labels + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + workflow_dispatch: + +jobs: + generate-pdf: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Install Playwright Chromium + run: npx playwright install chromium + + - name: Generate PDF + run: npm run generate-pdf + + - name: Upload PDF artifact + uses: actions/upload-artifact@v4 + with: + name: asn-labels-pdf + path: asn-labels.pdf + retention-days: 30 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf4eba1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +asn-labels.pdf diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6d2624e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,62 @@ +{ + "name": "asn-qr-code-label-generator", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "asn-qr-code-label-generator", + "version": "1.0.0", + "devDependencies": { + "playwright": "^1.49.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.56.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..c38c791 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "asn-qr-code-label-generator", + "version": "1.0.0", + "description": "QR code label generator for Paperless-ngx Archive Serial Numbers", + "private": true, + "scripts": { + "generate-pdf": "node scripts/generate-pdf.js" + }, + "devDependencies": { + "playwright": "^1.56.0" + } +} diff --git a/scripts/generate-pdf.js b/scripts/generate-pdf.js new file mode 100644 index 0000000..96ff80d --- /dev/null +++ b/scripts/generate-pdf.js @@ -0,0 +1,70 @@ +const { chromium } = require('playwright'); +const http = require('http'); +const fs = require('fs'); +const path = require('path'); + +async function generatePDF() { + // Start a simple HTTP server to serve the HTML file + const htmlPath = path.join(__dirname, '..', 'index.html'); + const htmlContent = fs.readFileSync(htmlPath, 'utf8'); + + const server = http.createServer((req, res) => { + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(htmlContent); + }); + + await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); + const port = server.address().port; + console.log(`Server started on port ${port}`); + + const browser = await chromium.launch({ + args: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--disable-dev-shm-usage' + ] + }); + const context = await browser.newContext(); + const page = await context.newPage(); + + try { + // Load the page from local server and wait for network to settle + await page.goto(`http://127.0.0.1:${port}`, { waitUntil: 'networkidle' }); + + // Wait for AlpineJS to initialize and generate labels + console.log('Waiting for labels to be generated...'); + await page.waitForFunction(() => { + const labels = document.querySelectorAll('ol li'); + return labels.length === 189; // 7 columns x 27 rows + }, { timeout: 60000 }); + + console.log('Labels generated, waiting for QR code images to load...'); + + // Wait for all QR code images to load + await page.waitForFunction(() => { + const images = document.querySelectorAll('ol li img'); + if (images.length === 0) return false; + return Array.from(images).every(img => img.complete && img.naturalHeight > 0); + }, { timeout: 120000 }); + + console.log('All images loaded, generating PDF...'); + + // Generate PDF with A4 format and print media + await page.pdf({ + path: 'asn-labels.pdf', + format: 'A4', + printBackground: true, + margin: { top: 0, right: 0, bottom: 0, left: 0 } + }); + + console.log('PDF generated successfully: asn-labels.pdf'); + } finally { + await browser.close(); + server.close(); + } +} + +generatePDF().catch(err => { + console.error('Error generating PDF:', err); + process.exit(1); +});