-
-
+
@@ -2466,62 +2466,47 @@
// ═══════════════════════════════════════════════════════════════════════
// MANUAL MODE — Photo
// ═══════════════════════════════════════════════════════════════════════
- let manualPhotoStream = null;
+ let manualPhotoFile = null;
+ let manualPhotoBlob = null;
+ let manualPhotoGps = null;
- async function startManualPhoto() {
- if (manualPhotoStream) return;
- try {
- manualPhotoStream = await navigator.mediaDevices.getUserMedia({
- video: { facingMode: { ideal: 'environment' }, width: { ideal: 1920 }, height: { ideal: 1080 } },
- audio: false,
- });
- const video = document.getElementById('manPhotoVideo');
- if (!video) return;
- video.srcObject = manualPhotoStream;
- await video.play();
- document.getElementById('manPhotoPlaceholder').style.display = 'none';
- video.style.display = 'block';
- document.getElementById('manPhotoCaptureRow').style.display = 'flex';
- } catch (e) {
- showToast('Camera failed: ' + e.message, true);
- }
- }
+ async function handleManualPhotoFile(event) {
+ const file = event.target.files?.[0];
+ if (!file) return;
+ manualPhotoFile = file;
+ manualPhotoBlob = file; // Use original file (preserves EXIF)
- async function captureManualPhoto() {
- const video = document.getElementById('manPhotoVideo');
- if (!video || !manualPhotoStream) return;
-
- const canvas = document.createElement('canvas');
- canvas.width = video.videoWidth;
- canvas.height = video.videoHeight;
- canvas.getContext('2d').drawImage(video, 0, 0);
- manualPhotoBlob = await new Promise(r => canvas.toBlob(r, 'image/jpeg', 0.85));
-
- const url = URL.createObjectURL(manualPhotoBlob);
+ // Show preview
+ const url = URL.createObjectURL(file);
document.getElementById('manPhotoPreview').src = url;
document.getElementById('manPhotoPreview').style.display = 'block';
document.getElementById('manPhotoRetake').style.display = 'block';
- stopManualPhoto();
+ document.getElementById('manPhotoPlaceholder').style.display = 'none';
+
+ // Try EXIF GPS from the original file
+ manualPhotoGps = await extractGpsFromPhoto(file);
+ if (manualPhotoGps) {
+ const coords = manualPhotoGps.lat.toFixed(6) + ', ' + manualPhotoGps.lng.toFixed(6);
+ const parkingEl = document.getElementById('manParkingLocation');
+ if (parkingEl && !parkingEl.value.trim()) {
+ parkingEl.value = coords;
+ }
+ const mapLinkEl = document.getElementById('manMapLink');
+ if (mapLinkEl && !mapLinkEl.value.trim()) {
+ mapLinkEl.value = `https://www.openstreetmap.org/?mlat=${manualPhotoGps.lat}&mlon=${manualPhotoGps.lng}&zoom=17`;
+ }
+ showToast('📍 GPS extracted from photo!');
+ }
}
function retakeManualPhoto() {
+ manualPhotoFile = null;
manualPhotoBlob = null;
+ manualPhotoGps = null;
document.getElementById('manPhotoPreview').style.display = 'none';
document.getElementById('manPhotoRetake').style.display = 'none';
- startManualPhoto();
- }
-
- function stopManualPhoto() {
- if (manualPhotoStream) {
- manualPhotoStream.getTracks().forEach(t => t.stop());
- manualPhotoStream = null;
- }
- const video = document.getElementById('manPhotoVideo');
- if (video) video.style.display = 'none';
- const ph = document.getElementById('manPhotoPlaceholder');
- if (ph) ph.style.display = '';
- const row = document.getElementById('manPhotoCaptureRow');
- if (row) row.style.display = 'none';
+ document.getElementById('manPhotoPlaceholder').style.display = '';
+ document.getElementById('manPhotoInput').value = '';
}
// ═══════════════════════════════════════════════════════════════════════
@@ -2536,12 +2521,16 @@
}
let photoPath = null;
- if (manualPhotoBlob) {
+ if (manualPhotoFile) {
try {
const fd = new FormData();
- fd.append('file', manualPhotoBlob, 'photo.jpg');
+ fd.append('file', manualPhotoFile, manualPhotoFile.name || 'photo.jpg');
const upData = await api('/api/upload/photo', { method: 'POST', body: fd });
photoPath = upData.path;
+ // If server returned EXIF GPS and we don't have GPS from the file yet, use it
+ if (upData.exif_gps && !manualPhotoGps) {
+ manualPhotoGps = upData.exif_gps;
+ }
} catch (e) { /* photo upload failed, continue without */ }
}
@@ -3780,55 +3769,18 @@
}
// ═══════════════════════════════════════════════════════════════════════
- // HOOK: EXIF GPS extraction after camera capture in manual mode
+ // Extract GPS from a photo file using exifr library
// ═══════════════════════════════════════════════════════════════════════
- // Patch captureManualPhoto to also try EXIF GPS extraction
- const _origCaptureManualPhoto = captureManualPhoto;
- captureManualPhoto = async function() {
- await _origCaptureManualPhoto();
- // After capture, try EXIF GPS from the blob
- if (manualPhotoBlob) {
- try {
- const gps = await extractGpsFromPhoto(manualPhotoBlob);
- if (gps) {
- const coords = gps.lat.toFixed(6) + ', ' + gps.lng.toFixed(6);
- const parkingEl = document.getElementById('manParkingLocation');
- if (parkingEl && !parkingEl.value.trim()) {
- parkingEl.value = coords;
- }
- const mapLinkEl = document.getElementById('manMapLink');
- if (mapLinkEl && !mapLinkEl.value.trim()) {
- mapLinkEl.value = `https://www.openstreetmap.org/?mlat=${gps.lat}&mlon=${gps.lng}&zoom=17`;
- }
- // Show GPS badge near photo
- const photoSection = document.querySelector('#addManualMode .form-section');
- let gpsTag = document.getElementById('manPhotoGpsTag');
- if (!gpsTag) {
- gpsTag = document.createElement('span');
- gpsTag.id = 'manPhotoGpsTag';
- gpsTag.className = 'gps-badge ok';
- gpsTag.style.marginLeft = '8px';
- const title = document.querySelector('#addManualMode .form-section-title');
- if (title) title.appendChild(gpsTag);
- }
- gpsTag.textContent = '📍 GPS from photo';
- gpsTag.style.display = 'inline-flex';
- showToast('📍 GPS extracted from photo!');
- }
- } catch (e) {
- // GPS extraction failure is non-critical
- console.warn('EXIF GPS from capture failed:', e.message);
- }
+ async function extractGpsFromPhoto(file) {
+ if (!file) return null;
+ try {
+ const gps = await exifr.gps(file);
+ return gps || null;
+ } catch (e) {
+ console.warn('EXIF GPS extraction failed:', e.message);
+ return null;
}
- };
-
- // Patch retakeManualPhoto to clear GPS tag
- const _origRetakeManualPhoto = retakeManualPhoto;
- retakeManualPhoto = function() {
- _origRetakeManualPhoto();
- const gpsTag = document.getElementById('manPhotoGpsTag');
- if (gpsTag) gpsTag.style.display = 'none';
- };
+ }
// Boot auth at page load
document.addEventListener('DOMContentLoaded', () => { initAuth(); });