yt_data_api 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.markdown +6 -0
- data/Rakefile +1 -0
- data/lib/yt_data_api/version.rb +3 -0
- data/lib/yt_data_api.rb +205 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/yt_data_api_spec.rb +62 -0
- data/yt_data_api.gemspec +26 -0
- metadata +80 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/lib/yt_data_api.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
require "yt_data_api/version"
|
2
|
+
require 'net/https'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'rss'
|
5
|
+
require 'xml'
|
6
|
+
|
7
|
+
module YtDataApi
|
8
|
+
class YtDataApiClient
|
9
|
+
def initialize(user_id, user_pswd, dev_key)
|
10
|
+
self.client_login(user_id, user_pswd, dev_key)
|
11
|
+
end
|
12
|
+
|
13
|
+
def client_login(user_id, user_pswd, dev_key)
|
14
|
+
http = Net::HTTP.new("www.google.com", 443)
|
15
|
+
http.use_ssl = true
|
16
|
+
path = "/accounts/ClientLogin"
|
17
|
+
|
18
|
+
data = "Email=#{user_id}&Passwd=#{user_pswd}&service=youtube&source=Test"
|
19
|
+
headers = {"Content-Type" => "application/x-www-form-urlencoded"}
|
20
|
+
|
21
|
+
response, data = http.post(path, data, headers)
|
22
|
+
|
23
|
+
if(response.code != "200")
|
24
|
+
raise "Error while authenticating YouTube user - #{response.code}"
|
25
|
+
end
|
26
|
+
|
27
|
+
@client_user_id = user_id
|
28
|
+
@client_auth_key = data[/Auth=(.*)/, 1]
|
29
|
+
@dev_auth_key = "key=" + dev_key
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_video_id(search_query)
|
33
|
+
query_uri = URI.parse("http://gdata.youtube.com/feeds/api/videos?q=#{search_query}&max-results=1")
|
34
|
+
rss_query_result = parse_rss(query_uri)
|
35
|
+
|
36
|
+
rss_query_result.items.each do |item|
|
37
|
+
return item.id.to_s[/<id>http:\/\/(.*\/)(.*)<\/id>/, 2]
|
38
|
+
end
|
39
|
+
|
40
|
+
return nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_client_playlist_id(playlist_name)
|
44
|
+
headers = {"Content-Type" => "application/x-www-form-urlencoded",
|
45
|
+
"Authorization" => "GoogleLogin auth=#{@client_auth_key}",
|
46
|
+
"X-GData-Key" => @dev_auth_key}
|
47
|
+
|
48
|
+
uri = URI.parse("http://gdata.youtube.com/feeds/api/users/default/playlists?v=2")
|
49
|
+
|
50
|
+
xml_client_playlists = Net::HTTP.start(uri.host, uri.port){|http|
|
51
|
+
http.get(uri.path, headers)
|
52
|
+
}
|
53
|
+
|
54
|
+
#Parse xml of client's playlists
|
55
|
+
source = XML::Parser.string(xml_client_playlists.body)
|
56
|
+
content = source.parse
|
57
|
+
content.root.namespaces.default_prefix = 'atom'
|
58
|
+
|
59
|
+
entries = content.root.find('atom:entry')
|
60
|
+
|
61
|
+
#Get playlist id
|
62
|
+
entries.each do |entry|
|
63
|
+
if(entry.find_first('atom:title').content.eql?(playlist_name))
|
64
|
+
feedlink = entry.find_first('gd:feedLink').attributes["href"]
|
65
|
+
return feedlink[/http:\/\/gdata.youtube.com\/feeds\/api\/playlists\/(.+)/, 1]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
return nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_client_playlist_entries(playlist_id)
|
73
|
+
headers = {"Content-Type" => "application/x-www-form-urlencoded",
|
74
|
+
"Authorization" => "GoogleLogin auth=#{@client_auth_key}",
|
75
|
+
"X-GData-Key" => @dev_auth_key}
|
76
|
+
|
77
|
+
uri = URI.parse("http://gdata.youtube.com/feeds/api/playlists/#{playlist_id}?v=2")
|
78
|
+
|
79
|
+
xml_client_playlist_videos = Net::HTTP.start(uri.host, uri.port){|http|
|
80
|
+
http.get(uri.path, headers)
|
81
|
+
}
|
82
|
+
|
83
|
+
source = XML::Parser.string(xml_client_playlist_videos.body)
|
84
|
+
content = source.parse
|
85
|
+
content.root.namespaces.default_prefix = 'atom'
|
86
|
+
|
87
|
+
entries = content.root.find('atom:entry')
|
88
|
+
|
89
|
+
playlist_entries = []
|
90
|
+
|
91
|
+
entries.each do |entry|
|
92
|
+
entry_id = entry.find_first('atom:id')
|
93
|
+
playlist_entry =
|
94
|
+
entry_id.content[/http:\/\/.*\/(.+)/, 1]
|
95
|
+
playlist_entries << playlist_entry
|
96
|
+
end
|
97
|
+
|
98
|
+
playlist_entries
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_video_to_playlist(video_id, playlist_id)
|
103
|
+
headers = {"Content-Type" => "application/atom+xml",
|
104
|
+
"Authorization" => "GoogleLogin auth=#{@client_auth_key}",
|
105
|
+
"X-GData-Key" => @dev_auth_key,
|
106
|
+
"GData-Version" => "2"}
|
107
|
+
|
108
|
+
new_row = "<?xml version='1.0' encoding='UTF-8'?>" +
|
109
|
+
"<entry xmlns='http://www.w3.org/2005/Atom' " +
|
110
|
+
"xmlns:yt='http://gdata.youtube.com/schemas/2007'>" +
|
111
|
+
"<id>#{video_id}</id></entry>"
|
112
|
+
|
113
|
+
headers["Content-Length"] = new_row.bytesize.to_s
|
114
|
+
|
115
|
+
uri = URI.parse("http://gdata.youtube.com/feeds/api/playlists/#{playlist_id}")
|
116
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
117
|
+
|
118
|
+
post_response = http.post(uri.path, new_row, headers)
|
119
|
+
|
120
|
+
if(post_response.code != "201")
|
121
|
+
raise "Error while adding #{video_id} to #{playlist_id} - #{post_response.code}"
|
122
|
+
end
|
123
|
+
|
124
|
+
post_response.code
|
125
|
+
end
|
126
|
+
|
127
|
+
def create_playlist(playlist_name)
|
128
|
+
headers = {"Content-Type" => "application/atom+xml",
|
129
|
+
"Authorization" => "GoogleLogin auth=#{@client_auth_key}",
|
130
|
+
"X-GData-Key" => @dev_auth_key,
|
131
|
+
"GData-Version" => "2"}
|
132
|
+
|
133
|
+
new_row = "<?xml version='1.0' encoding='UTF-8'?>" +
|
134
|
+
"<entry xmlns='http://www.w3.org/2005/Atom' " +
|
135
|
+
"xmlns:yt='http://gdata.youtube.com/schemas/2007'>" +
|
136
|
+
"<title type='text'>#{playlist_name}</title><summary></summary></entry>"
|
137
|
+
|
138
|
+
headers["Content-Length"] = new_row.bytesize.to_s
|
139
|
+
|
140
|
+
uri = URI.parse("http://gdata.youtube.com/feeds/api/users/default/playlists")
|
141
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
142
|
+
|
143
|
+
post_response = http.post(uri.path, new_row, headers)
|
144
|
+
|
145
|
+
if(post_response.code != "201")
|
146
|
+
raise "Error while creating #{playlist_name} - #{post_response.code}"
|
147
|
+
end
|
148
|
+
|
149
|
+
post_response.code
|
150
|
+
end
|
151
|
+
|
152
|
+
def empty_playlist(playlist_id)
|
153
|
+
headers = {"Content-Type" => "application/atom+xml",
|
154
|
+
"Authorization" => "GoogleLogin auth=#{@client_auth_key}",
|
155
|
+
"X-GData-Key" => @dev_auth_key,
|
156
|
+
"GData-Version" => "2"}
|
157
|
+
|
158
|
+
playlist_entries = self.get_client_playlist_entries(playlist_id)
|
159
|
+
|
160
|
+
playlist_entries.each do |playlist_entry|
|
161
|
+
uri = URI.parse("http://gdata.youtube.com/feeds/api/playlists/#{playlist_id}/#{playlist_entry}")
|
162
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
163
|
+
|
164
|
+
delete_response = http.delete(uri.path, headers)
|
165
|
+
|
166
|
+
if(delete_response.code != "200")
|
167
|
+
raise "#{playlist_entry} not deleted from #{@playlist_id} - #{delete_response.code}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
self.get_client_playlist_entries(playlist_id).empty?
|
172
|
+
end
|
173
|
+
|
174
|
+
def delete_playlist(playlist_id)
|
175
|
+
headers = {"Content-Type" => "application/atom+xml",
|
176
|
+
"Authorization" => "GoogleLogin auth=#{@client_auth_key}",
|
177
|
+
"X-GData-Key" => @dev_auth_key,
|
178
|
+
"GData-Version" => "2"}
|
179
|
+
|
180
|
+
uri = URI.parse("http://gdata.youtube.com/feeds/api/users/#{@client_user_id}/playlists/#{playlist_id}")
|
181
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
182
|
+
|
183
|
+
delete_response = http.delete(uri.path, headers)
|
184
|
+
|
185
|
+
if(delete_response.code != "200")
|
186
|
+
raise "#{playlist_id} not deleted for #{@client_user_id} - #{delete_response.code}"
|
187
|
+
end
|
188
|
+
|
189
|
+
delete_response.code
|
190
|
+
end
|
191
|
+
|
192
|
+
private
|
193
|
+
#Use Ruby RSS Parser to return parseable info from RSS feed
|
194
|
+
def parse_rss(rss_feed)
|
195
|
+
rss_content = ""
|
196
|
+
|
197
|
+
#Get feed information
|
198
|
+
open (rss_feed) do |f|
|
199
|
+
rss_content = f.read
|
200
|
+
end
|
201
|
+
|
202
|
+
RSS::Parser.parse(rss_content, false)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "YtDataApi::YtDataApiClient" do
|
4
|
+
it "should create a new instance using ClientLogin authentication" do
|
5
|
+
YtDataApi::YtDataApiClient.new(ENV['YT_USER'], ENV['YT_USER_PSWD'], ENV['YT_DEV_AUTH_KEY'])
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should not create a new instance without credentials for ClientLogin Authentication" do
|
9
|
+
lambda{ YtDataApi::YtDataApiClient.new }.should raise_error ArgumentError
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should not create a new instance without valid credentials for ClientLogin Authentication" do
|
13
|
+
lambda{ YtDataApi::YtDataApiClient.new("trash", "trash", "trash") }.should raise_error
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "authenticated" do
|
17
|
+
before(:each) do
|
18
|
+
@client = YtDataApi::YtDataApiClient.new(ENV['YT_USER'], ENV['YT_USER_PSWD'], ENV['YT_DEV_AUTH_KEY'])
|
19
|
+
@create_response = @client.create_playlist("test_one")
|
20
|
+
@playlist_id = @client.get_client_playlist_id("test_one")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should create a client's playlist" do
|
24
|
+
@create_response.should == "201"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should get a client's playlist id given the playlist's name" do
|
28
|
+
@playlist_id.should_not be nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should get a video id given a query string" do
|
32
|
+
query = "vampire-weekend-giving-up-the-gun"
|
33
|
+
video_id = @client.get_video_id(query)
|
34
|
+
video_id.should == "bccKotFwzoY"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should add a video to a client's playlist" do
|
38
|
+
video_id = "bccKotFwzoY"
|
39
|
+
post_response = @client.add_video_to_playlist(video_id, @playlist_id)
|
40
|
+
post_response.should == "201"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should remove all videos from a client's playlist" do
|
44
|
+
3.times do
|
45
|
+
@client.add_video_to_playlist("bccKotFwzoY", @playlist_id)
|
46
|
+
end
|
47
|
+
|
48
|
+
empty_playlist = @client.empty_playlist(@playlist_id)
|
49
|
+
empty_playlist.should == true
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should delete a client's playlist" do
|
53
|
+
delete_response = @client.delete_playlist(@playlist_id)
|
54
|
+
delete_response.should == "200"
|
55
|
+
end
|
56
|
+
|
57
|
+
after(:each) do
|
58
|
+
playlist = @client.get_client_playlist_id("test_one")
|
59
|
+
@client.delete_playlist(@playlist_id) unless playlist.nil?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/yt_data_api.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "yt_data_api/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "yt_data_api"
|
7
|
+
s.version = YtDataApi::VERSION
|
8
|
+
s.authors = ["Ali Ibrahim"]
|
9
|
+
s.email = ["aibrahim2k2@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Adds functionality to access YouTube Data API}
|
12
|
+
s.description = %q{Create a new instance of YtDataApi::YtDataApiClient passing
|
13
|
+
user credentials (username, password) and YouTube developer key
|
14
|
+
to access YouTube Data API using ClientLogin authentication.}
|
15
|
+
|
16
|
+
s.rubyforge_project = "yt_data_api"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.add_dependency 'libxml-ruby', '~>1.1.3'
|
24
|
+
|
25
|
+
s.add_development_dependency 'rspec', '~>2.4.0'
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yt_data_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ali Ibrahim
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-24 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: libxml-ruby
|
16
|
+
requirement: &70195100472000 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.1.3
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70195100472000
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &70195100474040 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.4.0
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70195100474040
|
36
|
+
description: ! "Create a new instance of YtDataApi::YtDataApiClient passing \n user
|
37
|
+
credentials (username, password) and YouTube developer key\n to
|
38
|
+
access YouTube Data API using ClientLogin authentication."
|
39
|
+
email:
|
40
|
+
- aibrahim2k2@gmail.com
|
41
|
+
executables: []
|
42
|
+
extensions: []
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- Gemfile
|
47
|
+
- README.markdown
|
48
|
+
- Rakefile
|
49
|
+
- lib/yt_data_api.rb
|
50
|
+
- lib/yt_data_api/version.rb
|
51
|
+
- spec/spec_helper.rb
|
52
|
+
- spec/yt_data_api_spec.rb
|
53
|
+
- yt_data_api.gemspec
|
54
|
+
homepage: ''
|
55
|
+
licenses: []
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project: yt_data_api
|
74
|
+
rubygems_version: 1.8.6
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Adds functionality to access YouTube Data API
|
78
|
+
test_files:
|
79
|
+
- spec/spec_helper.rb
|
80
|
+
- spec/yt_data_api_spec.rb
|