Implement photos serializer

This commit is contained in:
Eugene Burmakin 2024-12-02 18:21:12 +01:00
parent 202396a93d
commit be45af95fb
7 changed files with 96 additions and 26 deletions

View file

@ -10,7 +10,14 @@ class Api::V1::PhotosController < ApiController
end
def thumbnail
response = Rails.cache.fetch("photo_thumbnail_#{params[:id]}", expires_in: 1.day) do
response = fetch_cached_thumbnail
handle_thumbnail_response(response)
end
private
def fetch_cached_thumbnail
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: {
@ -19,14 +26,11 @@ class Api::V1::PhotosController < ApiController
}
)
end
end
def handle_thumbnail_response(response)
if response.success?
send_data(
response.body,
type: 'image/jpeg',
disposition: 'inline',
status: :ok
)
send_data(response.body, type: 'image/jpeg', disposition: 'inline', status: :ok)
else
render json: { error: 'Failed to fetch thumbnail' }, status: response.code
end

View file

@ -137,10 +137,13 @@ export default class extends Controller {
this.map.addControl(this.drawControl);
}
if (e.name === 'Photos') {
if (!this.userSettings.immich_url || !this.userSettings.immich_api_key) {
if (
(!this.userSettings.immich_url || !this.userSettings.immich_api_key) &&
(!this.userSettings.photoprism_url || !this.userSettings.photoprism_api_key)
) {
showFlashMessage(
'error',
'Immich integration is not configured. Please check your settings.'
'Photos integration is not configured. Please check your integrations settings.'
);
return;
}
@ -836,7 +839,7 @@ export default class extends Controller {
<h3 class="font-bold">${photo.originalFileName}</h3>
<p>Taken: ${new Date(photo.localDateTime).toLocaleString()}</p>
<p>Location: ${photo.exifInfo.city}, ${photo.exifInfo.state}, ${photo.exifInfo.country}</p>
${photo.type === 'VIDEO' ? '🎥 Video' : '📷 Photo'}
${photo.type === 'video' ? '🎥 Video' : '📷 Photo'}
</div>
`;
marker.bindPopup(popupContent);

View file

@ -0,0 +1,61 @@
# frozen_string_literal: true
class Api::PhotoSerializer
def initialize(photo)
@photo = photo
end
def call
{
id: id,
latitude: latitude,
longitude: longitude,
localDateTime: local_date_time,
originalFileName: original_file_name,
city: city,
state: state,
country: country,
type: type
}
end
private
attr_reader :photo
def id
photo['id'] || photo['ID']
end
def latitude
photo.dig('exifInfo', 'latitude') || photo['Lat']
end
def longitude
photo.dig('exifInfo', 'longitude') || photo['Lng']
end
def local_date_time
photo['localDateTime'] || photo['TakenAtLocal']
end
def original_file_name
photo['originalFileName'] || photo['OriginalName']
end
def city
photo.dig('exifInfo', 'city') || photo['PlaceCity']
end
def state
photo.dig('exifInfo', 'state') || photo['PlaceState']
end
def country
photo.dig('exifInfo', 'country') || photo['PlaceCountry']
end
def type
(photo['type'] || photo['Type']).downcase
end
end

View file

@ -5,7 +5,7 @@ class Immich::RequestPhotos
def initialize(user, start_date: '1970-01-01', end_date: nil)
@user = user
@immich_api_base_url = "#{user.settings['immich_url']}/api/search/metadata"
@immich_api_base_url = URI.parse("#{user.settings['immich_url']}/api/search/metadata")
@immich_api_key = user.settings['immich_api_key']
@start_date = start_date
@end_date = end_date

View file

@ -1,12 +1,11 @@
# frozen_string_literal: true
class Photoprism::RequestPhotos
class Error < StandardError; end
attr_reader :user, :photoprism_api_base_url, :photoprism_api_key, :start_date, :end_date
def initialize(user, start_date: '1970-01-01', end_date: nil)
@user = user
@photoprism_api_base_url = "#{user.settings['photoprism_url']}/api/v1/photos"
@photoprism_api_base_url = URI.parse("#{user.settings['photoprism_url']}/api/v1/photos")
@photoprism_api_key = user.settings['photoprism_api_key']
@start_date = start_date
@end_date = end_date
@ -18,7 +17,9 @@ class Photoprism::RequestPhotos
data = retrieve_photoprism_data
time_framed_data(data)
return [] if data[0]['error'].present?
time_framed_data(data, start_date, end_date)
end
private
@ -29,15 +30,14 @@ class Photoprism::RequestPhotos
while offset < 1_000_000
response_data = fetch_page(offset)
break unless response_data
break if response_data.blank? || response_data[0]['error'].present?
data << response_data
break if response_data.empty?
offset += 1000
end
data
data.flatten
end
def fetch_page(offset)
@ -47,7 +47,10 @@ class Photoprism::RequestPhotos
query: request_params(offset)
)
raise Error, "Photoprism API returned #{response.code}: #{response.body}" if response.code != 200
if response.code != 200
Rails.logger.info "Photoprism API returned #{response.code}: #{response.body}"
Rails.logger.debug "Photoprism API request params: #{request_params(offset).inspect}"
end
JSON.parse(response.body)
end
@ -71,12 +74,11 @@ class Photoprism::RequestPhotos
public: true,
quality: 3,
after: start_date,
count: 1000,
photo: 'yes'
count: 1000
}
end
def time_framed_data(data)
def time_framed_data(data, start_date, end_date)
data.flatten.select do |photo|
taken_at = DateTime.parse(photo['TakenAtLocal'])
end_date ||= Time.current

View file

@ -15,7 +15,7 @@ class Photos::Request
photos << request_immich if user.immich_integration_configured?
photos << request_photoprism if user.photoprism_integration_configured?
photos
photos.flatten.map { |photo| Api::PhotoSerializer.new(photo).call }
end
private

View file

@ -201,10 +201,10 @@ RSpec.describe Photoprism::RequestPhotos do
.to_return(status: 401, body: 'Unauthorized')
end
it 'raises an error' do
expect do
service.call
end.to raise_error(Photoprism::RequestPhotos::Error, 'Photoprism API returned 401: Unauthorized')
it 'logs the error' do
expect(Rails.logger).to receive(:error).with('Photoprism API returned 401: Unauthorized')
service.call
end
end