Files
parenthese/frontend/src/utils/gedcomBundle.js
T
IliesAllaliandClaude Opus 5.5 5447965243 feat(import): importer un zip qui contient le GEDCOM et ses photos
Le zip est lu dans le navigateur, sans bibliotheque (table des matieres puis
DecompressionStream, fichier par fichier) : le .ged le plus haut s'importe, GEDZIP
compris, et les photos et actes passent directement a l'etape des visages, rapproches
comme un dossier et decompresses seulement a l'envoi. Messages clairs pour un zip sans
.ged, protege par mot de passe ou trop gros. Corrige aussi « citait 1 autres fichiers ».

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 12:40:32 +02:00

43 lines
2.5 KiB
JavaScript
Raw 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.
// Fichier choisi pour l'import : un .ged seul, ou un zip qui contient le .ged et ses photos (un export
// « avec médias », un GEDZIP .gdz de GEDCOM 7, ou un dossier compressé à la main).
import { t } from '../i18n/index.js'
import { ZipError, extensionOf, isZipFile, lazyZipFile, openZip } from './zipReader.js'
const MEDIA_EXTENSIONS = new Set(['jpg', 'jpeg', 'png', 'gif', 'webp', 'heic', 'tif', 'tiff', 'bmp', 'pdf', 'mp4', 'mov', 'm4v', 'webm', 'avi', 'mp3', 'm4a', 'wav', 'ogg'])
// Fichiers sans intérêt glissés par macOS ou Windows dans un zip
const isJunk = (path) => /(^|\/)(__MACOSX|\.DS_Store|Thumbs\.db|desktop\.ini)(\/|$)/i.test(path) || /(^|\/)\._/.test(path)
const ZIP_MESSAGES = {
encrypted: () => t('Ce zip est protégé par un mot de passe. Refaites-le sans mot de passe, puis réessayez.'),
zip64: () => t('Ce zip est trop gros pour être lu ici (plus de 4 Go). Importez le fichier .ged seul, puis ajoutez les photos depuis leur dossier.'),
unsupported_method: () => t('Ce zip utilise une compression que le navigateur ne sait pas lire. Refaites-le avec l’outil de compression de votre ordinateur.'),
}
export function zipErrorMessage(error) {
return ZIP_MESSAGES[error?.code]?.() || t('Ce zip n’a pas pu être lu. Vérifiez qu’il s’ouvre sur votre ordinateur, puis réessayez.')
}
/**
* @returns { gedcomFile: File, bundledFiles: lazy files du zip (photos, actes, vidéos), fromZip: boolean }
*/
export async function readGedcomBundle(file) {
if (!(await isZipFile(file))) return { gedcomFile: file, bundledFiles: [], fromZip: false }
const zip = await openZip(file)
const usable = zip.entries.filter((entry) => !isJunk(entry.path))
// Le .ged le plus haut dans l'arborescence : « gedcom.ged » d'un GEDZIP, ou celui du dossier exporté
const gedcoms = usable
.filter((entry) => extensionOf(entry.name) === 'ged')
.sort((a, b) => a.path.split('/').length - b.path.split('/').length || b.size - a.size)
if (gedcoms.length === 0) throw new ZipError('no_gedcom', t('Ce zip ne contient pas de fichier .ged. Il faut l’export GEDCOM de votre logiciel, avec ses photos à côté.'))
const blob = await zip.read(gedcoms[0])
const gedcomFile = new File([blob], gedcoms[0].name, { type: 'text/plain' })
const bundledFiles = usable
.filter((entry) => entry !== gedcoms[0] && MEDIA_EXTENSIONS.has(extensionOf(entry.name)) && entry.size > 0)
.map((entry) => lazyZipFile(zip, entry))
return { gedcomFile, bundledFiles, fromZip: true }
}