Last active
September 25, 2018 13:34
-
-
Save flvrone/7733ed808e38764ae1858b8c51107390 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
class TranscodeJob | |
include Sidekiq::Worker | |
ORIGINAL_VERSION_NAME = 'original' | |
VIDEO_TRANSCODING_PIPELINE_ID = ENV['video_transcoding_pipeline_id'] | |
# list your versions here | |
VIDEO_TRANSCODING_VERSIONS_OPTIONS = { | |
'480p' => { | |
preset: ENV['your_480p_preset_id_env_var_name'], | |
extname: '.mp4', poster_extname: '.png' | |
}.freeze | |
}.with_indifferent_access.freeze | |
def perform(data) | |
@attacher = TranscoderUploader::Attacher.load(data) | |
execute_transcoding_job | |
store_original_cached_file | |
apply_outputs_to_resulting_versions | |
attacher.swap(resulting_versions) | |
end | |
private | |
attr_reader :attacher, :outputs | |
def cached_file | |
@cached_file ||= attacher.get | |
end | |
def transcoder | |
@transcoder ||= Aws::ElasticTranscoder::Client.new | |
end | |
def transcoder_job_id | |
@transcoder_job_id ||= transcoder.create_job( | |
pipeline_id: VIDEO_TRANSCODING_PIPELINE_ID, | |
input: { key: cached_file_absolute_location }, | |
outputs: job_outputs_params, | |
output_key_prefix: "#{store_uploader.storage.prefix}/" | |
).job.id | |
end | |
def execute_transcoding_job | |
transcoder.wait_until(:job_complete, id: transcoder_job_id) | |
@outputs = transcoder.read_job(id: transcoder_job_id).job.outputs | |
end | |
def job_outputs_params | |
versions_data.values.map do |data| | |
{ | |
key: data[:location], | |
thumbnail_pattern: data[:poster_location_pattern], | |
preset_id: data[:transcoder_preset] | |
} | |
end | |
end | |
def cached_file_absolute_location | |
"#{attacher.cache.storage.prefix}/#{cached_file.id}" | |
end | |
def store_uploader | |
@store_uploader ||= attacher.store | |
end | |
def uploaded_file_class | |
@uploaded_file_class ||= attacher.shrine_class::UploadedFile | |
end | |
def store_original_cached_file | |
store_uploader.store( | |
cached_file, | |
attacher.context.merge(location: original_data[:location]) | |
) | |
end | |
def versions_data | |
@versions_data ||= {}.tap do |hash| | |
VIDEO_TRANSCODING_VERSIONS_OPTIONS.each do |version, options| | |
poster_pattern = generate_poster_location_pattern_for(version) | |
hash[version] = { | |
mime_type: MIME::Types.of(options[:extname]).grep(/video/).first.to_s, | |
transcoder_preset: options[:preset], | |
location: generate_location_for(version), | |
filename: generate_filename_for(version), | |
poster_version_name: poster_version_name_for(version), | |
poster_filename: "poster#{options[:poster_extname]}", | |
poster_location_pattern: poster_pattern, | |
poster_location: | |
generate_poster_location_from(version, poster_pattern), | |
poster_mime_type: | |
MIME::Types.of(options[:poster_extname]).grep(/image/).first.to_s | |
} | |
end | |
end | |
end | |
def original_data | |
@original_data ||= { | |
filename: cached_file.original_filename, | |
location: generate_rough_location_for(ORIGINAL_VERSION_NAME) | |
}.tap do |hash| | |
extname = hash[:extname] = File.extname(hash[:filename].to_s) | |
hash[:location_ends_with_extname] = | |
extname.empty? ? false : hash[:location].match?(/#{extname}$/) | |
end | |
end | |
def generate_rough_location_for(version) | |
store_uploader.generate_location( | |
cached_file, attacher.context.merge(version: version) | |
) | |
end | |
def generate_location_for(version) | |
result = generate_rough_location_for(version) | |
version_extname = VIDEO_TRANSCODING_VERSIONS_OPTIONS[version][:extname] | |
original_extname = original_data[:extname] | |
if original_extname.empty? || !original_data[:location_ends_with_extname] | |
return result + version_extname | |
end | |
result.sub(/#{original_extname}$/, version_extname) | |
end | |
def generate_poster_location_pattern_for(version) | |
result = generate_rough_location_for(poster_version_name_for(version)) | |
# NOTE: "{count}" part is **required** by elastic transcoder | |
if original_data[:location_ends_with_extname] | |
return result.sub(/#{original_data[:extname]}$/, '-{count}') | |
end | |
result + '-{count}' | |
end | |
def poster_version_name_for(version) | |
"#{version}_poster" | |
end | |
def generate_poster_location_from(version, pattern) | |
# NOTE: elastic transcoder will replace "{count}" with "00001.png" | |
# (almost), more details here: | |
# https://docs.aws.amazon.com/elastictranscoder/latest/developerguide/job-settings.html#job-settings-output-details-part-3 | |
extname = VIDEO_TRANSCODING_VERSIONS_OPTIONS[version][:poster_extname] | |
pattern.sub('{count}', '00001' + extname) | |
end | |
def generate_filename_for(version) | |
return if (original_filename = original_data[:filename]).blank? | |
original_extname = original_data[:extname] | |
version_extname = VIDEO_TRANSCODING_VERSIONS_OPTIONS[version][:extname] | |
return original_filename + version_extname if original_extname.empty? | |
original_filename.sub(/#{original_extname}$/, version_extname) | |
end | |
def resulting_versions | |
@resulting_versions ||= { | |
ORIGINAL_VERSION_NAME => uploaded_file_class.new( | |
'id' => original_data[:location], | |
'storage' => 'store', | |
'metadata' => cached_file.metadata | |
) | |
} | |
end | |
def apply_outputs_to_resulting_versions | |
outputs.each_with_index do |output, index| | |
version = versions_data.keys[index] | |
version_data = versions_data[version] | |
resulting_versions[version] = uploaded_file_class.new( | |
'id' => output.key, | |
'storage' => 'store', | |
'metadata' => { | |
'filename' => version_data[:filename], | |
'width' => output.width, | |
'height' => output.height, | |
'duration' => output.duration, | |
'duration_millis' => output.duration_millis, | |
'file_size' => output.file_size, | |
'mime_type' => version_data[:mime_type] | |
} | |
) | |
resulting_versions[version_data[:poster_version_name]] = | |
uploaded_file_class.new( | |
'id' => version_data[:poster_location], | |
'storage' => 'store', | |
'metadata' => { | |
'filename' => version_data[:poster_filename], | |
'mime_type' => version_data[:poster_mime_type] | |
} | |
) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment