From 6acd47c1ca27d705afe88b292a55a5170c038d2e Mon Sep 17 00:00:00 2001 From: Ken D'Ambrosio Date: Thu, 14 May 2026 22:53:09 +0000 Subject: Auto-transcode non-browser-playable videos to MP4 in update.rb On each run, any .avi, .mkv, or .mov file without a same-named .mp4 sibling is transcoded with ffmpeg (H.264/AAC, CRF 23, faststart). The original is kept on disk and hidden in album.json so only the playable MP4 appears in the UI; admins can un-hide the original if needed. Co-Authored-By: Claude Sonnet 4.6 --- scripts/update.rb | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) (limited to 'scripts/update.rb') diff --git a/scripts/update.rb b/scripts/update.rb index 0b052ba..a4969d3 100644 --- a/scripts/update.rb +++ b/scripts/update.rb @@ -22,10 +22,11 @@ MEDIA_ROOT = (ENV['MEDIA_ROOT'] || '/var/albumen').freeze CACHE_ROOT = (ENV['CACHE_ROOT'] || '/opt/albumen/cache/thumbs').freeze THUMB_SIZE = 300 -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 -MEDIA_EXTS = (IMAGE_EXTS + VIDEO_EXTS + AUDIO_EXTS).freeze +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 +MEDIA_EXTS = (IMAGE_EXTS + VIDEO_EXTS + AUDIO_EXTS).freeze +TRANSCODE_EXTS = %w[avi mkv mov].freeze # not universally browser-playable; convert to MP4 # ── Directory processing ─────────────────────────────────────────────────────── @@ -37,6 +38,7 @@ def process_dir(dir) json_path = File.join(dir, 'album.json') data = load_json(json_path) data['files'] ||= {} + data['cover'] = '__random__' unless data.key?('cover') data['visible'] = true unless data.key?('visible') # Enumerate current media files @@ -57,6 +59,26 @@ def process_dir(dir) end end + # Transcode non-web-friendly videos to MP4; hide the original + current.select { |n| TRANSCODE_EXTS.include?(File.extname(n).downcase.delete_prefix('.')) } + .each do |name| + base = File.basename(name, '.*') + target = "#{base}.mp4" + next if current.include?(target) # already transcoded on a previous run + full = File.join(dir, name) + dest = File.join(dir, target) + puts " Transcoding: #{name} → #{target}" + transcode_to_mp4(full, dest) + if File.exist?(dest) + data['files'][name] ||= {} + data['files'][name]['visible'] ||= false # hide original; admin can override + current << target # include in processing pass below + puts " → done (original hidden)" + else + warn " Transcode failed: #{name}" + end + end + # Process each file current.each do |name| full = File.join(dir, name) @@ -161,6 +183,19 @@ rescue StandardError => e warn " Thumb error (image): #{e.message}" end +def transcode_to_mp4(source, dest) + system( + 'ffmpeg', '-y', '-i', source, + '-c:v', 'libx264', '-crf', '23', '-preset', 'medium', + '-c:a', 'aac', + '-movflags', '+faststart', + dest, + %i[out err] => '/dev/null' + ) +rescue StandardError => e + warn " Transcode error: #{e.message}" +end + def generate_video_thumb(source, dest) system( 'ffmpeg', '-y', '-ss', '2', '-i', source, -- cgit v1.2.3