class VideoProcessorJob < ApplicationJob queue_as :default def perform(video_id) video = Video.find(video_id) # Extract metadata metadata = VideoMetadataExtractor.new(video.full_file_path).extract video.update!(video_metadata: metadata) # Check if web compatible transcoder = VideoTranscoder.new web_compatible = transcoder.web_compatible?(video.full_file_path) video.update!(web_compatible: web_compatible) # Generate thumbnail generate_thumbnail(video) # Transcode if needed unless web_compatible transcode_video(video, transcoder) end video.update!(processed: true) rescue => e video.update!(processing_errors: e.message) raise end private def generate_thumbnail(video) transcoder = VideoTranscoder.new # Generate thumbnail at 10% of duration or 5 seconds if duration unknown thumbnail_time = video.duration ? video.duration * 0.1 : 5 thumbnail_path = transcoder.extract_frame(video.full_file_path, thumbnail_time) # Attach thumbnail as video asset video.video_assets.create!( asset_type: 'thumbnail', file: File.open(thumbnail_path) ) # Clean up temporary file File.delete(thumbnail_path) if File.exist?(thumbnail_path) end def transcode_video(video, transcoder) output_path = video.full_file_path.gsub(/\.[^.]+$/, '.web.mp4') transcoder.transcode_for_web( input_path: video.full_file_path, output_path: output_path ) video.update!( transcoded_path: File.basename(output_path), transcoded_permanently: true, web_compatible: true ) end end