yt_data_api 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +25 -3
- data/lib/yt_data_api.rb +121 -90
- data/lib/yt_data_api/version.rb +1 -1
- data/spec/yt_data_api_spec.rb +52 -11
- metadata +6 -6
data/README.markdown
CHANGED
@@ -1,6 +1,28 @@
|
|
1
1
|
#Yt_Data_Api
|
2
2
|
|
3
|
-
|
3
|
+
yt_data_api adds functionality to access elements of the YouTube Data API. This was created as a learning tool. Check out youtube_it for more functionality, https://github.com/kylejginavan/youtube_it.
|
4
4
|
|
5
|
-
#
|
6
|
-
|
5
|
+
#Usage
|
6
|
+
|
7
|
+
First, create a new client object passing YouTube user credentials. Note you will have to acquire a developer key from YouTube, http://code.google.com/apis/youtube/2.0/developers_guide_protocol.html#Developer_Key.
|
8
|
+
|
9
|
+
`client = YtDataApi::YtDataApiClient.new(YOUTUBE_USER_ID, YOUTUBE_USER_PSWD, YOUTUBE_DEV_KEY)`
|
10
|
+
|
11
|
+
Then, call functions on the client object to access the YouTube Data API.
|
12
|
+
|
13
|
+
##Create a playlist and get it's id
|
14
|
+
`client.create_playlist("test")`
|
15
|
+
`playlist_id = client.get_client_playlist_id("test")`
|
16
|
+
|
17
|
+
##Delete a playlist
|
18
|
+
`client.delete_playlist(playlist_id)`
|
19
|
+
|
20
|
+
##Get a video id given a query
|
21
|
+
Note spaces were replaced with '+'
|
22
|
+
`video_id = client.get_video_id("Otis+Kanye+West")`
|
23
|
+
|
24
|
+
##Add video to client playlist
|
25
|
+
`client.add_video_to_playlist(video_id, playlist_id)`
|
26
|
+
|
27
|
+
#TODO
|
28
|
+
- Add more functionality
|
data/lib/yt_data_api.rb
CHANGED
@@ -7,98 +7,78 @@ require 'xml'
|
|
7
7
|
module YtDataApi
|
8
8
|
class YtDataApiClient
|
9
9
|
def initialize(user_id, user_pswd, dev_key)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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}"
|
10
|
+
post_response = client_login(user_id, user_pswd, dev_key)
|
11
|
+
|
12
|
+
if(post_response.code != "200")
|
13
|
+
raise "Error while authenticating #{user_id} - #{post_response.code}: #{post_response.message}"
|
25
14
|
end
|
26
|
-
|
27
|
-
@client_user_id = user_id
|
28
|
-
@client_auth_key = data[/Auth=(.*)/, 1]
|
29
|
-
@dev_auth_key = "key=" + dev_key
|
30
15
|
end
|
31
16
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
17
|
+
def create_playlist(playlist_name)
|
18
|
+
headers = {"Content-Type" => "application/atom+xml",
|
19
|
+
"Authorization" => "GoogleLogin auth=#{@client_auth_key}",
|
20
|
+
"X-GData-Key" => @dev_auth_key,
|
21
|
+
"GData-Version" => "2"}
|
22
|
+
|
23
|
+
new_row = "<?xml version='1.0' encoding='UTF-8'?>" +
|
24
|
+
"<entry xmlns='http://www.w3.org/2005/Atom' " +
|
25
|
+
"xmlns:yt='http://gdata.youtube.com/schemas/2007'>" +
|
26
|
+
"<title type='text'>#{playlist_name}</title><summary></summary></entry>"
|
35
27
|
|
36
|
-
|
37
|
-
return item.id.to_s[/<id>http:\/\/(.*\/)(.*)<\/id>/, 2]
|
38
|
-
end
|
28
|
+
headers["Content-Length"] = new_row.bytesize.to_s
|
39
29
|
|
40
|
-
|
30
|
+
uri = URI.parse("http://gdata.youtube.com/feeds/api/users/default/playlists")
|
31
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
32
|
+
|
33
|
+
post_response = http.post(uri.path, new_row, headers)
|
34
|
+
post_response_content = parse_atom_xml(post_response)
|
35
|
+
post_response_entry = post_response_content.root.find_first('yt:playlistId')
|
36
|
+
playlist_id = post_response_entry.content
|
37
|
+
|
38
|
+
return post_response, playlist_id
|
41
39
|
end
|
42
|
-
|
43
|
-
def
|
40
|
+
|
41
|
+
def get_playlist_id(playlist_name)
|
44
42
|
headers = {"Content-Type" => "application/x-www-form-urlencoded",
|
45
43
|
"Authorization" => "GoogleLogin auth=#{@client_auth_key}",
|
46
44
|
"X-GData-Key" => @dev_auth_key}
|
47
45
|
|
48
46
|
uri = URI.parse("http://gdata.youtube.com/feeds/api/users/default/playlists?v=2")
|
49
47
|
|
50
|
-
|
48
|
+
playlists_feed = Net::HTTP.start(uri.host, uri.port){|http|
|
51
49
|
http.get(uri.path, headers)
|
52
50
|
}
|
51
|
+
|
52
|
+
playlists_content = parse_atom_xml(playlists_feed)
|
53
|
+
playlists_entries = playlists_content.root.find('atom:entry')
|
53
54
|
|
54
|
-
|
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|
|
55
|
+
playlists_entries.each do |entry|
|
63
56
|
if(entry.find_first('atom:title').content.eql?(playlist_name))
|
64
|
-
|
65
|
-
return feedlink[/http:\/\/gdata.youtube.com\/feeds\/api\/playlists\/(.+)/, 1]
|
57
|
+
return entry.find_first('yt:playlistId').content
|
66
58
|
end
|
67
59
|
end
|
68
60
|
|
69
61
|
return nil
|
70
62
|
end
|
71
|
-
|
72
|
-
def
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
63
|
+
|
64
|
+
def get_video_ids(search_query, count = 1)
|
65
|
+
query_uri = URI.parse("http://gdata.youtube.com/feeds/api/videos?q=#{search_query}&max-results=#{count}")
|
66
|
+
rss_query_result = parse_rss(query_uri)
|
67
|
+
video_ids = []
|
68
|
+
|
69
|
+
rss_query_result.items.each do |item|
|
70
|
+
video_id = item.id.to_s[/<id>http:\/\/(.*\/)(.*)<\/id>/, 2]
|
71
|
+
return video_id if count == 1
|
72
|
+
video_ids << video_id
|
96
73
|
end
|
97
|
-
|
98
|
-
playlist_entries
|
99
74
|
|
75
|
+
if(video_ids.empty?)
|
76
|
+
nil
|
77
|
+
else
|
78
|
+
video_ids
|
79
|
+
end
|
100
80
|
end
|
101
|
-
|
81
|
+
|
102
82
|
def add_video_to_playlist(video_id, playlist_id)
|
103
83
|
headers = {"Content-Type" => "application/atom+xml",
|
104
84
|
"Authorization" => "GoogleLogin auth=#{@client_auth_key}",
|
@@ -116,37 +96,56 @@ module YtDataApi
|
|
116
96
|
http = Net::HTTP.new(uri.host, uri.port)
|
117
97
|
|
118
98
|
post_response = http.post(uri.path, new_row, headers)
|
119
|
-
|
120
|
-
|
121
|
-
|
99
|
+
end
|
100
|
+
|
101
|
+
def add_videos_to_playlist(video_ids, playlist_id)
|
102
|
+
failed_to_add = []
|
103
|
+
|
104
|
+
video_ids.each_with_index do |video_id, index|
|
105
|
+
post_response = add_video_to_playlist(video_id, playlist_id)
|
106
|
+
|
107
|
+
if(post_response.code == "403")
|
108
|
+
sleep(30)
|
109
|
+
post_repsonse = add_video_to_playlist(video_id, playlist_id)
|
110
|
+
end
|
111
|
+
|
112
|
+
if(post_response.code != "201")
|
113
|
+
failed_to_add << "#{index + 1},#{video_id},#{post_response.code}"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
if(failed_to_add.empty?)
|
118
|
+
"201"
|
119
|
+
else
|
120
|
+
failed_to_add
|
122
121
|
end
|
123
|
-
|
124
|
-
post_response.code
|
125
122
|
end
|
126
123
|
|
127
|
-
def
|
128
|
-
headers = {"Content-Type" => "application/
|
124
|
+
def get_client_playlist_entries(playlist_id)
|
125
|
+
headers = {"Content-Type" => "application/x-www-form-urlencoded",
|
129
126
|
"Authorization" => "GoogleLogin auth=#{@client_auth_key}",
|
130
|
-
"X-GData-Key" => @dev_auth_key
|
131
|
-
"GData-Version" => "2"}
|
127
|
+
"X-GData-Key" => @dev_auth_key}
|
132
128
|
|
133
|
-
|
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>"
|
129
|
+
uri = URI.parse("http://gdata.youtube.com/feeds/api/playlists/#{playlist_id}?v=2")
|
137
130
|
|
138
|
-
|
131
|
+
playlist_entries_feed = Net::HTTP.start(uri.host, uri.port){|http|
|
132
|
+
http.get(uri.path, headers)
|
133
|
+
}
|
139
134
|
|
140
|
-
|
141
|
-
|
135
|
+
playlist_entries_content = parse_atom_xml(playlist_entries_feed)
|
136
|
+
playlist_entries = playlist_entries_content.root.find('atom:entry')
|
142
137
|
|
143
|
-
|
138
|
+
playlist_entries_ids = []
|
144
139
|
|
145
|
-
|
146
|
-
|
140
|
+
playlist_entries.each do |entry|
|
141
|
+
entry_id = entry.find_first('atom:id')
|
142
|
+
playlist_entry =
|
143
|
+
entry_id.content[/http:\/\/.*\/(.+)/, 1]
|
144
|
+
playlist_entries_ids << playlist_entry
|
147
145
|
end
|
146
|
+
|
147
|
+
playlist_entries_ids
|
148
148
|
|
149
|
-
post_response.code
|
150
149
|
end
|
151
150
|
|
152
151
|
def empty_playlist(playlist_id)
|
@@ -188,7 +187,7 @@ module YtDataApi
|
|
188
187
|
|
189
188
|
delete_response.code
|
190
189
|
end
|
191
|
-
|
190
|
+
|
192
191
|
private
|
193
192
|
#Use Ruby RSS Parser to return parseable info from RSS feed
|
194
193
|
def parse_rss(rss_feed)
|
@@ -200,6 +199,38 @@ module YtDataApi
|
|
200
199
|
end
|
201
200
|
|
202
201
|
RSS::Parser.parse(rss_content, false)
|
203
|
-
|
202
|
+
end
|
203
|
+
|
204
|
+
def parse_atom_xml(xml)
|
205
|
+
source = XML::Parser.string(xml.body)
|
206
|
+
content = source.parse
|
207
|
+
content.root.namespaces.default_prefix = 'atom'
|
208
|
+
content
|
209
|
+
end
|
210
|
+
|
211
|
+
def http_post_ssl(url, data, headers)
|
212
|
+
uri = URI.parse(url)
|
213
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
214
|
+
http.use_ssl = true
|
215
|
+
|
216
|
+
http.post(uri.path, data, headers)
|
217
|
+
end
|
218
|
+
|
219
|
+
def client_login(user_id, user_pswd, dev_key)
|
220
|
+
post_url = "https://www.google.com/accounts/ClientLogin"
|
221
|
+
data = "Email=#{user_id}&Passwd=#{user_pswd}&service=youtube&source=YtDataApi"
|
222
|
+
headers = {"Content-Type" => "application/x-www-form-urlencoded"}
|
223
|
+
|
224
|
+
post_response, data = http_post_ssl(post_url, data, headers)
|
225
|
+
|
226
|
+
if(post_response.code != "200")
|
227
|
+
post_response
|
228
|
+
else
|
229
|
+
@client_user_id = user_id
|
230
|
+
@client_auth_key = data[/Auth=(.*)/, 1]
|
231
|
+
@dev_auth_key = "key=" + dev_key
|
232
|
+
post_response
|
233
|
+
end
|
234
|
+
end
|
204
235
|
end
|
205
236
|
end
|
data/lib/yt_data_api/version.rb
CHANGED
data/spec/yt_data_api_spec.rb
CHANGED
@@ -5,10 +5,6 @@ describe "YtDataApi::YtDataApiClient" do
|
|
5
5
|
YtDataApi::YtDataApiClient.new(ENV['YT_USER'], ENV['YT_USER_PSWD'], ENV['YT_DEV_AUTH_KEY'])
|
6
6
|
end
|
7
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
8
|
it "should not create a new instance without valid credentials for ClientLogin Authentication" do
|
13
9
|
lambda{ YtDataApi::YtDataApiClient.new("trash", "trash", "trash") }.should raise_error
|
14
10
|
end
|
@@ -16,27 +12,72 @@ describe "YtDataApi::YtDataApiClient" do
|
|
16
12
|
describe "authenticated" do
|
17
13
|
before(:each) do
|
18
14
|
@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")
|
15
|
+
@create_response, @playlist_id = @client.create_playlist("test_one")
|
21
16
|
end
|
22
17
|
|
23
18
|
it "should create a client's playlist" do
|
24
|
-
@create_response.should == "201"
|
19
|
+
@create_response.code.should == "201"
|
25
20
|
end
|
26
21
|
|
27
22
|
it "should get a client's playlist id given the playlist's name" do
|
28
|
-
|
23
|
+
playlist_id = @client.get_playlist_id("test_one")
|
24
|
+
playlist_id.should == @playlist_id
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return nil if the playlist id cannot be found given playlist name" do
|
28
|
+
playlist_id = @client.get_playlist_id("trash")
|
29
|
+
playlist_id.should == nil
|
29
30
|
end
|
30
31
|
|
31
|
-
it "should get
|
32
|
+
it "should get one video id given a query string" do
|
32
33
|
query = "vampire-weekend-giving-up-the-gun"
|
33
|
-
video_id = @client.
|
34
|
+
video_id = @client.get_video_ids(query)
|
34
35
|
video_id.should == "bccKotFwzoY"
|
35
36
|
end
|
37
|
+
|
38
|
+
it "should get multiple video ids given a query string and count" do
|
39
|
+
query = "vampire-weekend-giving-up-the-gun"
|
40
|
+
video_ids = @client.get_video_ids(query, 10)
|
41
|
+
video_ids.size.should == 10
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return nil if no videos are found for given query" do
|
45
|
+
query = ","
|
46
|
+
video_id = @client.get_video_ids(query)
|
47
|
+
video_id.should == nil
|
48
|
+
end
|
36
49
|
|
37
50
|
it "should add a video to a client's playlist" do
|
38
51
|
video_id = "bccKotFwzoY"
|
39
52
|
post_response = @client.add_video_to_playlist(video_id, @playlist_id)
|
53
|
+
post_response.code.should == "201"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should add multiple videos (less than 50) to a client's playlist" do
|
57
|
+
video_ids = []
|
58
|
+
5.times do
|
59
|
+
video_ids << "bccKotFwzoY"
|
60
|
+
end
|
61
|
+
|
62
|
+
post_response = @client.add_videos_to_playlist(video_ids, @playlist_id)
|
63
|
+
post_response.should == "201"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should return an array of videos that could not be added to the client's playlist" do
|
67
|
+
video_ids = %w{ bccKotFwzoY trash trash bccKotFwzoY trash }
|
68
|
+
|
69
|
+
post_response = @client.add_videos_to_playlist(video_ids, @playlist_id)
|
70
|
+
array = post_response.map{|entry| entry.split(",")[1] }
|
71
|
+
array.should == %w{ trash trash trash }
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should add multiple videos (more than 50) to a playlist" do
|
75
|
+
video_ids = []
|
76
|
+
100.times do
|
77
|
+
video_ids << "bccKotFwzoY"
|
78
|
+
end
|
79
|
+
|
80
|
+
post_response = @client.add_videos_to_playlist(video_ids, @playlist_id)
|
40
81
|
post_response.should == "201"
|
41
82
|
end
|
42
83
|
|
@@ -55,7 +96,7 @@ describe "YtDataApi::YtDataApiClient" do
|
|
55
96
|
end
|
56
97
|
|
57
98
|
after(:each) do
|
58
|
-
playlist = @client.
|
99
|
+
playlist = @client.get_playlist_id("test_one")
|
59
100
|
@client.delete_playlist(@playlist_id) unless playlist.nil?
|
60
101
|
end
|
61
102
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yt_data_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-11-15 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: libxml-ruby
|
16
|
-
requirement: &
|
16
|
+
requirement: &70157707836100 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.1.3
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70157707836100
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &70157707835600 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: 2.4.0
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70157707835600
|
36
36
|
description: ! "Create a new instance of YtDataApi::YtDataApiClient passing \n user
|
37
37
|
credentials (username, password) and YouTube developer key\n to
|
38
38
|
access YouTube Data API using ClientLogin authentication."
|