devsite/strapi_extraction/media-sync/01-fetch-inventory.js
2026-04-28 12:22:24 +02:00

140 lines
3.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 01 — Appelle lAPI Strapi (lecture publique) et produit media-inventory.json
* (liste de tous les fichiers image liés aux content-types configurés).
*
* Usage : node strapi_extraction/media-sync/01-fetch-inventory.js
*/
const fs = require("fs");
const path = require("path");
const {
API_BASE,
WORK_ROOT,
FILE_INVENTORY,
COLLECTIONS,
PAGE_SIZE,
} = require("./config");
const { normalizeField, safeSlug } = require("./lib/collect-media");
function unwrapEntry(entry) {
if (!entry) return null;
if (entry.attributes) {
return {
...entry.attributes,
id: entry.id,
documentId: entry.documentId,
};
}
return entry;
}
async function fetchJson(url) {
const r = await fetch(url);
if (!r.ok) {
const txt = await r.text();
throw new Error(`HTTP ${r.status} ${url}\n${txt.slice(0, 500)}`);
}
return r.json();
}
async function fetchAllEntries(plural) {
const out = [];
let page = 1;
/* eslint-disable no-constant-condition */
while (true) {
const params = new URLSearchParams();
params.set("pagination[page]", String(page));
params.set("pagination[pageSize]", String(PAGE_SIZE));
/**
* Strapi v5 : populate[picture]=* peut provoquer « Invalid key related » selon versions.
* populate=* hydrate les relations premier niveau (y compris les médias).
*/
params.set("populate", "*");
const url = `${API_BASE}/${plural}?${params}`;
const json = await fetchJson(url);
const rows = Array.isArray(json.data) ? json.data : [];
for (const row of rows) {
out.push(unwrapEntry(row));
}
const pageCount = json.meta?.pagination?.pageCount ?? 1;
if (page >= pageCount || rows.length === 0) break;
page += 1;
await new Promise((r) => setTimeout(r, 200));
}
return out;
}
async function main() {
console.log("🔍 STRAPI_URL (origine) →", require("./config").STRAPI_URL);
console.log("🔍 API_BASE →", API_BASE);
if (!fs.existsSync(WORK_ROOT)) {
fs.mkdirSync(WORK_ROOT, { recursive: true });
}
const inventory = {
generatedAt: new Date().toISOString(),
apiBase: API_BASE,
files: [],
};
/** @type {typeof inventory.files} */
const records = [];
for (const col of COLLECTIONS) {
console.log(`\n📂 ${col.plural} (${col.section})…`);
let entries;
try {
entries = await fetchAllEntries(col.plural);
} catch (e) {
console.error(` ⚠️ Endpoint indisponible ou erreur : ${e.message}`);
continue;
}
console.log(` ${entries.length} entrée(s)`);
for (const entry of entries) {
if (!entry) continue;
const slug = safeSlug(entry);
for (const field of col.fields) {
const items = normalizeField(entry[field.name], field.multiple);
for (const { file, index } of items) {
const base = path.basename(file.url.split("?")[0] || "file");
records.push({
collectionPlural: col.plural,
collectionSingular: col.singular,
strapiRef: col.ref,
section: col.section,
entrySlug: slug,
entryId: entry.id,
entryDocumentId: entry.documentId ?? null,
fieldName: field.name,
fieldMultiple: field.multiple,
fieldIndex: index,
fileId: file.id,
fileDocumentId: file.documentId ?? null,
filename: file.name || base,
url: file.url,
mime: file.mime,
size: file.size,
ext: file.ext,
/** chemin relatif WORK_ROOT/downloaded/... rempli par 02 */
relativeDownloadPath: null,
});
}
}
}
}
inventory.files = records.slice().sort((a, b) => a.fileId - b.fileId);
fs.writeFileSync(FILE_INVENTORY, JSON.stringify(inventory, null, 2), "utf8");
console.log(`\n✅ Inventaire : ${inventory.files.length} fichier(s) → ${FILE_INVENTORY}`);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});