Initial init
This commit is contained in:
commit
d4d6fab753
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
public/
|
||||||
|
images/
|
||||||
|
*.html
|
||||||
|
*.css
|
||||||
|
*.png
|
||||||
|
*.jpg
|
||||||
|
*.jpeg
|
||||||
|
*.gif
|
||||||
|
images.json
|
||||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
FROM node:18-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
CMD ["node", "fetchImages.js"]
|
||||||
25
docker-compose.yml
Normal file
25
docker-compose.yml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
gallery:
|
||||||
|
build: .
|
||||||
|
volumes:
|
||||||
|
- ./public:/app/public
|
||||||
|
- ./images:/app/images
|
||||||
|
expose:
|
||||||
|
- "3000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.gallery-secure.entrypoints=https"
|
||||||
|
- "traefik.http.routers.gallery-secure.rule=Host(`analog.uplink.tel`)"
|
||||||
|
- "traefik.http.routers.gallery-secure.tls.certresolver=http"
|
||||||
|
- "traefik.http.services.gallery.loadbalancer.server.port=3000"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
web:
|
||||||
|
external: true
|
||||||
102
fetchImages.js
Normal file
102
fetchImages.js
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { pipeline } from 'stream/promises';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
apiKey: 'w7bVb1xk3mTQg4RuAHR0000lWnv0iaJD2Rq4M0Y1SLU',
|
||||||
|
albumId: 'f6303d3d-5343-4579-a92e-c1eb37518ae7',
|
||||||
|
baseUrl: 'https://photos.ghost.tel',
|
||||||
|
outputDir: './images' // Directory to store downloaded images
|
||||||
|
};
|
||||||
|
|
||||||
|
async function downloadImage(imageUrl, fileName, apiKey) {
|
||||||
|
const response = await axios({
|
||||||
|
method: 'GET',
|
||||||
|
url: imageUrl,
|
||||||
|
responseType: 'stream',
|
||||||
|
headers: {
|
||||||
|
'x-api-key': apiKey
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const outputPath = path.join(config.outputDir, fileName);
|
||||||
|
await pipeline(response.data, fs.createWriteStream(outputPath));
|
||||||
|
return outputPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAlbumAssets() {
|
||||||
|
try {
|
||||||
|
// Create output directory if it doesn't exist
|
||||||
|
if (!fs.existsSync(config.outputDir)) {
|
||||||
|
fs.mkdirSync(config.outputDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `${config.baseUrl}/api/albums/${config.albumId}`;
|
||||||
|
console.log('Fetching album data from:', url);
|
||||||
|
|
||||||
|
const response = await axios.get(url, {
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'x-api-key': config.apiKey
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.data) {
|
||||||
|
throw new Error('No data received from the API');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('First asset metadata sample:', JSON.stringify(response.data.assets[0], null, 2));
|
||||||
|
console.log(`Found ${response.data.assets.length} assets in album`);
|
||||||
|
|
||||||
|
const images = [];
|
||||||
|
for (const asset of response.data.assets) {
|
||||||
|
const originalUrl = `${config.baseUrl}/api/assets/${asset.id}/original`;
|
||||||
|
const fileName = `${asset.id}_${asset.originalFileName || 'untitled'}`;
|
||||||
|
|
||||||
|
console.log(`Downloading: ${fileName}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const localPath = await downloadImage(originalUrl, fileName, config.apiKey);
|
||||||
|
|
||||||
|
images.push({
|
||||||
|
id: asset.id,
|
||||||
|
originalUrl,
|
||||||
|
localPath,
|
||||||
|
name: asset.originalFileName || 'Untitled',
|
||||||
|
thumbnailUrl: `${config.baseUrl}/api/asset/thumbnail/${asset.id}`,
|
||||||
|
description: asset.exifInfo?.description || '',
|
||||||
|
metadata: {
|
||||||
|
createdAt: asset.createdAt,
|
||||||
|
fileCreatedAt: asset.fileCreatedAt,
|
||||||
|
deviceAssetId: asset.deviceAssetId,
|
||||||
|
type: asset.type
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Successfully downloaded: ${fileName}`);
|
||||||
|
} catch (downloadError) {
|
||||||
|
console.error(`Failed to download ${fileName}:`, downloadError.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the metadata
|
||||||
|
fs.writeFileSync('./images.json', JSON.stringify(images, null, 2));
|
||||||
|
console.log(`Successfully processed ${images.length} images`);
|
||||||
|
|
||||||
|
return images;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching album assets:', error.message);
|
||||||
|
if (error.response) {
|
||||||
|
console.error('Response status:', error.response.status);
|
||||||
|
console.error('Response data:', error.response.data);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the function
|
||||||
|
getAlbumAssets().catch(error => {
|
||||||
|
console.error('Failed to fetch images:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
131
generateSite.js
Normal file
131
generateSite.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
const fs = require('fs').promises;
|
||||||
|
const path = require('path');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
|
async function generateSite() {
|
||||||
|
// Read the images data
|
||||||
|
const imagesData = JSON.parse(
|
||||||
|
await fs.readFile('images.json', 'utf-8')
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(imagesData);
|
||||||
|
|
||||||
|
// Create output directory if it doesn't exist
|
||||||
|
await fs.mkdir('public', { recursive: true });
|
||||||
|
|
||||||
|
// Copy the CSS file to public directory
|
||||||
|
await fs.copyFile('public/styles.css', 'public/styles.css').catch(err => {
|
||||||
|
console.error('Error copying CSS file:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy the favicon
|
||||||
|
await fs.copyFile('public/AnalogCameraS.png', 'public/favicon.png').catch(err => {
|
||||||
|
console.error('Error copying favicon:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate individual pages for each image
|
||||||
|
for (let i = 0; i < imagesData.length; i++) {
|
||||||
|
const image = imagesData[i];
|
||||||
|
const prevImage = imagesData[i > 0 ? i - 1 : imagesData.length - 1];
|
||||||
|
const nextImage = imagesData[(i + 1) % imagesData.length];
|
||||||
|
|
||||||
|
// Use image ID for filename
|
||||||
|
const fileName = `${image.id}.html`;
|
||||||
|
const prevFileName = `${prevImage.id}.html`;
|
||||||
|
const nextFileName = `${nextImage.id}.html`;
|
||||||
|
|
||||||
|
const html = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>${image.description || `Image ${i + 1}`}</title>
|
||||||
|
<link rel="stylesheet" href="/styles.css">
|
||||||
|
<link rel="icon" type="image/png" href="/favicon.png">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="image-container">
|
||||||
|
${image?.localPath || 'No image URL available'
|
||||||
|
? `<img src="${image?.localPath || 'No image URL available'}" alt="${image.metadata.description || ''}">`
|
||||||
|
: '<p>Image not available</p>'
|
||||||
|
}
|
||||||
|
${image.description ? `<p class="description">${image.description}</p>` : ''}
|
||||||
|
<div class="navigation">
|
||||||
|
<a href="${prevFileName}">←</a>
|
||||||
|
<a href="${nextFileName}">→</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
|
||||||
|
await fs.writeFile(`public/${fileName}`, html);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update index.html to redirect to first image's ID
|
||||||
|
const indexHtml = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="refresh" content="0; url=${imagesData[0].id}.html">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Redirecting...
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
|
||||||
|
await fs.writeFile('public/index.html', indexHtml);
|
||||||
|
|
||||||
|
console.log('Site generated successfully!');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function serveStaticSite(port = 3000) {
|
||||||
|
const server = http.createServer(async (req, res) => {
|
||||||
|
try {
|
||||||
|
// Convert URL to filesystem path
|
||||||
|
let filePath;
|
||||||
|
if (req.url.startsWith('/images/')) {
|
||||||
|
// Serve directly from images folder
|
||||||
|
filePath = req.url.slice(1); // Remove leading slash
|
||||||
|
} else {
|
||||||
|
// Serve from public folder
|
||||||
|
filePath = path.join('public', req.url === '/' ? 'index.html' : req.url);
|
||||||
|
|
||||||
|
// Add .html extension if no extension exists
|
||||||
|
if (!path.extname(filePath)) {
|
||||||
|
filePath += '.html';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = await fs.readFile(filePath);
|
||||||
|
|
||||||
|
// Set content type based on file extension
|
||||||
|
const ext = path.extname(filePath).toLowerCase();
|
||||||
|
const contentType = {
|
||||||
|
'.html': 'text/html',
|
||||||
|
'.css': 'text/css',
|
||||||
|
'.jpg': 'image/jpeg',
|
||||||
|
'.jpeg': 'image/jpeg',
|
||||||
|
'.png': 'image/png',
|
||||||
|
'.gif': 'image/gif',
|
||||||
|
}[ext] || 'application/octet-stream';
|
||||||
|
|
||||||
|
res.writeHead(200, { 'Content-Type': contentType });
|
||||||
|
res.end(content);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error serving file:', error);
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end('Not found');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(port, () => {
|
||||||
|
console.log(`Server running at http://localhost:${port}/`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the site and then serve it
|
||||||
|
generateSite()
|
||||||
|
.then(() => serveStaticSite())
|
||||||
|
.catch(console.error);
|
||||||
|
|
||||||
205
package-lock.json
generated
Normal file
205
package-lock.json
generated
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
{
|
||||||
|
"name": "static-gallery",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "static-gallery",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.7.9",
|
||||||
|
"node-fetch": "^3.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.7.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
|
||||||
|
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.6",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/data-uri-to-buffer": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fetch-blob": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/jimmywarting"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "paypal",
|
||||||
|
"url": "https://paypal.me/jimmywarting"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-domexception": "^1.0.0",
|
||||||
|
"web-streams-polyfill": "^3.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20 || >= 14.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||||
|
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/formdata-polyfill": {
|
||||||
|
"version": "4.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||||
|
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fetch-blob": "^3.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.20.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-domexception": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/jimmywarting"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://paypal.me/jimmywarting"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-fetch": {
|
||||||
|
"version": "3.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||||
|
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"data-uri-to-buffer": "^4.0.0",
|
||||||
|
"fetch-blob": "^3.1.4",
|
||||||
|
"formdata-polyfill": "^4.0.10"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/node-fetch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/web-streams-polyfill": {
|
||||||
|
"version": "3.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||||
|
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
package.json
Normal file
13
package.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "static-gallery",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "fetchImages.js",
|
||||||
|
"scripts": {
|
||||||
|
"fetch": "node fetchImages.js",
|
||||||
|
"generate": "node generateSite.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.7.9",
|
||||||
|
"node-fetch": "^3.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user