summaryrefslogtreecommitdiffstats
path: root/app.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app.rb')
-rw-r--r--app.rb67
1 files changed, 67 insertions, 0 deletions
diff --git a/app.rb b/app.rb
index 5aba1b4..0678c67 100644
--- a/app.rb
+++ b/app.rb
@@ -15,6 +15,9 @@ CACHE_ROOT = (ENV['CACHE_ROOT'] || '/opt/albumen/cache/thumbs').freeze
CONFIG_PATH = (ENV['CONFIG_PATH'] || '/opt/albumen/config.yml').freeze
THUMB_SIZE = 300
+UPDATE_JOBS = {}
+UPDATE_JOBS_MUTEX = Mutex.new
+
IMAGE_EXTS = %w[jpg jpeg png gif webp heic heif tiff bmp].freeze
VIDEO_EXTS = %w[mp4 mov avi mkv webm m4v ogv].freeze
AUDIO_EXTS = %w[mp3 flac ogg wav m4a aac].freeze
@@ -409,6 +412,28 @@ post '/admin/edit/*' do
require_admin!
rel = params[:splat].first.chomp('/')
dir = resolve_dir(rel)
+
+ unless rel.empty?
+ new_name = params['folder_name'].to_s.strip
+ new_name = '' if new_name.include?('/') || new_name.include?("\x00") ||
+ new_name == '.' || new_name == '..'
+ old_name = File.basename(dir)
+ if !new_name.empty? && new_name != old_name
+ parent_dir = File.dirname(dir)
+ new_dir = File.join(parent_dir, new_name)
+ unless File.exist?(new_dir)
+ parent_rel = rel.include?('/') ? rel.split('/')[0..-2].join('/') : ''
+ new_rel = parent_rel.empty? ? new_name : "#{parent_rel}/#{new_name}"
+ old_cache = File.join(CACHE_ROOT, rel)
+ new_cache = File.join(CACHE_ROOT, new_rel)
+ FileUtils.mv(old_cache, new_cache) if File.directory?(old_cache)
+ FileUtils.mv(dir, new_dir)
+ save_edits(new_rel, new_dir)
+ redirect "/admin/edit/#{new_rel}"
+ end
+ end
+ end
+
save_edits(rel, dir)
redirect "/admin/edit/#{rel}"
end
@@ -435,6 +460,48 @@ def save_edits(rel, dir)
atomic_write(File.join(dir, 'album.json'), JSON.pretty_generate(data))
end
+# ── Background update ─────────────────────────────────────────────────────────
+
+post '/admin/update' do
+ require_admin!
+ rel = params[:rel].to_s.chomp('/')
+ job_id = SecureRandom.hex(8)
+ script = File.join(__dir__, 'scripts', 'update.rb')
+ cmd = rel.empty? ? ['ruby', script] : ['ruby', script, rel]
+
+ UPDATE_JOBS_MUTEX.synchronize do
+ UPDATE_JOBS[job_id] = { status: :running, lines: [] }
+ end
+
+ Thread.new do
+ begin
+ IO.popen(cmd, err: [:child, :out]) do |io|
+ io.each_line do |line|
+ UPDATE_JOBS_MUTEX.synchronize { UPDATE_JOBS[job_id][:lines] << line.chomp }
+ end
+ end
+ code = $?.exitstatus
+ UPDATE_JOBS_MUTEX.synchronize { UPDATE_JOBS[job_id][:status] = code == 0 ? :done : :error }
+ rescue => e
+ UPDATE_JOBS_MUTEX.synchronize do
+ UPDATE_JOBS[job_id][:status] = :error
+ UPDATE_JOBS[job_id][:lines] << "Error: #{e.message}"
+ end
+ end
+ end
+
+ content_type :json
+ { job_id: job_id }.to_json
+end
+
+get '/admin/update/:id' do
+ require_admin!
+ job = UPDATE_JOBS_MUTEX.synchronize { UPDATE_JOBS[params[:id]]&.dup }
+ halt 404 unless job
+ content_type :json
+ { status: job[:status], lines: job[:lines] }.to_json
+end
+
# ── Thumbnail generation ───────────────────────────────────────────────────────
def generate_thumb(source, dest, ext)