diff --git a/.env.example b/.env.example index 27de352..aa2557e 100644 --- a/.env.example +++ b/.env.example @@ -7,4 +7,6 @@ CACHE_LOCATION=./cache ROOT_CATEGORY_ID=0 JTL_SHOP_ID=0 JTL_SPRACHE_ID=1 -JTL_PLATTFORM_ID=1 \ No newline at end of file +JTL_PLATTFORM_ID=1 +SERVER_PORT=3991 +SERVER_HOST=127.0.0.1 \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..3b27159 --- /dev/null +++ b/index.html @@ -0,0 +1,226 @@ + + + + + + Category Tree Viewer + + + +
+

📦 Category Tree

+
+
Loading categories...
+
+
+ + + + diff --git a/index.js b/index.js index 4c12dcb..e171987 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ import categorySyncer from './category-syncer.js'; import pictureSyncer from './picture-syncer.js'; +import { startServer } from './server.js'; categorySyncer.on('synced', async ({ tree, unprunedTree, changed }) => { if (changed) { @@ -44,3 +45,6 @@ if (process.stdout.isTTY) { process.exit(0); }); } + +// Start Express server +startServer(); diff --git a/picture-syncer.js b/picture-syncer.js index 1b75110..74a2bd0 100644 --- a/picture-syncer.js +++ b/picture-syncer.js @@ -1,5 +1,6 @@ import fs from 'fs/promises'; import path from 'path'; +import sharp from 'sharp'; import { createConnection } from './database.js'; class PictureSyncer { @@ -25,18 +26,17 @@ class PictureSyncer { // Directory might be empty or new } - // Filter for image files (assuming we save as {id}.jpg or similar, but let's check just by ID prefix) - // Actually, let's assume we save as `${id}.jpg` + // Filter for image files (assuming we save as {id}.avif) const existingIds = existingFiles - .filter(f => f.endsWith('.jpg')) - .map(f => parseInt(f.replace('.jpg', ''))); + .filter(f => f.endsWith('.avif')) + .map(f => parseInt(f.replace('.avif', ''))); const validIds = new Set(imageIds.filter(id => id !== null && id !== undefined)); // 1. Delete obsolete images const toDelete = existingIds.filter(id => !validIds.has(id)); for (const id of toDelete) { - const filePath = path.join(groupDir, `${id}.jpg`); + const filePath = path.join(groupDir, `${id}.avif`); await fs.unlink(filePath); } if (toDelete.length > 0) { @@ -73,9 +73,11 @@ class PictureSyncer { for (const record of result.recordset) { if (record.bBild) { - const filePath = path.join(dir, `${record.kBild}.jpg`); - await fs.writeFile(filePath, record.bBild); - // console.log(`💾 Saved image: ${filePath}`); + const filePath = path.join(dir, `${record.kBild}.avif`); + // Convert to AVIF using sharp + await sharp(record.bBild) + .avif({ quality: 80 }) + .toFile(filePath); } } const processed = Math.min(i + chunkSize, ids.length); diff --git a/server.js b/server.js new file mode 100644 index 0000000..6147a30 --- /dev/null +++ b/server.js @@ -0,0 +1,52 @@ +import express from 'express'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import fs from 'fs/promises'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export function startServer() { + const app = express(); + const PORT = process.env.SERVER_PORT || 3000; + const HOST = process.env.SERVER_HOST || '0.0.0.0'; + const CACHE_DIR = process.env.CACHE_LOCATION || './cache'; + + // Serve category tree JSON + app.get('/api/categories', async (req, res) => { + try { + const treePath = path.join(CACHE_DIR, 'category_tree.json'); + const data = await fs.readFile(treePath, 'utf-8'); + res.json(JSON.parse(data)); + } catch (err) { + res.status(500).json({ error: 'Failed to load category tree' }); + } + }); + + // Serve category images + app.get('/img/cat/:id.avif', (req, res) => { + const { id } = req.params; + const imagePath = path.join(CACHE_DIR, 'img', 'categories', `${id}.avif`); + res.sendFile(path.resolve(imagePath), (err) => { + if (err) { + res.status(404).send('Image not found'); + } + }); + }); + + // Serve index.html + app.get('/', (req, res) => { + const htmlPath = path.join(__dirname, 'index.html'); + console.log('Attempting to serve:', htmlPath); + res.sendFile(htmlPath, (err) => { + if (err) { + console.error('Error serving index.html:', err); + res.status(500).send('Error loading page'); + } + }); + }); + + app.listen(PORT, HOST, () => { + console.log(`🌐 Server running on http://${HOST}:${PORT}`); + }); +}