mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 09:41:40 -05:00
Show individual photo markers on the map
This commit is contained in:
parent
130630b997
commit
428e927432
4 changed files with 84 additions and 33 deletions
|
|
@ -64,4 +64,11 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-marker img {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,32 @@ class Api::V1::PhotosController < ApiController
|
||||||
def index
|
def index
|
||||||
@photos = Rails.cache.fetch("photos_#{params[:start_date]}_#{params[:end_date]}", expires_in: 1.day) do
|
@photos = Rails.cache.fetch("photos_#{params[:start_date]}_#{params[:end_date]}", expires_in: 1.day) do
|
||||||
Immich::RequestPhotos.new(current_api_user, start_date: params[:start_date], end_date: params[:end_date]).call
|
Immich::RequestPhotos.new(current_api_user, start_date: params[:start_date], end_date: params[:end_date]).call
|
||||||
end
|
end.reject { |photo| photo['type'].downcase == 'video' }
|
||||||
|
|
||||||
render json: @photos, status: :ok
|
render json: @photos, status: :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def thumbnail
|
||||||
|
response = Rails.cache.fetch("photo_thumbnail_#{params[:id]}", expires_in: 1.day) do
|
||||||
|
HTTParty.get(
|
||||||
|
"#{current_api_user.settings['immich_url']}/api/assets/#{params[:id]}/thumbnail?size=preview",
|
||||||
|
headers: {
|
||||||
|
'x-api-key' => current_api_user.settings['immich_api_key'],
|
||||||
|
'accept' => 'application/octet-stream'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
if response.success?
|
||||||
|
send_data(
|
||||||
|
response.body,
|
||||||
|
type: 'image/jpeg',
|
||||||
|
disposition: 'inline',
|
||||||
|
status: :ok
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Rails.logger.error "Failed to fetch thumbnail: #{response.code} - #{response.body}"
|
||||||
|
render json: { error: 'Failed to fetch thumbnail' }, status: response.code
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -782,7 +782,10 @@ export default class extends Controller {
|
||||||
this.layerControl = L.control.layers(this.baseMaps(), layerControl).addTo(this.map);
|
this.layerControl = L.control.layers(this.baseMaps(), layerControl).addTo(this.map);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchAndDisplayPhotos(startDate, endDate) {
|
async fetchAndDisplayPhotos(startDate, endDate, retryCount = 0) {
|
||||||
|
const MAX_RETRIES = 3;
|
||||||
|
const RETRY_DELAY = 3000; // 3 seconds
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
api_key: this.apiKey,
|
api_key: this.apiKey,
|
||||||
|
|
@ -796,26 +799,49 @@ export default class extends Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
const photos = await response.json();
|
const photos = await response.json();
|
||||||
|
|
||||||
// Clear existing photo markers
|
|
||||||
this.photoMarkers.clearLayers();
|
this.photoMarkers.clearLayers();
|
||||||
|
|
||||||
// Create markers for each photo with coordinates
|
photos.forEach(photo => this.createPhotoMarker(photo));
|
||||||
photos.forEach(photo => {
|
|
||||||
if (photo.exifInfo?.latitude && photo.exifInfo?.longitude) {
|
if (!this.map.hasLayer(this.photoMarkers)) {
|
||||||
const marker = L.marker([photo.exifInfo.latitude, photo.exifInfo.longitude], {
|
this.photoMarkers.addTo(this.map);
|
||||||
icon: L.divIcon({
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching photos:', error);
|
||||||
|
|
||||||
|
if (retryCount < MAX_RETRIES) {
|
||||||
|
console.log(`Retrying in ${RETRY_DELAY/1000} seconds... (Attempt ${retryCount + 1}/${MAX_RETRIES})`);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.fetchAndDisplayPhotos(startDate, endDate, retryCount + 1);
|
||||||
|
}, RETRY_DELAY);
|
||||||
|
} else {
|
||||||
|
showFlashMessage('error', 'Failed to fetch photos after multiple attempts');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createPhotoMarker(photo) {
|
||||||
|
if (!photo.exifInfo?.latitude || !photo.exifInfo?.longitude) return;
|
||||||
|
|
||||||
|
const thumbnailUrl = `/api/v1/photos/${photo.id}/thumbnail.jpg?api_key=${this.apiKey}`;
|
||||||
|
|
||||||
|
const icon = L.divIcon({
|
||||||
className: 'photo-marker',
|
className: 'photo-marker',
|
||||||
html: `<div class="w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center">
|
html: `<img src="${thumbnailUrl}" style="width: 48px; height: 48px;">`,
|
||||||
<span class="text-white text-xs">📷</span>
|
iconSize: [48, 48]
|
||||||
</div>`,
|
|
||||||
iconSize: [24, 24]
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add popup with photo information
|
const marker = L.marker(
|
||||||
|
[photo.exifInfo.latitude, photo.exifInfo.longitude],
|
||||||
|
{ icon }
|
||||||
|
);
|
||||||
|
|
||||||
const popupContent = `
|
const popupContent = `
|
||||||
<div class="max-w-xs">
|
<div class="max-w-xs">
|
||||||
|
<img src="${thumbnailUrl}"
|
||||||
|
class="w-8 h-8 mb-2 rounded"
|
||||||
|
alt="${photo.originalFileName}">
|
||||||
<h3 class="font-bold">${photo.originalFileName}</h3>
|
<h3 class="font-bold">${photo.originalFileName}</h3>
|
||||||
<p>Taken: ${new Date(photo.localDateTime).toLocaleString()}</p>
|
<p>Taken: ${new Date(photo.localDateTime).toLocaleString()}</p>
|
||||||
<p>Location: ${photo.exifInfo.city}, ${photo.exifInfo.state}, ${photo.exifInfo.country}</p>
|
<p>Location: ${photo.exifInfo.city}, ${photo.exifInfo.state}, ${photo.exifInfo.country}</p>
|
||||||
|
|
@ -826,16 +852,4 @@ export default class extends Controller {
|
||||||
|
|
||||||
this.photoMarkers.addLayer(marker);
|
this.photoMarkers.addLayer(marker);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Add the layer group to the map if it's not already added
|
|
||||||
if (!this.map.hasLayer(this.photoMarkers)) {
|
|
||||||
this.photoMarkers.addTo(this.map);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching photos:', error);
|
|
||||||
showFlashMessage('error', 'Failed to fetch photos');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,12 @@ Rails.application.routes.draw do
|
||||||
namespace :countries do
|
namespace :countries do
|
||||||
resources :borders, only: :index
|
resources :borders, only: :index
|
||||||
end
|
end
|
||||||
|
|
||||||
|
resources :photos do
|
||||||
|
member do
|
||||||
|
get 'thumbnail', constraints: { id: %r{[^/]+} }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue