Skip to content

Instantly share code, notes, and snippets.

@hayesdavis
Created April 18, 2009 20:01
Show Gist options
  • Save hayesdavis/97756 to your computer and use it in GitHub Desktop.
Save hayesdavis/97756 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# This script performs an OAuth authorized POST with multipart encoding to
# http://twitter.com/account/update_profile_image.json
#
# This code is primarily taken from my Grackle library's implementation at
# http://github.com/hayesdavis/grackle
#
# RUNNING THIS WILL CHANGE AN ACCOUNT'S PROFILE IMAGE. BE CAREFUL.
#
# Instructions to run this script:
# 1) Install the OAuth gem if you don't have it (sudo gem install oauth)
# 2) Create an oauth.yml file in your working directory (see format below)
# 3) Run "ruby update_profile_image.rb /Path/to/image/file"
#
# oauth.yml format:
# consumer_key: APP_CONSUMER_KEY_FROM_TWITTER
# consumer_secret: APP_CONSUMER_SECRET_FROM_TWITTER
# token: ACCESS_TOKEN_FOR_A_USER_RETRIEVED_VIA_OAUTH_FLOW
# token_secret: ACCESS_TOKEN_SECRET_FOR_A_USER_RETRIEVED_VIA_OAUTH_FLOW
require 'rubygems'
require 'oauth'
require 'open-uri'
require 'net/http'
require 'yaml'
require 'cgi'
CRLF = "\r\n"
if ARGV.size < 1
puts "Usage: update_profile_image.rb path_to_image_file"
puts "e.g. update_profile_image.rb /Users/me/my_photo.jpg"
exit(1)
end
image_file = File.new(ARGV[0])
begin
oauth_config = YAML.load(IO.read('oauth.yml'))
#Make sure oauth_config contains symbol keys
oauth_config.replace(oauth_config.inject({}) {|h, (key,value)| h[key.to_sym] = value; h})
rescue
puts "You must have an oauth.yml file with your consumer and access info"
end
#Quick and dirty method for determining mime type of uploaded file
def mime_type(file)
case
when file =~ /\.jpg/ then 'image/jpg'
when file =~ /\.gif$/ then 'image/gif'
when file =~ /\.png$/ then 'image/png'
else 'application/octet-stream'
end
end
#Encodes the request as multipart
def add_multipart_data(req,params)
boundary = Time.now.to_i.to_s(16)
req["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
body = ""
params.each do |key,value|
esc_key = CGI.escape(key.to_s)
body << "--#{boundary}#{CRLF}"
if value.respond_to?(:read)
body << "Content-Disposition: form-data; name=\"#{esc_key}\"; filename=\"#{File.basename(value.path)}\"#{CRLF}"
body << "Content-Type: #{mime_type(value.path)}#{CRLF*2}"
body << value.read
else
body << "Content-Disposition: form-data; name=\"#{esc_key}\"#{CRLF*2}#{value}"
end
body << CRLF
end
body << "--#{boundary}--#{CRLF*2}"
req.body = body
req["Content-Length"] = req.body.size
end
#Uses the OAuth gem to add the signed Authorization header
def add_oauth(req,auth)
consumer = OAuth::Consumer.new(
auth[:consumer_key],auth[:consumer_secret],{:site=>'http://api.twitter.com'}
)
access_token = OAuth::AccessToken.new(consumer,auth[:token],auth[:token_secret])
consumer.sign!(req,access_token)
end
#Actually do the request and print out the response
url = URI.parse('http://api.twitter.com/1/account/update_profile_image.json')
Net::HTTP.new(url.host, url.port).start do |http|
req = Net::HTTP::Post.new(url.request_uri)
add_multipart_data(req,:image=>image_file)
add_oauth(req,oauth_config)
res = http.request(req)
puts res.body
end
@drewww
Copy link

drewww commented Aug 30, 2011

Updated version that uses the current API resource URIs here: https://gist.github.com/1181291

@hayesdavis
Copy link
Author

@drewww, I merged in your changes. Thanks for updating that.

@hayesdavis
Copy link
Author

hayesdavis commented Aug 30, 2011 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment