Skip to content

Commit

Permalink
Merge pull request #62 from vtexdocs/fix/image-script
Browse files Browse the repository at this point in the history
fix: images script
  • Loading branch information
julia-rabello authored Dec 3, 2024
2 parents 3f26fb4 + e5d61f6 commit 99f886c
Show file tree
Hide file tree
Showing 2,434 changed files with 14,890 additions and 8,306 deletions.
40 changes: 0 additions & 40 deletions .github/workflows/update-images.yml

This file was deleted.

2 changes: 2 additions & 0 deletions docs-utils/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

93 changes: 67 additions & 26 deletions docs-utils/update-all-images.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,80 @@
// This script has an error: it passes absolute paths to the function updateImages. So the updated image links are wrong. This can be fixed manually using VSCode search.
const fs = require('fs').promises; // Use the promise-based version of fs
const fs = require('fs');
const path = require('path');
const { updateImages } = require('./update-images.js'); // Ensure this returns a promise or is async

const targetDir = path.join(__dirname, '../docs');
let articleNumber = 0;
let allArticles = [];
const docsDirEN = path.join(__dirname, '../docs/en/');
const docsDirPT = path.join(__dirname, '../docs/pt/');
const docsDirES = path.join(__dirname, '../docs/es/');

async function iterateFiles(dir) {
const files = await fs.readdir(dir, { withFileTypes: true });
const { updateImages } = require('./update-images.js');

for (const file of files) {
const fullPath = path.join(dir, file.name).replace(/\\/g, '/');
const MAX_CONCURRENT_FILES = 100;

if (file.isDirectory()) {
// If it's a directory, recursively search it
await iterateFiles(fullPath);
} else if (file.isFile() && (file.name.endsWith('.md') || file.name.endsWith('.mdx'))) {
// If it's a .md or .mdx file, do something with it
articleNumber++;
allArticles.push(fullPath);
let activeFiles = 0;
let fileQueue = [];

// Function to process each Markdown file
async function processFile(filePath) {
try {
// console.log(`Updating images for: ${filePath}`);
await updateImages(filePath); // Wait for updateImages to finish before proceeding
// console.log(`Finished updating images for: ${filePath}`);
} catch (error) {
console.error(`Error processing file: ${filePath}`, error);
} finally {
activeFiles--;
if (fileQueue.length > 0) {
const nextFile = fileQueue.shift();
await processFile(nextFile);
}
}
}
}

async function processArticles() {
for (const article of allArticles) {
console.log(`Updating images for: ${article}`);
await updateImages(article); // Wait for updateImages to finish before proceeding
console.log(`Finished updating images for: ${article}`);
}
// Function to recursively process files in directories
async function processDirectory(dirPath) {
try {
const files = fs.readdirSync(dirPath);

for (const file of files) {
const filePath = path.join(dirPath, file);
const stats = fs.statSync(filePath);

if (stats.isDirectory()) {
await processDirectory(filePath);
} else if (path.extname(file) === '.md') {
if (activeFiles < MAX_CONCURRENT_FILES) {
activeFiles++;
await processFile(filePath);
} else {
fileQueue.push(filePath);
}
}
}
} catch (error) {
console.error('Error processing directory:', error);
}
}

// Start iterating from the target directory and process articles sequentially
async function updateAllImages() {
console.log("Updating all images...");
await processDirectory(docsDirEN);
await processDirectory(docsDirPT);
await processDirectory(docsDirES);

// Wait until all files are processed
while (activeFiles > 0 || fileQueue.length > 0) {
await new Promise(resolve => setTimeout(resolve, 100));
}

console.log("Finished replacing all images in markdown files.");
}

(async () => {
await iterateFiles(targetDir); // First gather all the articles
await processArticles(); // Then process them one by one
try {
await updateAllImages();
} catch (error) {
console.error('Error during image updates:', error);
}
})();

module.exports = { updateAllImages }
156 changes: 104 additions & 52 deletions docs-utils/update-images.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,130 @@
const fs = require('fs')
const path = require('path')
// const frontmatter = require('front-matter')
const imageDownloader = require('image-downloader')
const fs = require('fs');
const path = require('path');
const imageDownloader = require('image-downloader');
const sharp = require('sharp');

const baseURL = 'https://raw.githubusercontent.com/vtexdocs/help-center-content/refs/heads/main/'
const baseURL = 'https://raw.githubusercontent.com/vtexdocs/help-center-content/refs/heads/main/';

const isValidExtension = (ext) => {
return /^[a-zA-Z0-9]*$/.test(ext)
}
const isValidExtension = (ext) => /^[a-zA-Z0-9]*$/.test(ext);

const getExtension = (url) => {
let dotIndex = url.length - 1
while (dotIndex >= 0 && url[dotIndex] !== '.') {
dotIndex--
}
let dotIndex = url.lastIndexOf('.');
if (dotIndex < 0) return 'png'; // Default to 'png' if no extension
const ext = url.substring(dotIndex + 1);
return isValidExtension(ext) ? ext : 'png';
};

const ext = url.substring(dotIndex + 1)
if (dotIndex < 0 || !isValidExtension(ext)) return 'png'
return ext
}
const checkAndCompressImage = async (filePath) => {
try {
// Ensure the file is a GIF
const fileExt = path.extname(filePath).toLowerCase();
if (fileExt !== '.gif') {
console.log(`Skipping non-GIF file: ${filePath}`);
return filePath; // Return original path if it's not a GIF
}

const updateImages = async (filepath) => {
const stats = fs.statSync(filePath);
const fileSizeInMB = stats.size / (1024 * 1024); // Convert bytes to MB

if (fileSizeInMB > 100) { // If file exceeds 100MB
console.log(`File ${filePath} is over 100MB (${fileSizeInMB.toFixed(2)} MB). Compressing...`);
let compressedFilePath = filePath.replace(/(\.\w+)$/, '_compressed$1'); // Add "_compressed" before the extension
await sharp(filePath, {limitInputPixels: 0, animated: true })
.resize(800)
.gif({ interFrameMaxError: 32 })
.toFile(compressedFilePath);

// Check if original file exists and delete it
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath); // Delete the original file
console.log(`Original file deleted: ${filePath}`);
fs.renameSync(compressedFilePath, filePath);
console.log(`File renamed: ${filePath}`);
} else {
console.log(`Original file not found, skipping deletion: ${filePath}`);
}

console.log ('Running update-images.js')
return filePath; // Return compressed file path
} else {
console.log(`File ${filePath} is within the size limit (${fileSizeInMB.toFixed(2)} MB).`);
return filePath; // Return original file path if no compression needed
}
} catch (error) {
console.error(`Error checking or compressing file ${filePath}:`, error.message);
return filePath; // Return original path if there's an error
}
};

const updateImages = async (filepath) => {
if (!filepath) {
console.error('Received undefined filePath in updateImages');
return; // Early return if filePath is undefined
return;
}

const resolvedFilepath = path.resolve(filepath); // Ensure the path is absolute
console.log(`Processing images in this file: ${resolvedFilepath}`);

if (!fs.existsSync(resolvedFilepath)) {
console.error(`File not found: ${resolvedFilepath}`);
return;
}
const content = fs.readFileSync(filepath, 'utf-8')

const images = []
let imageIndex = 1

const content = fs.readFileSync(resolvedFilepath, 'utf-8');

const images = [];
let imageIndex = 1;

const replaceURL = (match, extra, url) => {
const isMarkdownBlock = match.startsWith('![')
if (url.startsWith(baseURL)) return match
const isMarkdownBlock = match.startsWith('![');
if (url.startsWith(baseURL)) return match; // Skip processing for already processed URLs

if (url.startsWith('//')) {
url = `https:${url}`
url = `https:${url}`;
}

let newURL = ''
const ext = getExtension(url)

const newfilepath = `${filepath.split('.')[0]}_${imageIndex}.${ext}`
const ext = getExtension(url);
const parsedPath = path.parse(resolvedFilepath); // Safely parse the path
const newFilepath = parsedPath.dir + '/' + `${parsedPath.name}_${imageIndex}.${ext}`; // Create new file path

images.push({
filepath: path.resolve(newfilepath),
url
})

newURL = `${baseURL}${filepath.split('.')[0]}_${imageIndex}.${ext}`
imageIndex++

return isMarkdownBlock ? `![${extra}](${newURL})` : `<img ${extra}src="${newURL}"`
}
filepath: path.resolve(newFilepath),
url,
});

const encodedFilepath = encodeURI(path.relative('.', newFilepath).replace(/\\/g, "/"));
const newURL = `${baseURL}${encodedFilepath}`;

const newContent = content
imageIndex++;

return isMarkdownBlock ? `![${extra}](${newURL})` : `<img ${extra}src="${newURL}"`;
};

let newContent = content
.replace(/\!\[(.*)\]\((.*)\)/g, replaceURL)
.replace(/<img (.*)src="(.*)"/g, replaceURL)
.replace(/<img (.*)src="(.*)"/g, replaceURL);

try {
for (let i = 0; i < images.length; i++) {
await imageDownloader.image({
url: images[i].url,
dest: images[i].filepath
})
for (const image of images) {
console.log(`Downloading image from: ${image.url} to ${image.filepath}`);
await imageDownloader.image({
url: image.url,
dest: image.filepath,
});

// Check and compress the image if needed
let compressedFilePath = await checkAndCompressImage(image.filepath);
}

fs.writeFileSync(filepath, newContent)

fs.writeFileSync(resolvedFilepath, newContent);
console.log(`Updated file: ${resolvedFilepath}`);
} catch (err) {
console.log("Couldn't download some of the images, leaving file as it is...\n\t",filepath)
console.error(`Error updating images for: ${resolvedFilepath}`, err);
}
}
};

const filepath = process.argv[2]
updateImages(filepath)
if (require.main === module) {
const filepath = process.argv[2]; // run with this command: node docs-utils/update-images.js "{fullFilePath}"
updateImages(filepath);
}

module.exports = { updateImages };
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ slugEN: 2018-02-15-my-orders-is-now-available-on-extension-store
locale: en
legacySlug: my-orders-is-now-available-on-extension-store
announcementImageID: ''
announcementSynopsisEN: "Starting June 5, the use of the 'My Orders' page's extension will be required for all stores."
announcementSynopsisEN: "Starting June 5, the use of the "My Orders" page's extension will be required for all stores."
---

>ℹ️ As announced here, **My Orders extension** is already mandatory to all stores. Since **June 6**, it is available by default and is not accessible through VTEX's App Store anymore.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: 'Shopping Season: Get your store ready with our Best Practices Guide'
id: AUjUgR4FNyv5oVyhrSLT2
status: PUBLISHED
createdAt: 2024-10-21T20:58:45.914Z
updatedAt: 2024-10-21T21:09:41.612Z
publishedAt: 2024-10-21T21:09:41.612Z
contentType: updates
productTeam: Others
author: 2Gy429C47ie3tL9XUEjeFL
slugEN: 2024-10-21-shopping-season-get-your-store-ready-with-our-best-practices-guide
locale: en
legacySlug: shopping-season-get-your-store-ready-with-our-best-practices-guide
announcementImageID: ''
announcementSynopsisEN: "Follow our recommendations and exclusive tips to make the most out of this year's Black Friday."
---

__Black Friday__ is coming. Despite its official date (__November 29__), many stores will start their campaigns a lot earlier. To make sure you'll make the most out of one of the main events on the retail calendar, start prepping soon.

As in previous years, we came up with a guide with recommendations and exclusive tips that will help you ensure your store's health and sales.

The guide is available to all our clients and partners and may be accessed through the homepage of your Admin or directly through the URL

```
https://{accountName}.myvtex.com/admin/shopping-season
```

Simply replace `{accountName}` with your store's [account name](https://help.vtex.com/en/tutorial/o-que-e-account-name--i0mIGLcg3QyEy8OCicEoC#).
Loading

0 comments on commit 99f886c

Please sign in to comment.