132 lines
3.7 KiB
JavaScript
132 lines
3.7 KiB
JavaScript
// appMetadata.js
|
|
import axios from "axios";
|
|
import * as cheerio from "cheerio";
|
|
import sizeOf from "image-size";
|
|
import sharp from "sharp";
|
|
|
|
export async function getAppMetadata(baseUrl) {
|
|
console.log(baseUrl);
|
|
try {
|
|
const res = await axios.get(baseUrl, { timeout: 3000 });
|
|
const $ = cheerio.load(res.data);
|
|
|
|
// -------------------------------
|
|
// 1. Nome più corto
|
|
// -------------------------------
|
|
const nameCandidates = [
|
|
$('meta[property="og:site_name"]').attr("content"),
|
|
$('meta[name="application-name"]').attr("content"),
|
|
$('meta[property="og:title"]').attr("content"),
|
|
$("title").text().trim()
|
|
].filter(Boolean);
|
|
|
|
const name = nameCandidates.length > 0
|
|
? nameCandidates.sort((a, b) => a.length - b.length)[0]
|
|
: "no_name";
|
|
|
|
// -------------------------------
|
|
// 2. Icone HTML
|
|
// -------------------------------
|
|
const htmlIcons = [];
|
|
$("link[rel*='icon']").each((_, el) => {
|
|
const href = $(el).attr("href");
|
|
const sizes = $(el).attr("sizes") || "";
|
|
if (href) htmlIcons.push({ href, sizes });
|
|
});
|
|
|
|
// -------------------------------
|
|
// 3. Manifest.json
|
|
// -------------------------------
|
|
let manifestIcons = [];
|
|
const manifestHref = $('link[rel="manifest"]').attr("href");
|
|
|
|
if (manifestHref) {
|
|
try {
|
|
const manifestUrl = new URL(manifestHref, baseUrl).href;
|
|
const manifestRes = await axios.get(manifestUrl, { timeout: 3000 });
|
|
const manifest = manifestRes.data;
|
|
|
|
if (manifest.icons && Array.isArray(manifest.icons)) {
|
|
manifestIcons = manifest.icons.map(icon => ({
|
|
href: icon.src,
|
|
sizes: icon.sizes || ""
|
|
}));
|
|
}
|
|
} catch {}
|
|
}
|
|
|
|
// -------------------------------
|
|
// 4. Fallback 4 icone
|
|
// -------------------------------
|
|
const fallbackPaths = [
|
|
"/favicon.ico",
|
|
"/favicon.png",
|
|
"/icon.png",
|
|
"/apple-touch-icon.png"
|
|
];
|
|
|
|
const fallbackIcons = fallbackPaths.map(p => ({
|
|
href: p,
|
|
sizes: ""
|
|
}));
|
|
|
|
// -------------------------------
|
|
// 5. Unisci tutte le icone
|
|
// -------------------------------
|
|
const allIcons = [...htmlIcons, ...manifestIcons, ...fallbackIcons];
|
|
|
|
// -------------------------------
|
|
// 6. Determina dimensione reale (PNG, ICO, SVG)
|
|
// -------------------------------
|
|
const iconsWithRealSize = [];
|
|
|
|
for (const icon of allIcons) {
|
|
try {
|
|
const url = new URL(icon.href, baseUrl).href;
|
|
const imgRes = await axios.get(url, { responseType: "arraybuffer" });
|
|
|
|
let width = 0;
|
|
|
|
// ---- PNG / JPG / ICO ----
|
|
try {
|
|
const dim = sizeOf(imgRes.data);
|
|
if (dim.width) width = dim.width;
|
|
} catch {
|
|
// Non è un formato supportato da image-size
|
|
}
|
|
|
|
// ---- SVG → converti in PNG e misura ----
|
|
if (width === 0) {
|
|
try {
|
|
const pngBuffer = await sharp(imgRes.data).png().toBuffer();
|
|
const dim = sizeOf(pngBuffer);
|
|
if (dim.width) width = dim.width;
|
|
} catch {
|
|
// SVG non convertibile → ignora
|
|
}
|
|
}
|
|
|
|
if (width > 0) {
|
|
iconsWithRealSize.push({ url, size: width });
|
|
}
|
|
|
|
} catch {
|
|
// icona non accessibile → ignora
|
|
}
|
|
}
|
|
|
|
// -------------------------------
|
|
// 7. Scegli la più grande
|
|
// -------------------------------
|
|
iconsWithRealSize.sort((a, b) => b.size - a.size);
|
|
|
|
const icon = iconsWithRealSize.length > 0
|
|
? iconsWithRealSize[0].url
|
|
: null;
|
|
|
|
return { name, icon };
|
|
|
|
} catch {
|
|
return { name: "no_name", icon: null };
|
|
}
|
|
}
|