wiki-img
Version:
Easily search & download wikipedia images (Zero dependency lib)
121 lines (107 loc) • 3.11 kB
text/typescript
import { get } from "node:https";
import { createWriteStream } from "node:fs";
import path from "node:path";
export interface Thumbnail {
mimetype: string;
size: null | number;
width: number;
height: number;
duration: null | number;
url: string;
}
export interface Page {
id: number;
key: string;
title: string;
excerpt: string;
description: string;
thumbnail?: Thumbnail;
}
interface SearchResult {
pages: Array<Page>;
}
// //u.wiki.org/wiki/commons/thumb/2/23/elon.jpg/121px-elon.jpg
const parseRawImg = (src: string) => {
const splitted = src.split("/");
splitted.pop(); // we dont need the last 121px-elon
splitted.splice(5, 1); // get rid of thumb
return `https:${splitted.join("/")}`; // put everything back
};
const saveImg = (page: Page, dir: string) => {
const rawThumbUrl = parseRawImg(page.thumbnail.url);
// eg image/jpeg
const fileExt = page.thumbnail.mimetype.split("/")[1];
return new Promise((resolve, reject) => {
const addr = new URL(rawThumbUrl);
const imgreq = get(
{
host: addr.host,
method: "GET",
port: 443,
path: addr.pathname,
headers: {
Accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"User-Agent": "Mozilla/5.0 ",
},
},
(res) => {
if (res.statusCode == 200) {
const imgPath = path.resolve(dir, `${page.key}.${fileExt}`);
const fstream = createWriteStream(imgPath, {
encoding: "binary",
});
// res.pipe(process.stdout);
res.pipe(fstream);
fstream.on("error", reject);
fstream.on("finish", () => {
resolve(true);
});
return;
}
reject(`Failed to get img with status ${res.statusMessage}`);
}
);
imgreq.end();
});
};
/**
* Query and download image from wikipedia
* @param {string} query - Search term for wikipedia
* @param {string} dir - Relative path of image to be saved
* @returns {Promise} Promise with info about the search
* @example
// get lady gaga image in celebs directory
getWikiImg("Lady gaga", "./celebs")
.then((res) => console.log(res))
.catch((err) => console.log("failed to get img", err));
*/
export const getWikiImg = (
query: string,
dir: string = "./"
): Promise<Page | Error> => {
return new Promise((resolve, reject) => {
const path = "https://api.wikimedia.org/core/v1/wikipedia/en/search";
const imgreq = get(`${path}/title?q=${query}&limit=1`);
imgreq.on("response", (res) => {
let body = "";
res.on("data", (d) => {
body += d;
});
res.on("end", async () => {
const json: SearchResult = JSON.parse(body);
const page = json.pages[0];
const thumb = page?.thumbnail?.url;
if (!thumb) {
return reject("No thumbnail found");
}
try {
await saveImg(page, dir);
resolve(page);
} catch (err) {
reject(err);
}
});
});
});
};