diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bf98f0c..64d88779 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +# [UNRELEASED] - + +## Changed + +- If user already have import with the same name, it will be appended with timestamp during the import process. + +## Fixed + +- Some types of imports were not being detected correctly and were failing to import. + # [0.30.10] - 2025-08-22 ## Added diff --git a/app/controllers/imports_controller.rb b/app/controllers/imports_controller.rb index a0f798ff..3ee75a95 100644 --- a/app/controllers/imports_controller.rb +++ b/app/controllers/imports_controller.rb @@ -102,27 +102,25 @@ class ImportsController < ApplicationController blob = ActiveStorage::Blob.find_signed(signed_id) - import = current_user.imports.build(name: blob.filename.to_s) + import_name = generate_unique_import_name(blob.filename.to_s) + import = current_user.imports.build(name: import_name) import.file.attach(blob) - import.source = detect_import_source(import.file) if import.source.blank? import.save! import end - def detect_import_source(file_attachment) - temp_file_path = Imports::SecureFileDownloader.new(file_attachment).download_to_temp_file + def generate_unique_import_name(original_name) + return original_name unless current_user.imports.exists?(name: original_name) - Imports::SourceDetector.new_from_file_header(temp_file_path).detect_source - rescue StandardError => e - Rails.logger.warn "Failed to auto-detect import source for #{file_attachment.filename}: #{e.message}" - nil - ensure - # Cleanup temp file - if temp_file_path && File.exist?(temp_file_path) - File.unlink(temp_file_path) - end + # Extract filename and extension + basename = File.basename(original_name, File.extname(original_name)) + extension = File.extname(original_name) + + # Add current datetime + timestamp = Time.current.strftime('%Y%m%d_%H%M%S') + "#{basename}_#{timestamp}#{extension}" end def validate_points_limit diff --git a/app/controllers/settings/background_jobs_controller.rb b/app/controllers/settings/background_jobs_controller.rb index 31bda769..fdc1fac3 100644 --- a/app/controllers/settings/background_jobs_controller.rb +++ b/app/controllers/settings/background_jobs_controller.rb @@ -1,12 +1,15 @@ # frozen_string_literal: true class Settings::BackgroundJobsController < ApplicationController - before_action :authenticate_self_hosted! + before_action :authenticate_self_hosted!, unless: lambda { + %w[start_immich_import start_photoprism_import].include?(params[:job_name]) + } + before_action :authenticate_admin!, unless: lambda { %w[start_immich_import start_photoprism_import].include?(params[:job_name]) } - def index;end + def index; end def create EnqueueBackgroundJob.perform_later(params[:job_name], current_user.id) diff --git a/app/models/import.rb b/app/models/import.rb index 74024798..8635f2a9 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -21,7 +21,7 @@ class Import < ApplicationRecord google_semantic_history: 0, owntracks: 1, google_records: 2, google_phone_takeout: 3, gpx: 4, immich_api: 5, geojson: 6, photoprism_api: 7, user_data_archive: 8 - } + }, allow_nil: true def process! if user_data_archive? diff --git a/app/services/imports/create.rb b/app/services/imports/create.rb index 8c8a93f2..a6675c92 100644 --- a/app/services/imports/create.rb +++ b/app/services/imports/create.rb @@ -16,7 +16,12 @@ class Imports::Create temp_file_path = Imports::SecureFileDownloader.new(import.file).download_to_temp_file - source = import.source.presence || detect_source_from_file(temp_file_path) + source = if import.source.nil? || should_detect_source? + detect_source_from_file(temp_file_path) + else + import.source + end + importer(source).new(import, user.id, temp_file_path).call schedule_stats_creating(user.id) @@ -90,8 +95,14 @@ class Imports::Create ).call end + def should_detect_source? + # Don't override API-based sources that can't be reliably detected + !%w[immich_api photoprism_api].include?(import.source) + end + def detect_source_from_file(temp_file_path) detector = Imports::SourceDetector.new_from_file_header(temp_file_path) + detector.detect_source! end diff --git a/app/services/imports/source_detector.rb b/app/services/imports/source_detector.rb index d122892f..7acbb081 100644 --- a/app/services/imports/source_detector.rb +++ b/app/services/imports/source_detector.rb @@ -62,10 +62,10 @@ class Imports::SourceDetector def self.new_from_file_header(file_path) filename = File.basename(file_path) - + # For detection, read only first 2KB to optimize performance header_content = File.open(file_path, 'rb') { |f| f.read(2048) } - + new(header_content, filename, file_path) end @@ -103,7 +103,7 @@ class Imports::SourceDetector # Must have .gpx extension AND contain GPX XML structure return false unless filename.downcase.end_with?('.gpx') - + # Check content for GPX structure content_to_check = if file_path && File.exist?(file_path) # Read first 1KB for GPX detection @@ -111,7 +111,7 @@ class Imports::SourceDetector else file_content end - + content_to_check.strip.start_with?('