require "yt_data_api/version" require 'net/https' require 'open-uri' require 'rss' require 'xml' module YtDataApi class YtDataApiClient def initialize(user_id, user_pswd, dev_key) post_response = client_login(user_id, user_pswd, dev_key) if(post_response.code != "200") raise "Error while authenticating #{user_id} - #{post_response.code}: #{post_response.message}" end end def create_playlist(playlist_name) headers = {"Content-Type" => "application/atom+xml", "Authorization" => "GoogleLogin auth=#{@client_auth_key}", "X-GData-Key" => @dev_auth_key, "GData-Version" => "2"} new_row = "" + "" + "#{playlist_name}" headers["Content-Length"] = new_row.bytesize.to_s uri = URI.parse("http://gdata.youtube.com/feeds/api/users/default/playlists") http = Net::HTTP.new(uri.host, uri.port) post_response = http.post(uri.path, new_row, headers) post_response_content = parse_atom_xml(post_response) post_response_entry = post_response_content.root.find_first('yt:playlistId') playlist_id = post_response_entry.content return post_response, playlist_id end def get_playlist_id(playlist_name) headers = {"Content-Type" => "application/x-www-form-urlencoded", "Authorization" => "GoogleLogin auth=#{@client_auth_key}", "X-GData-Key" => @dev_auth_key} uri = URI.parse("http://gdata.youtube.com/feeds/api/users/default/playlists?v=2") playlists_feed = Net::HTTP.start(uri.host, uri.port){|http| http.get(uri.path, headers) } playlists_content = parse_atom_xml(playlists_feed) playlists_entries = playlists_content.root.find('atom:entry') playlists_entries.each do |entry| if(entry.find_first('atom:title').content.eql?(playlist_name)) return entry.find_first('yt:playlistId').content end end return nil end def get_video_ids(search_query, count = 1) query_uri = URI.parse("http://gdata.youtube.com/feeds/api/videos?q=#{search_query}&max-results=#{count}") rss_query_result = parse_rss(query_uri) video_ids = [] rss_query_result.items.each do |item| video_id = item.id.to_s[/http:\/\/(.*\/)(.*)<\/id>/, 2] return video_id if count == 1 video_ids << video_id end if(video_ids.empty?) nil else video_ids end end def add_video_to_playlist(video_id, playlist_id) headers = {"Content-Type" => "application/atom+xml", "Authorization" => "GoogleLogin auth=#{@client_auth_key}", "X-GData-Key" => @dev_auth_key, "GData-Version" => "2"} new_row = "" + "" + "#{video_id}" headers["Content-Length"] = new_row.bytesize.to_s uri = URI.parse("http://gdata.youtube.com/feeds/api/playlists/#{playlist_id}") http = Net::HTTP.new(uri.host, uri.port) post_response = http.post(uri.path, new_row, headers) end def add_videos_to_playlist(video_ids, playlist_id) failed_to_add = [] video_ids.each_with_index do |video_id, index| post_response = add_video_to_playlist(video_id, playlist_id) if(post_response.code == "403") sleep(30) post_repsonse = add_video_to_playlist(video_id, playlist_id) end if(post_response.code != "201") failed_to_add << "#{index + 1},#{video_id},#{post_response.code}" end end if(failed_to_add.empty?) "201" else failed_to_add end end def get_client_playlist_entries(playlist_id) headers = {"Content-Type" => "application/x-www-form-urlencoded", "Authorization" => "GoogleLogin auth=#{@client_auth_key}", "X-GData-Key" => @dev_auth_key} uri = URI.parse("http://gdata.youtube.com/feeds/api/playlists/#{playlist_id}?v=2") playlist_entries_feed = Net::HTTP.start(uri.host, uri.port){|http| http.get(uri.path, headers) } playlist_entries_content = parse_atom_xml(playlist_entries_feed) playlist_entries = playlist_entries_content.root.find('atom:entry') playlist_entries_ids = [] playlist_entries.each do |entry| entry_id = entry.find_first('atom:id') playlist_entry = entry_id.content[/http:\/\/.*\/(.+)/, 1] playlist_entries_ids << playlist_entry end playlist_entries_ids end def empty_playlist(playlist_id) headers = {"Content-Type" => "application/atom+xml", "Authorization" => "GoogleLogin auth=#{@client_auth_key}", "X-GData-Key" => @dev_auth_key, "GData-Version" => "2"} playlist_entries = self.get_client_playlist_entries(playlist_id) playlist_entries.each do |playlist_entry| uri = URI.parse("http://gdata.youtube.com/feeds/api/playlists/#{playlist_id}/#{playlist_entry}") http = Net::HTTP.new(uri.host, uri.port) delete_response = http.delete(uri.path, headers) if(delete_response.code != "200") raise "#{playlist_entry} not deleted from #{@playlist_id} - #{delete_response.code}" end end self.get_client_playlist_entries(playlist_id).empty? end def delete_playlist(playlist_id) headers = {"Content-Type" => "application/atom+xml", "Authorization" => "GoogleLogin auth=#{@client_auth_key}", "X-GData-Key" => @dev_auth_key, "GData-Version" => "2"} uri = URI.parse("http://gdata.youtube.com/feeds/api/users/#{@client_user_id}/playlists/#{playlist_id}") http = Net::HTTP.new(uri.host, uri.port) delete_response = http.delete(uri.path, headers) if(delete_response.code != "200") raise "#{playlist_id} not deleted for #{@client_user_id} - #{delete_response.code}" end delete_response.code end private #Use Ruby RSS Parser to return parseable info from RSS feed def parse_rss(rss_feed) rss_content = "" #Get feed information open (rss_feed) do |f| rss_content = f.read end RSS::Parser.parse(rss_content, false) end def parse_atom_xml(xml) source = XML::Parser.string(xml.body) content = source.parse content.root.namespaces.default_prefix = 'atom' content end def http_post_ssl(url, data, headers) uri = URI.parse(url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.post(uri.path, data, headers) end def client_login(user_id, user_pswd, dev_key) post_url = "https://www.google.com/accounts/ClientLogin" data = "Email=#{user_id}&Passwd=#{user_pswd}&service=youtube&source=YtDataApi" headers = {"Content-Type" => "application/x-www-form-urlencoded"} post_response, data = http_post_ssl(post_url, data, headers) if(post_response.code != "200") post_response else @client_user_id = user_id @client_auth_key = data[/Auth=(.*)/, 1] @dev_auth_key = "key=" + dev_key post_response end end end end