Pipeline registrazione/upload con storage S3, archivio web e app, proxy replay per il browser, OAuth YouTube sulla pagina club (Premium Full) e footer legale. Co-authored-by: Cursor <cursoragent@cursor.com>
56 lines
1.7 KiB
Ruby
56 lines
1.7 KiB
Ruby
module Recordings
|
|
class GenerateThumbnail
|
|
class Error < StandardError; end
|
|
|
|
def initialize(recording, video_path: nil)
|
|
@recording = recording
|
|
@video_path = video_path
|
|
end
|
|
|
|
def call
|
|
return @recording if @recording.thumbnail_storage_key.present?
|
|
|
|
path = @video_path || local_video_path
|
|
return @recording unless path && File.exist?(path)
|
|
|
|
thumb_path = extract_frame(path)
|
|
key = thumbnail_key
|
|
Recordings::Storage.new.upload(local_path: thumb_path, key: key, content_type: "image/jpeg")
|
|
@recording.update!(thumbnail_storage_key: key)
|
|
FileUtils.rm_f(thumb_path)
|
|
@recording
|
|
rescue Recordings::Storage::Error => e
|
|
Rails.logger.warn("[Recordings::GenerateThumbnail] #{@recording.id}: #{e.message}")
|
|
@recording
|
|
ensure
|
|
FileUtils.rm_f(@thumb_temp) if @thumb_temp && File.exist?(@thumb_temp)
|
|
end
|
|
|
|
private
|
|
|
|
def local_video_path
|
|
return nil if @recording.storage_key.blank?
|
|
|
|
Recordings::Storage.new.local_path_for_key(@recording.storage_key)
|
|
end
|
|
|
|
def extract_frame(video_path)
|
|
@thumb_temp = File.join(Dir.tmpdir, "thumb-#{@recording.id}-#{SecureRandom.hex(4)}.jpg")
|
|
dur = @recording.duration_secs.to_i
|
|
offset = dur.positive? ? [[dur / 4, 5].max, dur - 1].min : 1
|
|
success = system(
|
|
"ffmpeg", "-y", "-ss", offset.to_s, "-i", video_path,
|
|
"-vframes", "1", "-q:v", "2", @thumb_temp,
|
|
out: File::NULL, err: File::NULL
|
|
)
|
|
raise Error, "ffmpeg thumbnail failed" unless success && File.exist?(@thumb_temp)
|
|
|
|
@thumb_temp
|
|
end
|
|
|
|
def thumbnail_key
|
|
"teams/#{@recording.team_id}/sessions/#{@recording.stream_session_id}/thumbnail.jpg"
|
|
end
|
|
end
|
|
end
|