From 0f38164a2eea66acb3c0a767a7e0bf948eccd764 Mon Sep 17 00:00:00 2001 From: ryuupendragon Date: Tue, 12 Aug 2025 20:48:30 +0530 Subject: [PATCH] WF test using selhst icons --- .crow/docker-build.yaml | 2 +- Dockerfile | 15 +++---- package.json | 13 ++++++ server.js | 89 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 package.json create mode 100644 server.js diff --git a/.crow/docker-build.yaml b/.crow/docker-build.yaml index 1bab266..082793a 100644 --- a/.crow/docker-build.yaml +++ b/.crow/docker-build.yaml @@ -10,7 +10,7 @@ steps: - name: publish-next-agent image: woodpeckerci/plugin-docker-buildx settings: - repo: ryuupendragon/caddy-test + repo: ryuupendragon/icons-test dockerfile: Dockerfile platforms: linux/amd64,linux/arm64/v8 tag: latest diff --git a/Dockerfile b/Dockerfile index 4b1aef3..0e94eff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,11 @@ -FROM caddy:2.10.0-builder AS builder +FROM node:18-alpine +WORKDIR /app -RUN xcaddy build \ - --with github.com/hslatman/caddy-crowdsec-bouncer/http \ - --with github.com/hslatman/caddy-crowdsec-bouncer/layer4 \ - --with github.com/hslatman/caddy-crowdsec-bouncer/appsec +COPY package.json ./ +RUN npm install -FROM caddy:2.10.0 +COPY server.js . -COPY --from=builder /usr/bin/caddy /usr/bin/caddy \ No newline at end of file +EXPOSE 4050 + +CMD ["node", "server.js"] \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..6ddc042 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "test-repo", + "version": "1.0.0", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "type": "module", + "dependencies": { + "express": "^4.18.2", + "node-fetch": "^3.3.0" + } +} \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 0000000..b73a4fa --- /dev/null +++ b/server.js @@ -0,0 +1,89 @@ +import express from 'express' +import fetch from 'node-fetch' +import path from 'path' + +const app = express() +const PORT = 4050 +const CDN_ROOT = 'https://cdn.jsdelivr.net/gh/selfhst/icons' +const CDN_PATH = 'svg' + +async function fileExists(url) { + try { + const resp = await fetch(url, { method: 'HEAD' }); + return resp.ok; + } catch { + return false; + } +} + +async function fetchAndPipe(url, res) { + const response = await fetch(url); + if (!response.ok) return res.status(404).send('File not found'); + res.type(path.extname(url).slice(1)); + response.body.pipe(res); +} + +app.get('/*', async (req, res) => { + const urlPath = req.path; + const extMatch = urlPath.match(/\.(\w+)$/); + if (!extMatch) + return res.status(404).send('File extension missing'); + + const ext = extMatch[1].toLowerCase(); + if (!['png', 'webp', 'svg'].includes(ext)) + return res.status(404).send('Format not supported'); + + const filename = urlPath.slice(1); + const lowerFilename = filename.toLowerCase(); + + const isSuffix = lowerFilename.endsWith('-light.svg') || lowerFilename.endsWith('-dark.svg'); + + if (isSuffix) { + return fetchAndPipe(`${CDN_ROOT}/${CDN_PATH}/${filename}`, res); + } + + let mainUrl; + if (ext === 'png') { + mainUrl = `${CDN_ROOT}/png/${filename}`; + } else if (ext === 'webp') { + mainUrl = `${CDN_ROOT}/webp/${filename}`; + } else if (ext === 'svg') { + mainUrl = `${CDN_ROOT}/svg/${filename}`; + } else { + mainUrl = null; + } + + const hasColor = !!req.query['color'] && req.query['color'].trim() !== ''; + + if (ext === 'svg') { + if (hasColor) { + const baseName = filename.replace(/\.(png|webp|svg)$/, ''); + const suffixUrl = `${CDN_ROOT}/${CDN_PATH}/${baseName}-light.svg`; + if (await fileExists(suffixUrl)) { + let svgContent = await fetch(suffixUrl).then(r => r.text()); + const color = req.query['color'].startsWith('#') ? req.query['color'] : `#${req.query['color']}`; + svgContent = svgContent + .replace(/style="[^"]*fill:\s*#fff[^"]*"/gi, (match) => { + console.log('Replacing style fill:', match); + return match.replace(/fill:\s*#fff/gi, `fill:${color}`); + }) + .replace(/fill="#fff"/gi, `fill="${color}"`); + return res.type('image/svg+xml').send(svgContent); + } else { + return fetchAndPipe(mainUrl, res); + } + } else { + return fetchAndPipe(mainUrl, res); + } + } else { + // PNG/WebP: serve directly + return fetchAndPipe(mainUrl, res); + } +}); + +app.get('/', (req, res) => { + res.send('Self-hosted icon server'); +}); +app.listen(PORT, () => { + console.log(`Listening on port ${PORT}`); +}); \ No newline at end of file