mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 09:41:40 -05:00
Implement photos serializer
This commit is contained in:
parent
202396a93d
commit
be45af95fb
7 changed files with 96 additions and 26 deletions
|
|
@ -10,7 +10,14 @@ class Api::V1::PhotosController < ApiController
|
||||||
end
|
end
|
||||||
|
|
||||||
def thumbnail
|
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(
|
HTTParty.get(
|
||||||
"#{current_api_user.settings['immich_url']}/api/assets/#{params[:id]}/thumbnail?size=preview",
|
"#{current_api_user.settings['immich_url']}/api/assets/#{params[:id]}/thumbnail?size=preview",
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -19,14 +26,11 @@ class Api::V1::PhotosController < ApiController
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_thumbnail_response(response)
|
||||||
if response.success?
|
if response.success?
|
||||||
send_data(
|
send_data(response.body, type: 'image/jpeg', disposition: 'inline', status: :ok)
|
||||||
response.body,
|
|
||||||
type: 'image/jpeg',
|
|
||||||
disposition: 'inline',
|
|
||||||
status: :ok
|
|
||||||
)
|
|
||||||
else
|
else
|
||||||
render json: { error: 'Failed to fetch thumbnail' }, status: response.code
|
render json: { error: 'Failed to fetch thumbnail' }, status: response.code
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -137,10 +137,13 @@ export default class extends Controller {
|
||||||
this.map.addControl(this.drawControl);
|
this.map.addControl(this.drawControl);
|
||||||
}
|
}
|
||||||
if (e.name === 'Photos') {
|
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(
|
showFlashMessage(
|
||||||
'error',
|
'error',
|
||||||
'Immich integration is not configured. Please check your settings.'
|
'Photos integration is not configured. Please check your integrations settings.'
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -836,7 +839,7 @@ export default class extends Controller {
|
||||||
<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>
|
||||||
${photo.type === 'VIDEO' ? '🎥 Video' : '📷 Photo'}
|
${photo.type === 'video' ? '🎥 Video' : '📷 Photo'}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
marker.bindPopup(popupContent);
|
marker.bindPopup(popupContent);
|
||||||
|
|
|
||||||
61
app/serializers/api/photo_serializer.rb
Normal file
61
app/serializers/api/photo_serializer.rb
Normal 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
|
||||||
|
|
@ -5,7 +5,7 @@ class Immich::RequestPhotos
|
||||||
|
|
||||||
def initialize(user, start_date: '1970-01-01', end_date: nil)
|
def initialize(user, start_date: '1970-01-01', end_date: nil)
|
||||||
@user = user
|
@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']
|
@immich_api_key = user.settings['immich_api_key']
|
||||||
@start_date = start_date
|
@start_date = start_date
|
||||||
@end_date = end_date
|
@end_date = end_date
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Photoprism::RequestPhotos
|
class Photoprism::RequestPhotos
|
||||||
class Error < StandardError; end
|
|
||||||
attr_reader :user, :photoprism_api_base_url, :photoprism_api_key, :start_date, :end_date
|
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)
|
def initialize(user, start_date: '1970-01-01', end_date: nil)
|
||||||
@user = user
|
@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']
|
@photoprism_api_key = user.settings['photoprism_api_key']
|
||||||
@start_date = start_date
|
@start_date = start_date
|
||||||
@end_date = end_date
|
@end_date = end_date
|
||||||
|
|
@ -18,7 +17,9 @@ class Photoprism::RequestPhotos
|
||||||
|
|
||||||
data = retrieve_photoprism_data
|
data = retrieve_photoprism_data
|
||||||
|
|
||||||
time_framed_data(data)
|
return [] if data[0]['error'].present?
|
||||||
|
|
||||||
|
time_framed_data(data, start_date, end_date)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
@ -29,15 +30,14 @@ class Photoprism::RequestPhotos
|
||||||
|
|
||||||
while offset < 1_000_000
|
while offset < 1_000_000
|
||||||
response_data = fetch_page(offset)
|
response_data = fetch_page(offset)
|
||||||
break unless response_data
|
break if response_data.blank? || response_data[0]['error'].present?
|
||||||
|
|
||||||
data << response_data
|
data << response_data
|
||||||
break if response_data.empty?
|
|
||||||
|
|
||||||
offset += 1000
|
offset += 1000
|
||||||
end
|
end
|
||||||
|
|
||||||
data
|
data.flatten
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_page(offset)
|
def fetch_page(offset)
|
||||||
|
|
@ -47,7 +47,10 @@ class Photoprism::RequestPhotos
|
||||||
query: request_params(offset)
|
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)
|
JSON.parse(response.body)
|
||||||
end
|
end
|
||||||
|
|
@ -71,12 +74,11 @@ class Photoprism::RequestPhotos
|
||||||
public: true,
|
public: true,
|
||||||
quality: 3,
|
quality: 3,
|
||||||
after: start_date,
|
after: start_date,
|
||||||
count: 1000,
|
count: 1000
|
||||||
photo: 'yes'
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def time_framed_data(data)
|
def time_framed_data(data, start_date, end_date)
|
||||||
data.flatten.select do |photo|
|
data.flatten.select do |photo|
|
||||||
taken_at = DateTime.parse(photo['TakenAtLocal'])
|
taken_at = DateTime.parse(photo['TakenAtLocal'])
|
||||||
end_date ||= Time.current
|
end_date ||= Time.current
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ class Photos::Request
|
||||||
photos << request_immich if user.immich_integration_configured?
|
photos << request_immich if user.immich_integration_configured?
|
||||||
photos << request_photoprism if user.photoprism_integration_configured?
|
photos << request_photoprism if user.photoprism_integration_configured?
|
||||||
|
|
||||||
photos
|
photos.flatten.map { |photo| Api::PhotoSerializer.new(photo).call }
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
||||||
|
|
@ -201,10 +201,10 @@ RSpec.describe Photoprism::RequestPhotos do
|
||||||
.to_return(status: 401, body: 'Unauthorized')
|
.to_return(status: 401, body: 'Unauthorized')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises an error' do
|
it 'logs the error' do
|
||||||
expect do
|
expect(Rails.logger).to receive(:error).with('Photoprism API returned 401: Unauthorized')
|
||||||
service.call
|
|
||||||
end.to raise_error(Photoprism::RequestPhotos::Error, 'Photoprism API returned 401: Unauthorized')
|
service.call
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue