Publier Globinours 1.0.0-rc.3
This commit is contained in:
parent
ea8c24d622
commit
9a2b4068da
325 changed files with 38230 additions and 20 deletions
165
scripts/import-asm3-photos.php
Normal file
165
scripts/import-asm3-photos.php
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
$root = dirname(__DIR__);
|
||||
require $root . '/app/Services/DB.php';
|
||||
require $root . '/app/Services/BackupService.php';
|
||||
require $root . '/app/Services/ImageService.php';
|
||||
require $root . '/app/Services/Asm3Analyzer.php';
|
||||
|
||||
$apply = in_array('--apply', $argv, true);
|
||||
$positional = array_values(
|
||||
array_filter(array_slice($argv, 1), static fn($arg) => !str_starts_with((string) $arg, '--')),
|
||||
);
|
||||
$dump = $positional[0] ?? '';
|
||||
$sourceDir = $positional[1] ?? '';
|
||||
if ($dump === '' || $sourceDir === '') {
|
||||
fwrite(STDERR, "Usage : php scripts/import-asm3-photos.php <dump.sql> <dossier-photos> [--apply]\n");
|
||||
exit(2);
|
||||
}
|
||||
if (!is_file($dump) || !is_dir($sourceDir)) {
|
||||
throw new RuntimeException('Dump ASM3 ou dossier des photos introuvable.');
|
||||
}
|
||||
$hash = hash_file('sha256', $dump);
|
||||
$source = Asm3Analyzer::rows($dump, ['media', 'dbfs']);
|
||||
$db = DB::pdo();
|
||||
$links = [];
|
||||
$q = $db->prepare("SELECT source_id,target_id FROM asm3_import_links WHERE source_sha256=? AND entity_type='animal'");
|
||||
$q->execute([$hash]);
|
||||
foreach ($q as $row) {
|
||||
$links[(int) $row['source_id']] = (int) $row['target_id'];
|
||||
}
|
||||
$dbfs = [];
|
||||
foreach ($source['dbfs'] ?? [] as $row) {
|
||||
$dbfs[(int) $row['ID']] = $row;
|
||||
}
|
||||
$items = [];
|
||||
$errors = [];
|
||||
foreach ($source['media'] ?? [] as $media) {
|
||||
if ((int) $media['LINKTYPEID'] !== 0 || !str_starts_with((string) $media['MEDIAMIMETYPE'], 'image/')) {
|
||||
continue;
|
||||
}
|
||||
$sourceAnimal = (int) $media['LINKID'];
|
||||
$targetAnimal = $links[$sourceAnimal] ?? 0;
|
||||
$physical = $dbfs[(int) $media['DBFSID']] ?? null;
|
||||
$filename = $physical ? basename(str_replace('file:', '', (string) $physical['URL'])) : '';
|
||||
$path = $sourceDir . '/' . $filename;
|
||||
if (!$targetAnimal) {
|
||||
$errors[] = 'Animal ASM3 non relié : ' . $sourceAnimal;
|
||||
} elseif ($filename === '' || !is_file($path)) {
|
||||
$errors[] = 'Fichier absent pour le média ASM3 ' . $media['ID'];
|
||||
} else {
|
||||
$inspection = ImageService::inspect($path);
|
||||
$items[] = [
|
||||
'media' => $media,
|
||||
'animal' => $targetAnimal,
|
||||
'path' => $path,
|
||||
'physical' => $filename,
|
||||
'inspection' => $inspection,
|
||||
];
|
||||
}
|
||||
}
|
||||
if ($errors) {
|
||||
throw new RuntimeException(implode("\n", $errors));
|
||||
}
|
||||
$targets = array_values(array_unique(array_column($items, 'animal')));
|
||||
$primaryCount = count(array_filter($items, static fn(array $i): bool => (int) $i['media']['WEBSITEPHOTO'] === 1));
|
||||
$summary = [
|
||||
'mode' => $apply ? 'APPLIQUE' : 'SIMULATION',
|
||||
'photos_found' => count($items),
|
||||
'animals' => count($targets),
|
||||
'primary_photos' => $primaryCount,
|
||||
'public_photos' => count($items),
|
||||
'already_imported' => 0,
|
||||
'created' => 0,
|
||||
'optimized' => 0,
|
||||
'backup' => null,
|
||||
];
|
||||
foreach ($items as $item) {
|
||||
$original = 'ASM3-' . (int) $item['media']['ID'] . '-' . (string) $item['media']['MEDIANAME'];
|
||||
$s = $db->prepare('SELECT 1 FROM animal_photos WHERE animal_id=? AND original_name=?');
|
||||
$s->execute([$item['animal'], $original]);
|
||||
if ($s->fetchColumn()) {
|
||||
$summary['already_imported']++;
|
||||
}
|
||||
}
|
||||
if (!$apply) {
|
||||
echo json_encode($summary, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
|
||||
exit();
|
||||
}
|
||||
$backup = BackupService::create('avant-import-photos-asm3');
|
||||
$summary['backup'] = $backup['name'] ?? null;
|
||||
$written = [];
|
||||
$db->beginTransaction();
|
||||
try {
|
||||
$db->prepare(
|
||||
"INSERT INTO asm3_import_runs(source_name,source_sha256,status,summary_json,backup_name) VALUES(?,?,'completed','{}',?)",
|
||||
)->execute([basename($dump) . ' · photos', $hash, $summary['backup']]);
|
||||
$run = (int) $db->lastInsertId();
|
||||
$reset = $db->prepare('UPDATE animal_photos SET is_primary=0 WHERE animal_id=?');
|
||||
foreach ($targets as $animalId) {
|
||||
$reset->execute([$animalId]);
|
||||
}
|
||||
$insert = $db->prepare(
|
||||
'INSERT INTO animal_photos(animal_id,filename,original_name,mime,size_bytes,is_primary,is_public,caption,created_at) VALUES(?,?,?,?,?,?,1,?,COALESCE(?,datetime(\'now\')))',
|
||||
);
|
||||
$link = $db->prepare(
|
||||
"INSERT OR IGNORE INTO asm3_import_links(source_sha256,entity_type,source_id,target_id,import_run_id) VALUES(?,'media',?,?,?)",
|
||||
);
|
||||
foreach ($items as $item) {
|
||||
$media = $item['media'];
|
||||
$original = 'ASM3-' . (int) $media['ID'] . '-' . (string) $media['MEDIANAME'];
|
||||
$existing = $db->prepare('SELECT id FROM animal_photos WHERE animal_id=? AND original_name=?');
|
||||
$existing->execute([$item['animal'], $original]);
|
||||
$photoId = (int) $existing->fetchColumn();
|
||||
if (!$photoId) {
|
||||
$stored = ImageService::storeLocal(
|
||||
$item['path'],
|
||||
$root . '/public/media/animals/' . $item['animal'],
|
||||
'asm3_' . (int) $media['ID'],
|
||||
'photo',
|
||||
);
|
||||
$written[] = $stored['path'];
|
||||
$caption = trim((string) ($media['MEDIANOTES'] ?? ''));
|
||||
$caption = $caption !== '' ? 'Archive ASM3 · ' . $caption : 'Archive ASM3';
|
||||
$insert->execute([
|
||||
$item['animal'],
|
||||
$stored['filename'],
|
||||
$original,
|
||||
$stored['mime'],
|
||||
$stored['size'],
|
||||
(int) $media['WEBSITEPHOTO'] === 1 ? 1 : 0,
|
||||
$caption,
|
||||
substr((string) $media['CREATEDDATE'], 0, 19) ?: null,
|
||||
]);
|
||||
$photoId = (int) $db->lastInsertId();
|
||||
$summary['created']++;
|
||||
if ($stored['optimized']) {
|
||||
$summary['optimized']++;
|
||||
}
|
||||
} elseif ((int) $media['WEBSITEPHOTO'] === 1) {
|
||||
$db->prepare('UPDATE animal_photos SET is_primary=1,is_public=1 WHERE id=?')->execute([$photoId]);
|
||||
} else {
|
||||
$db->prepare('UPDATE animal_photos SET is_public=1 WHERE id=?')->execute([$photoId]);
|
||||
}
|
||||
$link->execute([$hash, (int) $media['ID'], $photoId, $run]);
|
||||
}
|
||||
$db->prepare('UPDATE asm3_import_runs SET summary_json=? WHERE id=?')->execute([
|
||||
json_encode($summary, JSON_UNESCAPED_UNICODE),
|
||||
$run,
|
||||
]);
|
||||
if ($db->query('PRAGMA foreign_key_check')->fetchAll()) {
|
||||
throw new RuntimeException('Violation de clé étrangère après import.');
|
||||
}
|
||||
$db->commit();
|
||||
} catch (Throwable $e) {
|
||||
if ($db->inTransaction()) {
|
||||
$db->rollBack();
|
||||
}
|
||||
foreach ($written as $path) {
|
||||
@unlink($path);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
echo json_encode($summary, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
|
||||
Loading…
Add table
Add a link
Reference in a new issue