refactor: streamline client import pipeline
This commit is contained in:
@@ -26,6 +26,7 @@ const state = {
|
|||||||
};
|
};
|
||||||
let activeImportController = null;
|
let activeImportController = null;
|
||||||
const IMPORT_RENDER_INTERVAL_MS = 180;
|
const IMPORT_RENDER_INTERVAL_MS = 180;
|
||||||
|
const IMPORT_CONCURRENCY = 2;
|
||||||
let scheduledRenderFrame = null;
|
let scheduledRenderFrame = null;
|
||||||
let scheduledRenderTimer = null;
|
let scheduledRenderTimer = null;
|
||||||
let scheduledRenderOptions = { fitMap: false };
|
let scheduledRenderOptions = { fitMap: false };
|
||||||
@@ -908,14 +909,19 @@ async function readRemoteImage(entry, shareUrlValue, signal) {
|
|||||||
const capturedAt =
|
const capturedAt =
|
||||||
normalizeExifDate(tags?.DateTimeOriginal?.value ?? tags?.DateTimeOriginal) ||
|
normalizeExifDate(tags?.DateTimeOriginal?.value ?? tags?.DateTimeOriginal) ||
|
||||||
parseDateOrNull(entry.lastModified);
|
parseDateOrNull(entry.lastModified);
|
||||||
|
|
||||||
|
if (gps?.latitude === undefined || gps?.longitude === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const thumbUrl = await createThumbnailObjectUrl(blob);
|
const thumbUrl = await createThumbnailObjectUrl(blob);
|
||||||
state.objectUrls.push(thumbUrl);
|
state.objectUrls.push(thumbUrl);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: entry.href,
|
id: entry.href,
|
||||||
name: entry.name,
|
name: entry.name,
|
||||||
latitude: gps?.latitude ?? null,
|
latitude: gps.latitude,
|
||||||
longitude: gps?.longitude ?? null,
|
longitude: gps.longitude,
|
||||||
capturedAt,
|
capturedAt,
|
||||||
thumbUrl,
|
thumbUrl,
|
||||||
fullUrl,
|
fullUrl,
|
||||||
@@ -923,6 +929,50 @@ async function readRemoteImage(entry, shareUrlValue, signal) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function processImportEntries(listing, shareUrlValue, signal) {
|
||||||
|
let loaded = 0;
|
||||||
|
let skipped = 0;
|
||||||
|
let processed = 0;
|
||||||
|
let nextIndex = 0;
|
||||||
|
|
||||||
|
async function importWorker() {
|
||||||
|
while (nextIndex < listing.length) {
|
||||||
|
if (signal.aborted) {
|
||||||
|
throw signal.reason ?? new Error("Import canceled");
|
||||||
|
}
|
||||||
|
|
||||||
|
const entry = listing[nextIndex];
|
||||||
|
nextIndex += 1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const photo = await readRemoteImage(entry, shareUrlValue, signal);
|
||||||
|
if (photo) {
|
||||||
|
appendPhoto(photo);
|
||||||
|
loaded += 1;
|
||||||
|
} else {
|
||||||
|
skipped += 1;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (signal.aborted) {
|
||||||
|
throw signal.reason ?? error;
|
||||||
|
}
|
||||||
|
skipped += 1;
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
processed += 1;
|
||||||
|
setProgress(processed, listing.length, "processed " + processed + " / " + listing.length);
|
||||||
|
setImportStatus("Importing: " + loaded + " shown, " + skipped + " skipped.");
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const workerCount = Math.min(IMPORT_CONCURRENCY, listing.length);
|
||||||
|
await Promise.all(Array.from({ length: workerCount }, () => importWorker()));
|
||||||
|
|
||||||
|
return { loaded, skipped };
|
||||||
|
}
|
||||||
|
|
||||||
async function importFromShare() {
|
async function importFromShare() {
|
||||||
if (activeImportController) {
|
if (activeImportController) {
|
||||||
return;
|
return;
|
||||||
@@ -945,32 +995,7 @@ async function importFromShare() {
|
|||||||
|
|
||||||
setProgress(0, listing.length, "checking files");
|
setProgress(0, listing.length, "checking files");
|
||||||
|
|
||||||
let loaded = 0;
|
const { loaded, skipped } = await processImportEntries(listing, importUrlInput.value, controller.signal);
|
||||||
let skipped = 0;
|
|
||||||
let processed = 0;
|
|
||||||
|
|
||||||
for (const entry of listing) {
|
|
||||||
if (controller.signal.aborted) {
|
|
||||||
throw controller.signal.reason ?? new Error("Import canceled");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const photo = await readRemoteImage(entry, importUrlInput.value, controller.signal);
|
|
||||||
if (photo.latitude !== null && photo.longitude !== null) {
|
|
||||||
appendPhoto(photo);
|
|
||||||
loaded += 1;
|
|
||||||
} else {
|
|
||||||
skipped += 1;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
skipped += 1;
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
processed += 1;
|
|
||||||
setProgress(processed, listing.length, "processed " + processed + " / " + listing.length);
|
|
||||||
setImportStatus("Importing: " + loaded + " shown, " + skipped + " skipped.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
throw new Error("No images with GPS data found.");
|
throw new Error("No images with GPS data found.");
|
||||||
|
|||||||
Reference in New Issue
Block a user