This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch fix-image-url
in repository https://gitbox.apache.org/repos/asf/opendal.git

commit 9ee2b811e130b0cbf1a860bc2473a7fd504b98c1
Author: Xuanwo <[email protected]>
AuthorDate: Mon Mar 10 19:28:05 2025 +0800

    fix(website): Handling svg image correctly
    
    Signed-off-by: Xuanwo <[email protected]>
---
 website/plugins/image-ssr-plugin.js | 167 +++++++++++++++++++++---------------
 1 file changed, 99 insertions(+), 68 deletions(-)

diff --git a/website/plugins/image-ssr-plugin.js 
b/website/plugins/image-ssr-plugin.js
index 42b8ae657..a2aee0fbd 100644
--- a/website/plugins/image-ssr-plugin.js
+++ b/website/plugins/image-ssr-plugin.js
@@ -22,105 +22,136 @@ const fs = require("fs-extra");
 const axios = require("axios");
 const { createHash } = require("crypto");
 const cheerio = require("cheerio");
+const url = require("url");
 
-module.exports = function () {
-  return {
-    name: "docusaurus-image-ssr",
+module.exports = function (context) {
+  const processedImages = new Map();
 
-    async postBuild({ outDir }) {
-      console.log("Localizing external images in build output...");
+  function getImageFilename(imageUrl) {
+    const hash = createHash("md5").update(imageUrl).digest("hex");
+    let ext = ".jpg";
 
-      const imagesDir = path.join(outDir, "img/external");
-      await fs.ensureDir(imagesDir);
+    try {
+      const parsedUrl = url.parse(imageUrl);
+      const pathname = parsedUrl.pathname || "";
 
-      const imageCache = new Map();
+      const pathExt = path.extname(pathname);
+      if (pathExt) ext = pathExt;
 
-      async function downloadImage(url) {
-        if (imageCache.has(url)) {
-          return imageCache.get(url);
-        }
-
-        try {
-          const hash = createHash("md5").update(url).digest("hex");
-          const ext = path.extname(url) || ".jpg";
-          const filename = `${hash}${ext}`;
-          const imagePath = path.join(imagesDir, filename);
-
-          if (!fs.existsSync(imagePath)) {
-            console.log(`Downloading: ${url}`);
-            const response = await axios({
-              url: url,
-              responseType: "arraybuffer",
-              timeout: 15000,
-              headers: {
-                "User-Agent":
-                  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36",
-              },
-            });
-
-            await fs.writeFile(imagePath, response.data);
-          }
+      if (
+        imageUrl.includes("img.shields.io") ||
+        imageUrl.includes("actions?query")
+      ) {
+        ext = ".svg";
+      }
+    } catch (e) {}
+
+    return `${hash}${ext}`;
+  }
+
+  async function downloadImage(imageUrl, buildDir) {
+    if (processedImages.has(imageUrl)) {
+      return processedImages.get(imageUrl);
+    }
+
+    try {
+      const filename = getImageFilename(imageUrl);
+      const buildImagesDir = path.join(buildDir, "img/external");
+      const buildOutputPath = path.join(buildImagesDir, filename);
+
+      fs.ensureDirSync(buildImagesDir);
+
+      if (!fs.existsSync(buildOutputPath)) {
+        console.log(`Downloading image: ${imageUrl}`);
+
+        const response = await axios({
+          url: imageUrl,
+          responseType: "arraybuffer",
+          timeout: 20000,
+          headers: {
+            "User-Agent":
+              "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
+            Accept: "image/webp,image/apng,image/*,*/*;q=0.8",
+          },
+          maxRedirects: 5,
+          validateStatus: (status) => status < 400,
+        });
 
-          const localUrl = `/img/external/${filename}`;
-          imageCache.set(url, localUrl);
-          return localUrl;
-        } catch (error) {
-          console.error(`Failed to download ${url}: ${error.message}`);
-          return url;
-        }
+        await fs.writeFile(buildOutputPath, response.data);
       }
 
-      const htmlFiles = [];
+      const localUrl = `/img/external/${filename}`;
+      processedImages.set(imageUrl, localUrl);
+      return localUrl;
+    } catch (error) {
+      console.error(`Error downloading image ${imageUrl}: ${error.message}`);
+      return imageUrl;
+    }
+  }
 
-      async function findHtmlFiles(dir) {
-        const files = await fs.readdir(dir);
+  return {
+    name: "docusaurus-ssr-image-plugin",
 
-        for (const file of files) {
-          const filePath = path.join(dir, file);
-          const stat = await fs.stat(filePath);
+    async postBuild({ outDir }) {
+      console.log("Processing HTML files for external images...");
 
-          if (stat.isDirectory()) {
-            await findHtmlFiles(filePath);
-          } else if (file.endsWith(".html")) {
-            htmlFiles.push(filePath);
+      const htmlFiles = [];
+
+      async function findHtmlFiles(dir) {
+        const entries = await fs.readdir(dir, { withFileTypes: true });
+
+        for (const entry of entries) {
+          const fullPath = path.join(dir, entry.name);
+          if (entry.isDirectory()) {
+            await findHtmlFiles(fullPath);
+          } else if (entry.name.endsWith(".html")) {
+            htmlFiles.push(fullPath);
           }
         }
       }
 
       await findHtmlFiles(outDir);
-      console.log(`Found ${htmlFiles.length} HTML files`);
 
       for (const htmlFile of htmlFiles) {
         const html = await fs.readFile(htmlFile, "utf8");
-        const $ = cheerio.load(html);
+        let $ = cheerio.load(html);
+        let modified = false;
 
-        const externalImages = $('img[src^="http"]');
-        if (externalImages.length === 0) continue;
+        const externalImages = $("img").filter((_, el) => {
+          const src = $(el).attr("src");
+          return src && src.startsWith("http");
+        });
 
-        console.log(
-          `Processing ${externalImages.length} images in ${htmlFile}`,
-        );
+        if (externalImages.length === 0) continue;
 
-        const promises = [];
+        const downloadPromises = [];
 
         externalImages.each((_, img) => {
           const element = $(img);
-          const url = element.attr("src");
-
-          promises.push(
-            downloadImage(url).then((localUrl) => {
-              element.attr("src", localUrl);
-              element.attr("data-original-src", url);
-            }),
+          const imageUrl = element.attr("src");
+
+          if (!imageUrl || !imageUrl.startsWith("http")) return;
+
+          downloadPromises.push(
+            downloadImage(imageUrl, outDir)
+              .then((localUrl) => {
+                if (localUrl !== imageUrl) {
+                  element.attr("src", localUrl);
+                  modified = true;
+                }
+              })
+              .catch(() => {}),
           );
         });
 
-        await Promise.all(promises);
+        await Promise.all(downloadPromises);
 
-        await fs.writeFile(htmlFile, $.html());
+        if (modified) {
+          await fs.writeFile(htmlFile, $.html());
+        }
       }
 
-      console.log("Image localization complete!");
+      console.log(`Processed ${processedImages.size} external images`);
     },
   };
 };

Reply via email to