Show some photos from the trip

This commit is contained in:
Eugene Burmakin 2024-11-28 10:40:08 +01:00
parent 9522f81abf
commit c689051472
6 changed files with 121 additions and 21 deletions

View file

@ -13,6 +13,10 @@ class TripsController < ApplicationController
:latitude, :longitude, :battery, :altitude, :timestamp, :velocity, :id,
:country
).map { [_1.to_f, _2.to_f, _3.to_s, _4.to_s, _5.to_s, _6.to_s, _7.to_s, _8.to_s] }
@photos = Rails.cache.fetch("trip_photos_#{@trip.id}", expires_in: 1.day) do
@trip.photos
end
end
def new

View file

@ -10,7 +10,7 @@ import { esriWorldStreetMapLayer } from "../maps/layers"
import { esriWorldTopoMapLayer } from "../maps/layers"
import { esriWorldImageryMapLayer } from "../maps/layers"
import { esriWorldGrayCanvasMapLayer } from "../maps/layers"
// import { fetchAndDisplayPhotos } from "../helpers/photoFetcher";
import { fetchAndDisplayPhotos } from '../maps/helpers';
export default class extends Controller {
static targets = ["container"]
@ -52,7 +52,28 @@ export default class extends Controller {
// Add layer control
L.control.layers(this.baseMaps(), overlayMaps).addTo(this.map)
// Add markers for each coordinate
// Add event listener for layer changes
this.map.on('overlayadd', (e) => {
if (e.name === 'Photos' && this.coordinates?.length > 0) {
const firstCoord = this.coordinates[0];
const lastCoord = this.coordinates[this.coordinates.length - 1];
// Convert Unix timestamp to a Date object
const startDate = new Date(firstCoord[4] * 1000).toISOString().split('T')[0];
const endDate = new Date(lastCoord[4] * 1000).toISOString().split('T')[0];
fetchAndDisplayPhotos({
map: this.map,
photoMarkers: this.photoMarkers,
apiKey: this.apiKey,
startDate: startDate,
endDate: endDate,
userSettings: this.userSettings
});
}
});
// Add markers and route
if (this.coordinates?.length > 0) {
this.addMarkers()
this.addPolyline()
@ -129,11 +150,4 @@ export default class extends Controller {
esriWorldGrayCanvas: esriWorldGrayCanvasMapLayer(this.map, selectedLayerName)
};
}
someMethod() {
// Example usage
const startDate = '2023-01-01';
const endDate = '2023-12-31';
fetchAndDisplayPhotos(this.map, this.apiKey, this.photoMarkers, startDate, endDate);
}
}

View file

@ -12,4 +12,24 @@ class Trip < ApplicationRecord
def countries
points.pluck(:country).uniq.compact
end
def photos
immich_photos = Immich::RequestPhotos.new(
user,
start_date: started_at.to_date.to_s,
end_date: ended_at.to_date.to_s
).call
# let's count what photos are more: vertical or horizontal and select the ones that are more
vertical_photos = immich_photos.select { _1['exifInfo']['orientation'] == '6' }
horizontal_photos = immich_photos.select { _1['exifInfo']['orientation'] == '3' }
# this is ridiculous, but I couldn't find my way around frontend
# to show all photos in the same height
photos = vertical_photos.count > horizontal_photos.count ? vertical_photos : horizontal_photos
photos.sample(12).map do |asset|
{ url: "/api/v1/photos/#{asset['id']}/thumbnail.jpg?api_key=#{user.api_key}" }
end
end
end

View file

@ -27,6 +27,7 @@ class Immich::RequestPhotos
data = []
max_pages = 10_000 # Prevent infinite loop
# TODO: Handle pagination using nextPage
while page <= max_pages
response = JSON.parse(
HTTParty.post(
@ -49,7 +50,7 @@ class Immich::RequestPhotos
page += 1
end
data.flatten
data.flatten.reject { |asset| asset['type'].downcase == 'video' }
end
def headers

View file

@ -48,15 +48,20 @@
</div>
<!-- Photos Grid Section -->
<% (1..12).each_slice(4) do |slice| %>
<div class="flex flex-row gap-4 mt-4 justify-center">
<% slice.each do %>
<div class="aspect-square rounded-box overflow-hidden bg-base-200 w-32">
<img src="https://placehold.co/128x128" alt="Photo Placeholder"
class="w-32 object-cover">
</div>
<% if @photos.any? %>
<% @photos.each_slice(4) do |slice| %>
<div class="h-32 flex gap-4 mt-4 justify-center">
<% slice.each do |photo| %>
<div class="flex-1 h-full overflow-hidden rounded-lg transition-transform duration-300 hover:scale-105 hover:shadow-lg">
<img
src="<%= photo[:url] %>"
loading='lazy'
class="h-full w-full object-cover"
>
</div>
<% end %>
</div>
<% end %>
</div>
<% end %>
<div class="text-center mt-6">

View file

@ -18,8 +18,8 @@ RSpec.describe Immich::RequestPhotos do
"facets": []
},
"assets": {
"total": 1000,
"count": 1000,
"total": 2,
"count": 2,
"items": [
{
"id": '7fe486e3-c3ba-4b54-bbf9-1281b39ed15c',
@ -71,8 +71,60 @@ RSpec.describe Immich::RequestPhotos do
"hasMetadata": true,
"duplicateId": '88a34bee-783d-46e4-aa52-33b75ffda375',
"resized": true
},
{
"id": '7fe486e3-c3ba-4b54-bbf9-1281b39ed15c2',
"deviceAssetId": 'IMG_9913.jpeg-1168914',
"ownerId": 'f579f328-c355-438c-a82c-fe3390bd5f08',
"deviceId": 'CLI',
"libraryId": nil,
"type": 'VIDEO',
"originalPath": 'upload/library/admin/2023/2023-06-08/IMG_9913.jpeg',
"originalFileName": 'IMG_9913.jpeg',
"originalMimeType": 'image/jpeg',
"thumbhash": '4RgONQaZqYaH93g3h3p3d6RfPPrG',
"fileCreatedAt": '2023-06-08T07:58:45.637Z',
"fileModifiedAt": '2023-06-08T09:58:45.000Z',
"localDateTime": '2023-06-08T09:58:45.637Z',
"updatedAt": '2024-08-24T18:20:47.965Z',
"isFavorite": false,
"isArchived": false,
"isTrashed": false,
"duration": '0:00:00.00000',
"exifInfo": {
"make": 'Apple',
"model": 'iPhone 12 Pro',
"exifImageWidth": 4032,
"exifImageHeight": 3024,
"fileSizeInByte": 1_168_914,
"orientation": '6',
"dateTimeOriginal": '2023-06-08T07:58:45.637Z',
"modifyDate": '2023-06-08T07:58:45.000Z',
"timeZone": 'Europe/Berlin',
"lensModel": 'iPhone 12 Pro back triple camera 4.2mm f/1.6',
"fNumber": 1.6,
"focalLength": 4.2,
"iso": 320,
"exposureTime": '1/60',
"latitude": 52.11,
"longitude": 13.22,
"city": 'Johannisthal',
"state": 'Berlin',
"country": 'Germany',
"description": '',
"projectionType": nil,
"rating": nil
},
"livePhotoVideoId": nil,
"people": [],
"checksum": 'aL1edPVg4ZpEnS6xCRWNUY0pUS8=',
"isOffline": false,
"hasMetadata": true,
"duplicateId": '88a34bee-783d-46e4-aa52-33b75ffda375',
"resized": true
}
]
],
nextPage: nil
}
}.to_json
end
@ -84,6 +136,10 @@ RSpec.describe Immich::RequestPhotos do
'http://immich.app/api/search/metadata'
).to_return(status: 200, body: immich_data, headers: {})
end
it 'returns only images' do
expect(service.map { _1['type'] }.uniq).to eq(['IMAGE'])
end
end
context 'when user has no immich_url' do