Skip to content

Commit ebbc6e1

Browse files
Use a manual event id mapping as fallback for unmatched events.
1 parent a6ce97c commit ebbc6e1

File tree

3 files changed

+127
-31
lines changed

3 files changed

+127
-31
lines changed

scripts/import-data/lib/import.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export async function handleImport(args: string[]) {
5454
]);
5555

5656
// Process photos
57-
const { photosByEvent } = assignPhotosToEvents(photosJSON, eventsWithVenuesJSON, stats);
57+
const { photosByEvent } = await assignPhotosToEvents(photosJSON, eventsWithVenuesJSON, stats);
5858

5959
// Process events
6060
logger.section("Processing Events");

scripts/import-data/lib/photos.ts

Lines changed: 117 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,49 @@ interface InferredBatch extends PhotoBatch {
4545
isInferred: boolean;
4646
}
4747

48-
export function assignPhotosToEvents(
48+
interface PatchMapping {
49+
[timestamp: string]: string;
50+
}
51+
52+
const PATCH_FILE_PATH = path.join("scripts", "import-data", "patch_events.json");
53+
54+
async function loadPatchMappings(): Promise<PatchMapping> {
55+
try {
56+
if (existsSync(PATCH_FILE_PATH)) {
57+
const content = await fs.readFile(PATCH_FILE_PATH, "utf-8");
58+
return JSON.parse(content);
59+
}
60+
} catch (err) {
61+
logger.warn(`Failed to load patch_events.json: ${err instanceof Error ? err.message : String(err)}`);
62+
}
63+
return {};
64+
}
65+
66+
async function savePatchMappings(mappings: PatchMapping): Promise<void> {
67+
try {
68+
await fs.writeFile(PATCH_FILE_PATH, JSON.stringify(mappings, null, 2));
69+
logger.success(`Saved patch mappings to ${PATCH_FILE_PATH}`);
70+
} catch (err) {
71+
logger.error(`Failed to save patch_events.json: ${err instanceof Error ? err.message : String(err)}`);
72+
}
73+
}
74+
75+
function findEventById(eventId: string, eventsJSON: EventsWithVenuesJSON): Event | null {
76+
for (const groupData of Object.values(eventsJSON.groups)) {
77+
for (const event of groupData.events) {
78+
if (event.id === eventId) {
79+
return event;
80+
}
81+
}
82+
}
83+
return null;
84+
}
85+
86+
export async function assignPhotosToEvents(
4987
photosJSON: PhotoJSON,
5088
eventsWithVenuesJSON: EventsWithVenuesJSON,
5189
stats: ImportStatistics,
52-
): PhotoAssignmentResult {
90+
): Promise<PhotoAssignmentResult> {
5391
const photosByEvent: Record<string, Photo[]> = {};
5492
const photoBatchesByEvent: Record<string, InferredBatch[]> = {};
5593
let unassignedBatches = 0;
@@ -58,6 +96,12 @@ export function assignPhotosToEvents(
5896
stats.photoBatchesTotal = Object.keys(photosJSON.groups).length;
5997

6098
const inferredAssignments: Array<{ eventId: string; eventTitle: string; timestamp: number }> = [];
99+
100+
// Load existing patch mappings
101+
const patchMappings = await loadPatchMappings();
102+
const newPatchMappings: PatchMapping = { ...patchMappings };
103+
let patchMappingsUsed = 0;
104+
let newMappingsCreated = 0;
61105

62106
Object.entries(photosJSON.groups).forEach(([key, grp]) => {
63107
if (grp.event) {
@@ -72,37 +116,70 @@ export function assignPhotosToEvents(
72116

73117
stats.photoBatchesAssigned++;
74118
stats.photoBatchesUnchanged++; // Confirmed assignments are unchanged
75-
} else if (INFER_EVENTS) {
76-
// Attempt to infer the event based on timestamp
77-
const inferred = inferEventByTimestamp(grp.timestamp, eventsWithVenuesJSON);
78-
if (inferred) {
79-
inferredAssignments.push({
80-
eventId: inferred.event.id,
81-
eventTitle: inferred.event.title,
82-
timestamp: grp.timestamp,
83-
});
84-
85-
const list = photosByEvent[inferred.event.id] ?? [];
86-
list.push(...grp.photos);
87-
photosByEvent[inferred.event.id] = list;
88-
89-
const batches = photoBatchesByEvent[inferred.event.id] ?? [];
90-
batches.push({ timestamp: grp.timestamp, photos: grp.photos, isInferred: true });
91-
photoBatchesByEvent[inferred.event.id] = batches;
92-
93-
stats.photoBatchesAssigned++;
94-
stats.photoBatchesCreated++; // Inferred assignments are new/created
119+
} else {
120+
// First check patch mappings (always, regardless of INFER_EVENTS)
121+
const timestampKey = grp.timestamp.toString();
122+
const patchedEventId = patchMappings[timestampKey];
123+
124+
if (patchedEventId) {
125+
// Use patched mapping
126+
const event = findEventById(patchedEventId, eventsWithVenuesJSON);
127+
if (event) {
128+
const list = photosByEvent[patchedEventId] ?? [];
129+
list.push(...grp.photos);
130+
photosByEvent[patchedEventId] = list;
131+
132+
const batches = photoBatchesByEvent[patchedEventId] ?? [];
133+
batches.push({ timestamp: grp.timestamp, photos: grp.photos, isInferred: false });
134+
photoBatchesByEvent[patchedEventId] = batches;
135+
136+
stats.photoBatchesAssigned++;
137+
stats.photoBatchesUnchanged++;
138+
patchMappingsUsed++;
139+
logger.debug(`Used patch mapping for batch ${timestampKey}${patchedEventId}`);
140+
} else {
141+
logger.warn(`Patch mapping references non-existent event ${patchedEventId} for batch ${timestampKey}`);
142+
unassignedBatches++;
143+
stats.photoBatchesUnassigned++;
144+
}
145+
} else if (INFER_EVENTS) {
146+
// Attempt to infer the event based on timestamp
147+
const inferred = inferEventByTimestamp(grp.timestamp, eventsWithVenuesJSON);
148+
if (inferred) {
149+
inferredAssignments.push({
150+
eventId: inferred.event.id,
151+
eventTitle: inferred.event.title,
152+
timestamp: grp.timestamp,
153+
});
154+
155+
const list = photosByEvent[inferred.event.id] ?? [];
156+
list.push(...grp.photos);
157+
photosByEvent[inferred.event.id] = list;
158+
159+
const batches = photoBatchesByEvent[inferred.event.id] ?? [];
160+
batches.push({ timestamp: grp.timestamp, photos: grp.photos, isInferred: true });
161+
photoBatchesByEvent[inferred.event.id] = batches;
162+
163+
stats.photoBatchesAssigned++;
164+
stats.photoBatchesCreated++; // Inferred assignments are new/created
165+
166+
// Save this inference to the patch file only if not already defined
167+
if (!patchMappings[timestampKey]) {
168+
newPatchMappings[timestampKey] = inferred.event.id;
169+
newMappingsCreated++;
170+
}
171+
} else {
172+
logger.warn(`Could not infer event for photos batch with timestamp ${grp.timestamp}`);
173+
unassignedBatches++;
174+
stats.photoBatchesUnassigned++;
175+
}
95176
} else {
96-
logger.warn(`Could not infer event for photos batch with timestamp ${grp.timestamp}`);
177+
logger.debug(
178+
`Skipping photos batch ${key} (timestamp: ${grp.timestamp}) because INFER_EVENTS is disabled and no patch mapping exists.`,
179+
);
97180
unassignedBatches++;
98181
stats.photoBatchesUnassigned++;
99182
}
100-
} else {
101-
logger.debug(
102-
`Skipping photos batch ${key} (timestamp: ${grp.timestamp}) because INFER_EVENTS is disabled and no event id present.`,
103-
);
104-
unassignedBatches++;
105-
stats.photoBatchesUnassigned++;
106183
}
107184
});
108185

@@ -114,9 +191,19 @@ export function assignPhotosToEvents(
114191
stats,
115192
);
116193

194+
// Save updated patch mappings if we created new ones
195+
if (newMappingsCreated > 0) {
196+
await savePatchMappings(newPatchMappings);
197+
logger.info(`Created ${newMappingsCreated} new patch mappings`);
198+
}
199+
117200
// Combined reporting for photo assignments
118-
if (inferredAssignments.length > 0 || redistributions.length > 0) {
201+
if (inferredAssignments.length > 0 || redistributions.length > 0 || patchMappingsUsed > 0) {
119202
logger.section("Photo Batch Processing");
203+
204+
if (patchMappingsUsed > 0) {
205+
logger.info(`Used ${patchMappingsUsed} existing patch mappings`);
206+
}
120207

121208
if (inferredAssignments.length > 0) {
122209
logger.info(`Inferred ${inferredAssignments.length} photo batch assignments:`);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"1676970780777": "291352411",
3+
"1687916937627": "293876831",
4+
"1708481165291": "298753297",
5+
"1751017766431": "307295517",
6+
"1755942261631": "310102122",
7+
"1755944868036": "310102122",
8+
"1755945025060": "310102122"
9+
}

0 commit comments

Comments
 (0)