class FlatironVideoUploader::Runner
Constants
- GRANT_TYPE
- THOR_SHELL
Public Class Methods
upload_video(file,batch)
click to toggle source
# File lib/flatiron-video-uploader/runner.rb, line 42 def self.upload_video(file,batch) begin `ffmpeg > /dev/null 2>&1` rescue puts "Looks like you don't have ffmpeg. Install with brew install ffmpeg" exit end begin http = Net::HTTP.new("accounts.google.com",443) http.use_ssl = true req = Net::HTTP::Head.new('/') http.start {http.request(req)} rescue OpenSSL::SSL::SSLError => e puts "Looks like your version of ruby has messed up SSL Certs." puts "Please install openssl with brew install openssl" puts "Then re-install ruby without binaries with rvm reinstall #{RUBY_VERSION} --disable-binary" exit end FFMPEG.logger=Logger.new(STDOUT) FFMPEG.logger.level = Logger::ERROR begin token_response = YAML.load_file(File.expand_path('~/.flatiron-uploader')) rescue puts "We are going to need a few ID/Secret stuff." puts "\n\nGoogle" google_client_id = THOR_SHELL.ask("What is your Google Client ID?") google_client_secret = THOR_SHELL.ask("What is your Google Client Secret?") puts "Finished with Google.\n\n" puts "#"*30 puts "\n\nAmazon S3" amazon_s3_key = THOR_SHELL.ask("What is your Amazon S3 Key?") amazon_s3_secret = THOR_SHELL.ask("What is your Amazon S3 Secret?") puts "#"*30 response = HTTParty.post("https://accounts.google.com/o/oauth2/device/code",:query => {:scope => "https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtube", :client_id => "404828420863-l0nvu5ihjg7kji18d4pghrnetre28d5e.apps.googleusercontent.com"}) puts "OK cool, go to #{response["verification_url"]} and type in the following code" `open #{response["verification_url"]}` puts "#"*30 puts response["user_code"] puts "#"*30 puts "polling" token_response = HTTParty.post("https://www.googleapis.com/oauth2/v3/token", :query => {:client_id => google_client_id, :client_secret => google_client_secret, :grant_type => GRANT_TYPE, :code => response["device_code"]}) while(token_response.code==400) sleep(response["interval"]) token_response = HTTParty.post("https://www.googleapis.com/oauth2/v3/token", :query => {:client_id => google_client_id, :client_secret => google_client_secret, :grant_type => GRANT_TYPE, :code => response["device_code"]}) end puts "Found!" token_response["google_client_id"] = google_client_id token_response["google_client_secret"] = google_client_secret token_response["amazon_s3_key"] = amazon_s3_key token_response["amazon_s3_secret"] = amazon_s3_secret File.open(File.expand_path('~/.flatiron-uploader'), 'w') do |h| h.write token_response.to_yaml end end if !File.exist?(file) || !File.file?(file) puts "Not a file!" exit end progress_mutex = Mutex.new print_progress = false movie_transcode_thread = Thread.new do FFMPEG::Transcoder.timeout=90 movie = FFMPEG::Movie.new(file) movie.transcode("/tmp/transcoded.mp4","-vf 'scale=-2:720:flags=lanczos' -vcodec libx264 -profile:v main -level 3.1 -preset veryfast -crf 31 -x264-params ref=4 -acodec copy -movflags +faststart") do |prog| progress_mutex.synchronize do if print_progress print "\r" # puts add \n to the end of string, use print instead print sprintf("%.2f",prog*100) # force the output to appear immediately when using print # by default when \n is printed to the standard output, the buffer is flushed. $stdout.flush end end end TerminalNotifier.notify("Finished Transcoding for iPad") end auth = Signet::OAuth2::Client.new( :authorization_uri => "https://accounts.google.com/o/oauth2/auth", :token_credential_uri => "https://accounts.google.com/o/oauth2/token", :client_id => token_response['google_client_id'], :client_secret => token_response['google_client_secret'] ) auth.refresh_token = token_response["refresh_token"] auth.refresh! client = Google::APIClient.new( :application_name => "flatiron_uploder", :application_version => "0.1") client.authorization = auth video_title= "" topics = [] answer = "N" while (answer.upcase != "Y") do temp = THOR_SHELL.ask("What is the name of this video(#{video_title})?") video_title = temp unless temp.empty? if (batch.empty?) puts "#"*30 puts "\n\nUploading Topic Video!\n\n" puts "#"*30 end temp = THOR_SHELL.ask("Comma separated list of topics (#{topics})?") topics = temp.split(",") unless temp.empty? puts "#"*30 puts "Summary" puts "Title: #{video_title}" puts "Batch: #{batch}" unless batch.empty? puts "Topics: #{topics}" answer=THOR_SHELL.ask("Is that correct (Y/N)?") end youtube = client.discovered_api("youtube","v3") s3 = Aws::S3::Client.new( # credentials: Aws::Credentials.new('AKIAJY4YSCUKNRWWASIA', 'lXp+rsDPaHcoaEay3XcjfAnE1l1W8BRWOrdLfsPH'), credentials: Aws::Credentials.new(token_response['amazon_s3_key'], token_response['amazon_s3_secret']), region: 'us-east-1' ) topics << batch unless batch.empty? # begin body = { :snippet => { :title => video_title, :tags => topics }, :status => { :privacyStatus => "unlisted" } } puts "\n\nOK, about to upload the video. This will take a while" begin video_to_upload = Google::APIClient::UploadIO.new(file, 'video/*') video_to_upload.chunk_size =10000000 progressbar = ProgressBar.create(:title => "Youtube Upload", :total =>video_to_upload.length) videos_insert_response = client.execute( :api_method => youtube.videos.insert, :body_object => body, :media => video_to_upload, :retries => 0, :parameters => { :uploadType => 'resumable', :part => body.keys.join(','), } ) while !videos_insert_response.resumable_upload.complete? do progressbar.progress += video_to_upload.chunk_size videos_insert_response = client.execute(videos_insert_response.resumable_upload) end progressbar.finish puts "Uploaded wooooooooo. The id is #{videos_insert_response.data.id}" puts "\n\n" puts "#"*30 puts "Place this in todays schedule on github\n\n\n" command = "<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/#{videos_insert_response.data.id}?rel=0&modestbranding=1\" frameborder=\"0\" allowfullscreen></iframe><p><a href=\"https://www.youtube.com/watch?v=#{videos_insert_response.data.id}\">#{video_title}</a></p>" puts command puts "\n\n" puts "#"*30 rescue Exception => e exit end TerminalNotifier.notify("Finished Uploading Video to Youtube. Click to copy embed ", :title => "Video Uploader", :execute => `echo '#{command}' | pbcopy`) # rescue Google::APIClient::TransmissionError => e # binding.pry # puts e.result.body # end puts "Waiting for the video to finish encoding to iPad format\n\n" raw_upload_thread = nil if batch.empty? raw_upload_thread = Thread.new do raw_obj = s3.bucket('flatiron-school-learn-videos').object("topic-videos-full/#{videos_insert_response.data.id}.mp4") raw_obj.upload_file(file, acl:'public-read') end end print_progress = true movie_transcode_thread.join puts "\nDone transcoding. Let's upload to S3" bucket = 'flatiron-school-learn-videos' key = "lecture-videos/#{videos_insert_response.data.id}.mp4" lock_file = File.open("/tmp/flatiron-uploader.lock","a+") lock_file.sync=true exit unless lock_file.flock( File::LOCK_NB | File::LOCK_EX ) file_name = "/tmp/transcoded.mp4" File.open('/tmp/transcoded.mp4', 'rb') do |file| if file.size > PART_SIZE puts "File size over #{PART_SIZE} bytes, using multipart upload..." input_opts = { bucket: bucket, key: key, } input_opts_with_acl = input_opts.merge({acl: "public-read"}) lock_hash = {} total_parts = file.size.to_f / PART_SIZE current_part=1 begin existing_file = lock_file.read lock_hash = JSON.parse existing_file if lock_hash["file_name"]==file_name && lock_hash["file_size"]==file.size && lock_hash["key"]==key && lock_hash["total_parts"] == total_parts binding.pry current_part = lock_hash["current_part"] else input_opts_with_upload = input_opts.merge({ :upload_id => lock_hash["upload_id"], :key => lock_hash["key"], }) s3.abort_multipart_upload(input_opts_with_upload) binding.pry lock_file.truncate(0) mpu_create_response = s3.create_multipart_upload(input_opts_with_acl) lock_hash = {"total_parts"=> total_parts, "current_part" => current_part, "file_name" =>file_name, "file_size" => file.size, "key" => key, "upload_id" =>mpu_create_response.upload_id, } lock_file.puts lock_hash.to_json end rescue StandardError => e mpu_create_response = s3.create_multipart_upload(input_opts_with_acl) lock_hash = {"total_parts"=> total_parts, "current_part" => current_part, "file_name" =>file_name, "file_size" => file.size, "key" => key, "upload_id" =>mpu_create_response.upload_id, } lock_file.puts lock_hash.to_json end file.each_part(current_part) do |part| begin tries ||=3 part_response = s3.upload_part({ body: part, bucket: bucket, key: key, part_number: current_part, upload_id: lock_hash["upload_id"], }) percent_complete = (current_part.to_f / total_parts.to_f) * 100 percent_complete = 100 if percent_complete > 100 percent_complete = sprintf('%.2f', percent_complete.to_f) puts "percent complete: #{percent_complete}" current_part = current_part + 1 lock_hash["current_part"]=current_part lock_file.truncate(0) lock_file.puts lock_hash.to_json rescue Exception => e if e.class == Interrupt puts "LEaving" lock_file.truncate(0) lock_file.puts lock_hash.to_json File.delete(lock_file.path) exit end puts "trying again" # input_opts = input_opts.merge({ # :upload_id => mpu_create_response.upload_id, # }) lock_file.truncate(0) lock_file.puts lock_hash.to_json retry unless (tries-=1).zero? puts "Couldn't get it to work, exiting" File.delete(lock_file.path) exit end end mark_as_complete(s3,input_opts,lock_hash) File.delete(lock_file.path) else s3.put_object(bucket: bucket, key: key, body: file, acl: 'public-read') end end # obj = s3.bucket('flatiron-school-learn-videos').object("lecture-videos/#{videos_insert_response.data.id}.mp4") # obj.initiate_multipart_upload(options) # obj.upload_file('/tmp/transcoded.mp4', acl:'public-read') raw_upload_thread.join unless raw_upload_thread.nil? puts "All Done!" TerminalNotifier.notify("All Done!", :title =>"Video Uploader") `rm /tmp/transcoded.mp4` end