import { __ID__, devMode, filePath } from "../consts.mjs"; const { fetchJsonWithTimeout } = foundry.utils; /** * Returns a pseudo-hash for a file. If the browser is in a secure * context this will return a true SHA-1 hash of the file, otherwise * a random ID is generated using the character set A-Za-z0-9. * * @param {File} file The file to hash */ export async function hashFile(file) { // Handle fallback when hashing isn't possible if (!window.isSecureContext || !crypto.subtle.digest) { return foundry.utils.randomID(40); }; // Actually hash the file since we can const bytes = await file.arrayBuffer(); const buffer = await crypto.subtle.digest(`SHA-1`, bytes); const intArray = new Uint8Array(buffer); if (Uint8Array.prototype.toHex) { return intArray.toHex(); }; return Array.from(intArray) .map(b => b.toString(16).padStart(2, `0`)) .join(``); }; export async function lastModifiedAt(path) { try { const response = await fetch(filePath(path), { method: `HEAD` }); return response.headers.get(`Last-Modified`); } catch { return null; }; }; export async function getFileSize(path) { try { const response = await fetch(filePath(path), { method: `HEAD` }); const bytes = response.headers.get(`Content-Length`); if (!bytes) { return null } // round the non-bytes to 2 decimal places const kilobytes = Math.floor(bytes / 10) / 100; const megabytes = Math.floor(bytes / 10_000) / 100; // determine the most appropriate unit to use let friendly = `${bytes} bytes`; if (megabytes > 0.25) { friendly = `${megabytes}MB`; } else if (kilobytes > 0) { friendly = `${kilobytes}KB`; }; return { bytes, kilobytes, megabytes, friendly }; } catch { return null; }; }; export async function getFile(path) { try { return fetchJsonWithTimeout(filePath(path)); } catch { return undefined; }; }; /** * @param {string} path * @param {any} data */ export async function uploadJson(path, filename, data) { const content = JSON.stringify( data, undefined, devMode() ? `\t` : undefined, ); try { const file = new File( [content], filename, { type: `text/plain` }, ); await uploadFile(path, file); } catch {}; }; export async function uploadFile(path, file) { // uploadPersistent adds "storage" into the path automatically if (path.startsWith(`storage/`)) { path = path.slice(8); }; if (path.endsWith(`/`)) { path = path.slice(0, -1); }; const picker = foundry.applications.apps.FilePicker.implementation; try { await picker.uploadPersistent( __ID__, path, file, ); } catch {}; }; export function determineFileExtension(file) { for (const [short, long] of Object.entries(CONST.IMAGE_FILE_EXTENSIONS)) { if (long === file.type) { return short; }; }; return null; };