netflix 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Rakefile +25 -3
- data/lib/netflix.rb +3 -1
- data/lib/netflix/client.rb +4 -0
- data/lib/netflix/errors.rb +44 -0
- data/lib/netflix/queue.rb +47 -16
- data/lib/netflix/response.rb +29 -0
- data/lib/netflix/user.rb +1 -5
- data/test/error_test.rb +27 -0
- data/test/http_fixtures/netflix_queue_responses.yml +226 -2
- data/test/integration/.gitignore +1 -0
- data/test/integration/queue_test.rb +72 -0
- data/test/integration/rake_test_helper.rb +42 -0
- data/test/queue_test.rb +36 -19
- metadata +24 -13
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg/
|
data/Rakefile
CHANGED
@@ -1,17 +1,39 @@
|
|
1
1
|
require 'rake/testtask'
|
2
2
|
require 'rubygems/package_task'
|
3
3
|
|
4
|
-
Rake::TestTask.new("test") { |t|
|
4
|
+
Rake::TestTask.new("test:unit") { |t|
|
5
5
|
t.libs << 'test'
|
6
|
-
t.test_files = Dir.glob( "test
|
6
|
+
t.test_files = Dir.glob( "test/*_test.rb" ).sort
|
7
7
|
|
8
8
|
t.verbose = true
|
9
9
|
t.warning = true
|
10
10
|
}
|
11
|
+
require File.join(File.dirname(__FILE__), 'test/integration/rake_test_helper')
|
12
|
+
|
13
|
+
file "test/integration/oauth_settings.yml" do |t|
|
14
|
+
credentials = IntegrationTestHelper.obtain_credentials
|
15
|
+
open("test/integration/oauth_settings.yml", 'wb') do |f|
|
16
|
+
YAML.dump(credentials, f)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Rake::TestTask.new("test:integration") { |t|
|
21
|
+
#t.description = "Run integration tests against a REAL netflix account you supply"
|
22
|
+
t.libs << 'test'
|
23
|
+
t.test_files = Dir.glob( "test/integration/**/*_test.rb" ).sort
|
24
|
+
|
25
|
+
t.verbose = true
|
26
|
+
t.warning = true
|
27
|
+
}
|
28
|
+
|
29
|
+
task "test:integration" => "test/integration/oauth_settings.yml"
|
30
|
+
|
31
|
+
desc "run unit tests only"
|
32
|
+
task :test => "test:unit"
|
11
33
|
|
12
34
|
gem_spec = Gem::Specification.new do |s|
|
13
35
|
s.name = "netflix"
|
14
|
-
s.version = "0.
|
36
|
+
s.version = "0.2.0"
|
15
37
|
s.authors = ["Dean Holdren"]
|
16
38
|
s.date = %q{2012-01-09}
|
17
39
|
s.description = "Ruby Netflix API wrapper"
|
data/lib/netflix.rb
CHANGED
data/lib/netflix/client.rb
CHANGED
@@ -16,6 +16,8 @@ module Netflix
|
|
16
16
|
:authorize_url => "https://api-user.netflix.com/oauth/login")
|
17
17
|
if user_access_token && user_access_secret
|
18
18
|
@oauth_access_token = oauth_access_token(user_access_token, user_access_secret)
|
19
|
+
#automatically determine if error should be thrown based on response codes
|
20
|
+
@oauth_access_token.extend(ResponseErrorDecorator)
|
19
21
|
elsif !!user_access_token ^ !!user_access_secret
|
20
22
|
raise ArgumentError 'Must specify both user_access_token and user_access_secret if specifying either'
|
21
23
|
end
|
@@ -36,6 +38,8 @@ module Netflix
|
|
36
38
|
authorize_url = request_token.authorize_url(:oauth_consumer_key =>
|
37
39
|
Netflix::Client.consumer_key)
|
38
40
|
Launchy.open(authorize_url)
|
41
|
+
puts "Go to browser, a page has been opened to establish oauth"
|
42
|
+
printf "Pin from Netflix:"
|
39
43
|
pin = gets.chomp
|
40
44
|
access_token = request_token.get_access_token(:oauth_verifier => pin)
|
41
45
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Netflix
|
4
|
+
module Error
|
5
|
+
class ResponseError < StandardError
|
6
|
+
def initialize(body, headers)
|
7
|
+
@body = body
|
8
|
+
@headers = headers
|
9
|
+
body_obj = JSON.parse(body)
|
10
|
+
message = body_obj["status"]["message"]
|
11
|
+
super(message)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
#4xx level errors
|
15
|
+
class ClientError < ResponseError
|
16
|
+
end
|
17
|
+
#5xx level errors
|
18
|
+
class ServerError < ResponseError
|
19
|
+
end
|
20
|
+
#400
|
21
|
+
class BadRequest < ClientError
|
22
|
+
end
|
23
|
+
#403
|
24
|
+
class Forbidden < ClientError
|
25
|
+
end
|
26
|
+
#404
|
27
|
+
class NotFound < ClientError
|
28
|
+
end
|
29
|
+
#401
|
30
|
+
class Unauthorized < ClientError
|
31
|
+
end
|
32
|
+
#420 (?)
|
33
|
+
class RateLimit < ClientError
|
34
|
+
end
|
35
|
+
|
36
|
+
CODEMAP = {400 => BadRequest, 403 => Forbidden, 404 => NotFound, 401 => Unauthorized, 420 => RateLimit}
|
37
|
+
def self.for(response)
|
38
|
+
#codemap = {400 => BadRequest, 403 => Forbidden, 404 => NotFound, 401 => Unauthorized, 420 => RateLimit}
|
39
|
+
code = response.code.to_i
|
40
|
+
(CODEMAP[code] || ResponseError).new(response.body, response.header)
|
41
|
+
#codemap[code].new(response.body, response.header)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/netflix/queue.rb
CHANGED
@@ -22,20 +22,29 @@ module Netflix
|
|
22
22
|
|
23
23
|
def add(title_ref, position=nil)
|
24
24
|
response = @oauth_access_token.post "/users/#{@user_id}/queues/#{@type}?output=json", {:etag => etag, :title_ref => title_ref, :position=> position}
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
#@map = retrieve
|
26
|
+
#netflix is wacky. GET after an add can be STALE. ughg
|
27
|
+
#so recreate the contents programattically instead
|
28
|
+
response_obj = JSON.parse(response.body)
|
29
|
+
new_queue_item = response_obj["status"]["resources_created"]["queue_item"]
|
30
|
+
new_etag = response_obj["status"]["etag"]
|
31
|
+
repopulate(new_queue_item, new_etag)
|
32
|
+
self
|
30
33
|
end
|
31
34
|
|
32
35
|
def remove(position)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
id = discs[position-1].id
|
37
|
+
#response = @oauth_access_token.delete "/users/#{@user_id}/queues/#{@type}/available/#{position}?output=json" , {'etag' => etag}
|
38
|
+
response = @oauth_access_token.delete "#{id}?output=json"
|
39
|
+
@map = retrieve
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def remove_by_title_ref(title_ref)
|
44
|
+
disc = discs.find {|disc| disc =~ /\/#{title_ref}\//}
|
45
|
+
response = @oauth_access_token.delete "#{disc.id}?output=json"
|
46
|
+
@map = retrieve
|
47
|
+
self
|
39
48
|
end
|
40
49
|
|
41
50
|
def discs
|
@@ -47,13 +56,35 @@ module Netflix
|
|
47
56
|
end
|
48
57
|
end
|
49
58
|
|
59
|
+
def refresh
|
60
|
+
@map = retrieve(etag)
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
50
64
|
private
|
51
|
-
def retrieve
|
52
|
-
|
53
|
-
if
|
54
|
-
|
65
|
+
def retrieve(etag = nil)
|
66
|
+
url = "/users/#{@user_id}/queues/#{@type}/available?max_results=#{MAX_RESULTS}&output=json"
|
67
|
+
if (etag)
|
68
|
+
response = @oauth_access_token.get(url, { 'etag' => etag.to_s })
|
69
|
+
else
|
70
|
+
response = @oauth_access_token.get(url)
|
71
|
+
end
|
72
|
+
JSON.parse(response.body)["queue"]
|
73
|
+
end
|
74
|
+
|
75
|
+
def repopulate(new_queue_item, new_etag)
|
76
|
+
@map["etag"] = new_etag
|
77
|
+
new_queue_item_index = new_queue_item["position"].to_i
|
78
|
+
if @map["queue_item"] #single or array
|
79
|
+
@map["queue_item"] = [@map["queue_item"]].flatten
|
80
|
+
@map["queue_item"].insert((new_queue_item_index - 1), new_queue_item)
|
81
|
+
@map["queue_item"][new_queue_item_index..-1].each {|queue_item|
|
82
|
+
new_position = (queue_item["position"].to_i + 1).to_s
|
83
|
+
queue_item["position"] = new_position
|
84
|
+
queue_item["id"] = queue_item["id"].gsub(/\/(\d+)\/(\d+)/,"/#{new_position}/\\2")
|
85
|
+
}
|
55
86
|
else
|
56
|
-
|
87
|
+
@map["queue_item"] = [new_queue_item]
|
57
88
|
end
|
58
89
|
end
|
59
90
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Netflix
|
2
|
+
module ResponseErrorDecorator
|
3
|
+
def get(*args)
|
4
|
+
response = super(*args)
|
5
|
+
response_or_raise_error(response)
|
6
|
+
end
|
7
|
+
def delete(*args)
|
8
|
+
response = super(*args)
|
9
|
+
response_or_raise_error(response)
|
10
|
+
end
|
11
|
+
def post(*args)
|
12
|
+
response = super(*args)
|
13
|
+
response_or_raise_error(response)
|
14
|
+
end
|
15
|
+
def put(*args)
|
16
|
+
response = super(*args)
|
17
|
+
response_or_raise_error(response)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def response_or_raise_error(response)
|
22
|
+
if response && response.is_a?(Net::HTTPSuccess)
|
23
|
+
response
|
24
|
+
else
|
25
|
+
raise Error.for(response)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/netflix/user.rb
CHANGED
@@ -17,11 +17,7 @@ module Netflix
|
|
17
17
|
private
|
18
18
|
def retrieve
|
19
19
|
response = @oauth_access_token.get "/users/#{@user_id}?output=json"
|
20
|
-
|
21
|
-
JSON.parse(response.body)["user"]
|
22
|
-
else
|
23
|
-
raise "Error retrieving user #{@user_id}"
|
24
|
-
end
|
20
|
+
JSON.parse(response.body)["user"]
|
25
21
|
end
|
26
22
|
|
27
23
|
end
|
data/test/error_test.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ErrorTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
stub_netflix_for_user('nuid_one')
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_handle_404_on_delete
|
9
|
+
#add to disc queue
|
10
|
+
FakeWeb.register_uri(:delete, %r|http://api\.netflix\.com/users/nuid_one/queues/disc/available|,
|
11
|
+
:body => '{"status": {
|
12
|
+
"message": "Title is not in Queue",
|
13
|
+
"status_code": 404,
|
14
|
+
"sub_code": 610
|
15
|
+
}}',
|
16
|
+
:status => ['404', 'Not Found'])
|
17
|
+
|
18
|
+
user = Netflix::Client.new('nuid_access_key', 'nuid_access_secret').user('nuid_one')
|
19
|
+
available_disc_queue = user.available_disc_queue
|
20
|
+
assert available_disc_queue
|
21
|
+
assert_raises(Netflix::Error::NotFound) do
|
22
|
+
available_disc_queue.remove(2)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -324,7 +324,129 @@ nuid_one:
|
|
324
324
|
]
|
325
325
|
}}
|
326
326
|
post:
|
327
|
-
body:
|
327
|
+
body: |
|
328
|
+
{"status": {
|
329
|
+
"resources_created": {"queue_item": {
|
330
|
+
"average_rating": "3.7",
|
331
|
+
"box_art": {
|
332
|
+
"large": "http://cdn-3.nflximg.com/us/boxshots/large/70071613.jpg",
|
333
|
+
"small": "http://cdn-3.nflximg.com/us/boxshots/tiny/70071613.jpg",
|
334
|
+
"medium": "http://cdn-3.nflximg.com/us/boxshots/small/70071613.jpg"
|
335
|
+
},
|
336
|
+
"category": [
|
337
|
+
{
|
338
|
+
"term": "available now",
|
339
|
+
"content": "Available Now",
|
340
|
+
"scheme": "http://api.netflix.com/categories/queue_availability",
|
341
|
+
"label": "available now"
|
342
|
+
},
|
343
|
+
{
|
344
|
+
"term": "Blu-ray",
|
345
|
+
"scheme": "http://api.netflix.com/categories/title_formats",
|
346
|
+
"label": "Blu-ray"
|
347
|
+
},
|
348
|
+
{
|
349
|
+
"term": "R",
|
350
|
+
"scheme": "http://api.netflix.com/categories/mpaa_ratings",
|
351
|
+
"label": "R"
|
352
|
+
},
|
353
|
+
{
|
354
|
+
"term": "Thrillers",
|
355
|
+
"scheme": "http://api.netflix.com/categories/genres",
|
356
|
+
"label": "Thrillers"
|
357
|
+
},
|
358
|
+
{
|
359
|
+
"term": "Crime Thrillers",
|
360
|
+
"scheme": "http://api.netflix.com/categories/genres",
|
361
|
+
"label": "Crime Thrillers"
|
362
|
+
},
|
363
|
+
{
|
364
|
+
"term": "Suspense",
|
365
|
+
"scheme": "http://api.netflix.com/categories/genres",
|
366
|
+
"label": "Suspense"
|
367
|
+
},
|
368
|
+
{
|
369
|
+
"term": "Dramas Based on Contemporary Literature",
|
370
|
+
"scheme": "http://api.netflix.com/categories/genres",
|
371
|
+
"label": "Dramas Based on Contemporary Literature"
|
372
|
+
},
|
373
|
+
{
|
374
|
+
"term": "Dramas Based on the Book",
|
375
|
+
"scheme": "http://api.netflix.com/categories/genres",
|
376
|
+
"label": "Dramas Based on the Book"
|
377
|
+
}
|
378
|
+
],
|
379
|
+
"updated": "1276960028",
|
380
|
+
"id": "http://api.netflix.com/users/nuid_one/queues/disc/available/4/70071613",
|
381
|
+
"link": [
|
382
|
+
{
|
383
|
+
"href": "http://api.netflix.com/users/nuid_one/queues/disc/available",
|
384
|
+
"rel": "http://schemas.netflix.com/queues.available",
|
385
|
+
"title": "available queue"
|
386
|
+
},
|
387
|
+
{
|
388
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70071613",
|
389
|
+
"rel": "http://schemas.netflix.com/catalog/title",
|
390
|
+
"title": "No Country for Old Men"
|
391
|
+
},
|
392
|
+
{
|
393
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70071613/synopsis",
|
394
|
+
"rel": "http://schemas.netflix.com/catalog/titles/synopsis",
|
395
|
+
"title": "synopsis"
|
396
|
+
},
|
397
|
+
{
|
398
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70071613/cast",
|
399
|
+
"rel": "http://schemas.netflix.com/catalog/people.cast",
|
400
|
+
"title": "cast"
|
401
|
+
},
|
402
|
+
{
|
403
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70071613/directors",
|
404
|
+
"rel": "http://schemas.netflix.com/catalog/people.directors",
|
405
|
+
"title": "directors"
|
406
|
+
},
|
407
|
+
{
|
408
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70071613/format_availability",
|
409
|
+
"rel": "http://schemas.netflix.com/catalog/titles/format_availability",
|
410
|
+
"title": "formats"
|
411
|
+
},
|
412
|
+
{
|
413
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70071613/awards",
|
414
|
+
"rel": "http://schemas.netflix.com/catalog/titles/awards",
|
415
|
+
"title": "awards"
|
416
|
+
},
|
417
|
+
{
|
418
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70071613/screen_formats",
|
419
|
+
"rel": "http://schemas.netflix.com/catalog/titles/screen_formats",
|
420
|
+
"title": "screen formats"
|
421
|
+
},
|
422
|
+
{
|
423
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70071613/languages_and_audio",
|
424
|
+
"rel": "http://schemas.netflix.com/catalog/titles/languages_and_audio",
|
425
|
+
"title": "languages and audio"
|
426
|
+
},
|
427
|
+
{
|
428
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70071613/similars",
|
429
|
+
"rel": "http://schemas.netflix.com/catalog/titles.similars",
|
430
|
+
"title": "similars"
|
431
|
+
},
|
432
|
+
{
|
433
|
+
"href": "http://www.netflix.com/Movie/No_Country_for_Old_Men/70071613",
|
434
|
+
"rel": "alternate",
|
435
|
+
"title": "web page"
|
436
|
+
}
|
437
|
+
],
|
438
|
+
"position": "4",
|
439
|
+
"runtime": "7320",
|
440
|
+
"title": {
|
441
|
+
"regular": "No Country for Old Men",
|
442
|
+
"short": "No Country for Old Men"
|
443
|
+
},
|
444
|
+
"release_year": "2007"
|
445
|
+
}},
|
446
|
+
"status_code": "201",
|
447
|
+
"message": "Move successful",
|
448
|
+
"etag": "82198468425"
|
449
|
+
}}
|
328
450
|
delete:
|
329
451
|
body: |
|
330
452
|
{"status": {
|
@@ -1192,6 +1314,108 @@ empty_queue:
|
|
1192
1314
|
"number_of_results": "0"
|
1193
1315
|
}}
|
1194
1316
|
post:
|
1195
|
-
body:
|
1317
|
+
body: |
|
1318
|
+
{"status": {
|
1319
|
+
"resources_created": {"queue_item": {
|
1320
|
+
"average_rating": "3.4",
|
1321
|
+
"box_art": {
|
1322
|
+
"large": "http://cdn-2.nflximg.com/us/boxshots/large/70167072.jpg",
|
1323
|
+
"small": "http://cdn-2.nflximg.com/us/boxshots/tiny/70167072.jpg",
|
1324
|
+
"medium": "http://cdn-2.nflximg.com/us/boxshots/small/70167072.jpg"
|
1325
|
+
},
|
1326
|
+
"category": [
|
1327
|
+
{
|
1328
|
+
"term": "available now",
|
1329
|
+
"content": "Available Now",
|
1330
|
+
"scheme": "http://api.netflix.com/categories/queue_availability",
|
1331
|
+
"label": "available now"
|
1332
|
+
},
|
1333
|
+
{
|
1334
|
+
"term": "Blu-ray",
|
1335
|
+
"scheme": "http://api.netflix.com/categories/title_formats",
|
1336
|
+
"label": "Blu-ray"
|
1337
|
+
},
|
1338
|
+
{
|
1339
|
+
"term": "PG-13",
|
1340
|
+
"scheme": "http://api.netflix.com/categories/mpaa_ratings",
|
1341
|
+
"label": "PG-13"
|
1342
|
+
},
|
1343
|
+
{
|
1344
|
+
"term": "Comedy",
|
1345
|
+
"scheme": "http://api.netflix.com/categories/genres",
|
1346
|
+
"label": "Comedy"
|
1347
|
+
},
|
1348
|
+
{
|
1349
|
+
"term": "Romantic Comedies",
|
1350
|
+
"scheme": "http://api.netflix.com/categories/genres",
|
1351
|
+
"label": "Romantic Comedies"
|
1352
|
+
}
|
1353
|
+
],
|
1354
|
+
"updated": "1323539988",
|
1355
|
+
"id": "http://api.netflix.com/users/empty_queue/queues/disc/available/1/70167072",
|
1356
|
+
"link": [
|
1357
|
+
{
|
1358
|
+
"href": "http://api.netflix.com/users/empty_queue/queues/disc/available",
|
1359
|
+
"rel": "http://schemas.netflix.com/queues.available",
|
1360
|
+
"title": "available queue"
|
1361
|
+
},
|
1362
|
+
{
|
1363
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70167072",
|
1364
|
+
"rel": "http://schemas.netflix.com/catalog/title",
|
1365
|
+
"title": "Arthur"
|
1366
|
+
},
|
1367
|
+
{
|
1368
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70167072/synopsis",
|
1369
|
+
"rel": "http://schemas.netflix.com/catalog/titles/synopsis",
|
1370
|
+
"title": "synopsis"
|
1371
|
+
},
|
1372
|
+
{
|
1373
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70167072/cast",
|
1374
|
+
"rel": "http://schemas.netflix.com/catalog/people.cast",
|
1375
|
+
"title": "cast"
|
1376
|
+
},
|
1377
|
+
{
|
1378
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70167072/directors",
|
1379
|
+
"rel": "http://schemas.netflix.com/catalog/people.directors",
|
1380
|
+
"title": "directors"
|
1381
|
+
},
|
1382
|
+
{
|
1383
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70167072/format_availability",
|
1384
|
+
"rel": "http://schemas.netflix.com/catalog/titles/format_availability",
|
1385
|
+
"title": "formats"
|
1386
|
+
},
|
1387
|
+
{
|
1388
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70167072/screen_formats",
|
1389
|
+
"rel": "http://schemas.netflix.com/catalog/titles/screen_formats",
|
1390
|
+
"title": "screen formats"
|
1391
|
+
},
|
1392
|
+
{
|
1393
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70167072/languages_and_audio",
|
1394
|
+
"rel": "http://schemas.netflix.com/catalog/titles/languages_and_audio",
|
1395
|
+
"title": "languages and audio"
|
1396
|
+
},
|
1397
|
+
{
|
1398
|
+
"href": "http://api.netflix.com/catalog/titles/movies/70167072/similars",
|
1399
|
+
"rel": "http://schemas.netflix.com/catalog/titles.similars",
|
1400
|
+
"title": "similars"
|
1401
|
+
},
|
1402
|
+
{
|
1403
|
+
"href": "http://www.netflix.com/Movie/Arthur/70167072",
|
1404
|
+
"rel": "alternate",
|
1405
|
+
"title": "web page"
|
1406
|
+
}
|
1407
|
+
],
|
1408
|
+
"position": "1",
|
1409
|
+
"runtime": "6600",
|
1410
|
+
"title": {
|
1411
|
+
"regular": "Arthur",
|
1412
|
+
"short": "Arthur"
|
1413
|
+
},
|
1414
|
+
"release_year": "2011"
|
1415
|
+
}},
|
1416
|
+
"status_code": "201",
|
1417
|
+
"message": "Move successful",
|
1418
|
+
"etag": "82198468425"
|
1419
|
+
}}
|
1196
1420
|
delete:
|
1197
1421
|
body:
|
@@ -0,0 +1 @@
|
|
1
|
+
oauth_settings.yml
|
@@ -0,0 +1,72 @@
|
|
1
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "lib"))
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'yaml'
|
5
|
+
require 'netflix'
|
6
|
+
|
7
|
+
class QueueTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@oauth_settings = YAML.load_file(File.join(File.dirname(__FILE__),"oauth_settings.yml"))
|
10
|
+
#puts @oauth_settings
|
11
|
+
Netflix::Client.consumer_key = @oauth_settings[:consumer_key]
|
12
|
+
Netflix::Client.consumer_secret = @oauth_settings[:consumer_secret]
|
13
|
+
@client = Netflix::Client.new(@oauth_settings[:user][:access_token], @oauth_settings[:user][:access_secret])
|
14
|
+
|
15
|
+
#Do direct oauth gem retrieval of queue and deletion of all queue entries to get a clean start
|
16
|
+
oauth_access_token = @client.instance_variable_get(:@oauth_access_token)
|
17
|
+
#user_response = oauth_access_token.get "/users/current?output=json"
|
18
|
+
#puts "current_user: #{JSON.parse(user_response.body)}"
|
19
|
+
queue_response = oauth_access_token.get "/users/#{@oauth_settings[:user][:user_id]}/queues/disc/available?output=json"
|
20
|
+
queue_response_json = queue_response.body
|
21
|
+
queue_response_obj = JSON.parse(queue_response_json)
|
22
|
+
puts "get queue response: #{queue_response_obj}"
|
23
|
+
queue = queue_response_obj["queue"]
|
24
|
+
queue_items = queue && queue["queue_item"] && [queue["queue_item"]].flatten
|
25
|
+
if queue_items
|
26
|
+
queue_item_urls = queue_items.map() {|queue_item| queue_item["id"]}
|
27
|
+
queue_item_urls.reverse.each {|queue_item_url|
|
28
|
+
sleep 0.25 # for netflix api queries per second limit
|
29
|
+
response = oauth_access_token.delete queue_item_url
|
30
|
+
puts "delete response= #{response.body}"
|
31
|
+
}
|
32
|
+
end
|
33
|
+
sleep 0.25 # for netflix api queries per second limit
|
34
|
+
@user = @client.user(@oauth_settings[:user][:user_id])
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_get_available_disc_queue
|
38
|
+
available_disc_queue = @user.available_disc_queue
|
39
|
+
assert available_disc_queue, "Expecting user to have a disc_queue"
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_get_discs_add_and_remove
|
43
|
+
sleep 0.25 # for netflix api queries per second limit
|
44
|
+
queue = @user.available_disc_queue
|
45
|
+
assert queue, "Expecting queue"
|
46
|
+
assert_equal 0, queue.etag, "Initial etag should be 0 when no discs"
|
47
|
+
discs = queue.discs
|
48
|
+
assert discs, "Expecting the queue to respond to #discs"
|
49
|
+
assert_equal 0, discs.size, "Expecting the discs list to have size 0 at start"
|
50
|
+
|
51
|
+
sleep 0.25 # for netflix api queries per second limit
|
52
|
+
queue.add("http://api.netflix.com/catalog/titles/movies/70167072")
|
53
|
+
queue_after_add = @user.available_disc_queue
|
54
|
+
assert_not_equal 0, queue.etag, "Etag should not be 0 after a disc is added"
|
55
|
+
discs = queue_after_add.discs
|
56
|
+
assert discs, "Expecting the queue to respond to #discs"
|
57
|
+
assert_equal 1, discs.size, "Expecting the discs list to have size 1 after add"
|
58
|
+
|
59
|
+
disc_one = discs[0]
|
60
|
+
assert_equal "http://api.netflix.com/users/#{@oauth_settings[:user][:user_id]}/queues/disc/available/1/70167072", disc_one.id
|
61
|
+
assert_equal "Arthur", disc_one.title
|
62
|
+
|
63
|
+
sleep 0.25 # for netflix api queries per second limit
|
64
|
+
queue.remove(1)
|
65
|
+
sleep 0.25 # for netflix api queries per second limit
|
66
|
+
queue_after_remove = @user.available_disc_queue
|
67
|
+
discs = queue_after_remove.discs
|
68
|
+
assert discs, "Expecting the queue to respond to #discs"
|
69
|
+
assert_equal 0, discs.size, "Expecting the discs list to have size 0 after remove"
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'oauth'
|
2
|
+
require 'launchy'
|
3
|
+
|
4
|
+
class IntegrationTestHelper
|
5
|
+
def self.obtain_credentials
|
6
|
+
puts "Enter Consumer Key/Secret info before running integration tests, you should have registered with http://developer.netflix.com"
|
7
|
+
printf "Consumer Key:"
|
8
|
+
consumer_key = STDIN.gets.chomp
|
9
|
+
printf "Consumer Secret:"
|
10
|
+
consumer_secret = STDIN. gets.chomp
|
11
|
+
printf "Do you have an access token/secret? ([Y]/n)"
|
12
|
+
answer = STDIN.gets.chomp
|
13
|
+
if ["N","n","No","no"].include?(answer)
|
14
|
+
puts "Launching netflix oauth page, login to TEST account and allow this application"
|
15
|
+
oauth_consumer = OAuth::Consumer.new(consumer_key, consumer_secret,
|
16
|
+
:site => "http://api.netflix.com",
|
17
|
+
:request_token_url => "http://api.netflix.com/oauth/request_token",
|
18
|
+
:access_token_url => "http://api.netflix.com/oauth/access_token",
|
19
|
+
:authorize_url => "https://api-user.netflix.com/oauth/login")
|
20
|
+
request_token = oauth_consumer.get_request_token
|
21
|
+
authorize_url = request_token.authorize_url(:oauth_consumer_key => consumer_key)
|
22
|
+
Launchy.open(authorize_url)
|
23
|
+
puts "Go to browser, a page has been opened to establish oauth"
|
24
|
+
printf "Pin from Netflix:"
|
25
|
+
pin = STDIN.gets.chomp
|
26
|
+
access_token_response = request_token.get_access_token(:oauth_verifier => pin)
|
27
|
+
access_token = access_token_response.token
|
28
|
+
access_secret = access_token_response.secret
|
29
|
+
user_id = access_token_response.params["user_id"]
|
30
|
+
else
|
31
|
+
printf "Access Token:"
|
32
|
+
access_token = STDIN.gets.chomp
|
33
|
+
printf "Access Secret:"
|
34
|
+
access_secret = STDIN.gets.chomp
|
35
|
+
printf "User id:"
|
36
|
+
user_id = STDIN.gets.chomp
|
37
|
+
end
|
38
|
+
|
39
|
+
{:consumer_key => consumer_key, :consumer_secret => consumer_secret, :user => {:access_token => access_token, :access_secret => access_secret, :user_id => user_id}}
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
data/test/queue_test.rb
CHANGED
@@ -3,6 +3,7 @@ require 'test_helper'
|
|
3
3
|
class QueueTest < Test::Unit::TestCase
|
4
4
|
def setup
|
5
5
|
stub_netflix_for_user('nuid_one')
|
6
|
+
stub_netflix_for_user('nuid_sub1')
|
6
7
|
Netflix::Client.consumer_key = 'foo_consumer_key'
|
7
8
|
Netflix::Client.consumer_secret = 'foo_consumer_secret'
|
8
9
|
end
|
@@ -25,18 +26,48 @@ class QueueTest < Test::Unit::TestCase
|
|
25
26
|
assert_equal "Arthur", disc_one.title
|
26
27
|
end
|
27
28
|
|
28
|
-
def
|
29
|
+
def test_add_item_to_queue_end_the_default
|
29
30
|
user = Netflix::Client.new('nuid_access_key', 'nuid_access_secret').user('nuid_one')
|
30
31
|
available_disc_queue = user.available_disc_queue
|
31
32
|
assert available_disc_queue
|
32
|
-
|
33
|
+
#pre tests
|
34
|
+
assert_equal "http://api.netflix.com/users/nuid_one/queues/disc/available/1/70167072", available_disc_queue.discs[0].id
|
35
|
+
assert_equal "http://api.netflix.com/users/nuid_one/queues/disc/available/2/70142826", available_disc_queue.discs[1].id
|
36
|
+
assert_equal "http://api.netflix.com/users/nuid_one/queues/disc/available/3/70108988", available_disc_queue.discs[2].id
|
37
|
+
assert_equal "115673854498", available_disc_queue.etag
|
38
|
+
#operation and tests
|
39
|
+
new_queue = available_disc_queue.add("http://api.netflix.com/catalog/titles/movies/70071613")
|
40
|
+
assert_equal "http://api.netflix.com/users/nuid_one/queues/disc/available/1/70167072", new_queue.discs[0].id
|
41
|
+
assert_equal "http://api.netflix.com/users/nuid_one/queues/disc/available/2/70142826", new_queue.discs[1].id
|
42
|
+
assert_equal "http://api.netflix.com/users/nuid_one/queues/disc/available/3/70108988", new_queue.discs[2].id
|
43
|
+
assert_equal "http://api.netflix.com/users/nuid_one/queues/disc/available/4/70071613", new_queue.discs[3].id
|
44
|
+
assert_equal "1", new_queue.discs[0].instance_variable_get(:@map)["position"]
|
45
|
+
assert_equal "2", new_queue.discs[1].instance_variable_get(:@map)["position"]
|
46
|
+
assert_equal "3", new_queue.discs[2].instance_variable_get(:@map)["position"]
|
47
|
+
assert_equal "4", new_queue.discs[3].instance_variable_get(:@map)["position"]
|
48
|
+
assert_equal "82198468425", new_queue.etag
|
33
49
|
end
|
34
50
|
|
35
51
|
def test_add_item_to_queue_top
|
36
|
-
user = Netflix::Client.new('nuid_access_key', 'nuid_access_secret').user('
|
52
|
+
user = Netflix::Client.new('nuid_access_key', 'nuid_access_secret').user('nuid_sub1')
|
37
53
|
available_disc_queue = user.available_disc_queue
|
38
54
|
assert available_disc_queue
|
39
|
-
|
55
|
+
#pre tests
|
56
|
+
assert_equal "http://api.netflix.com/users/nuid_sub1/queues/disc/available/1/70071613", available_disc_queue.discs[0].id
|
57
|
+
assert_equal "http://api.netflix.com/users/nuid_sub1/queues/disc/available/2/70117306", available_disc_queue.discs[1].id
|
58
|
+
assert_equal "http://api.netflix.com/users/nuid_sub1/queues/disc/available/3/70105135", available_disc_queue.discs[2].id
|
59
|
+
assert_equal "115673854498", available_disc_queue.etag
|
60
|
+
#operation and tests
|
61
|
+
new_queue = available_disc_queue.add("http://api.netflix.com/catalog/titles/movies/70167072", 1)
|
62
|
+
assert_equal "http://api.netflix.com/users/nuid_sub1/queues/disc/available/1/70167072", new_queue.discs[0].id
|
63
|
+
assert_equal "http://api.netflix.com/users/nuid_sub1/queues/disc/available/2/70071613", new_queue.discs[1].id
|
64
|
+
assert_equal "http://api.netflix.com/users/nuid_sub1/queues/disc/available/3/70117306", new_queue.discs[2].id
|
65
|
+
assert_equal "http://api.netflix.com/users/nuid_sub1/queues/disc/available/4/70105135", new_queue.discs[3].id
|
66
|
+
assert_equal "1", new_queue.discs[0].instance_variable_get(:@map)["position"]
|
67
|
+
assert_equal "2", new_queue.discs[1].instance_variable_get(:@map)["position"]
|
68
|
+
assert_equal "3", new_queue.discs[2].instance_variable_get(:@map)["position"]
|
69
|
+
assert_equal "4", new_queue.discs[3].instance_variable_get(:@map)["position"]
|
70
|
+
assert_equal "82198468425", new_queue.etag
|
40
71
|
end
|
41
72
|
|
42
73
|
def test_remove_item_from_queue_by_index
|
@@ -46,21 +77,6 @@ class QueueTest < Test::Unit::TestCase
|
|
46
77
|
available_disc_queue.remove(2)
|
47
78
|
end
|
48
79
|
|
49
|
-
#def test_add_item_to_stale_queue_fails
|
50
|
-
# user = Netflix::Client.new('nuid_access_key', 'nuid_access_secret').user('nuid_one')
|
51
|
-
# available_disc_queue = user.available_disc_queue
|
52
|
-
# assert available_disc_queue
|
53
|
-
# available_disc_queue.add('70071613')
|
54
|
-
# old_available_disc_queue = available_disc_queue
|
55
|
-
#
|
56
|
-
# available_disc_queue = user.available_disc_queue
|
57
|
-
# available_disc_queue.add('70117306')
|
58
|
-
#
|
59
|
-
# assert_raises() {
|
60
|
-
# old_available_disc_queue.add('70105135')
|
61
|
-
# }
|
62
|
-
#end
|
63
|
-
|
64
80
|
def test_empty_queue
|
65
81
|
stub_netflix_for_user('empty_queue')
|
66
82
|
user = Netflix::Client.new('nuid_access_key', 'nuid_access_secret').user('empty_queue')
|
@@ -68,6 +84,7 @@ class QueueTest < Test::Unit::TestCase
|
|
68
84
|
assert available_disc_queue, "Expected a disc_queue"
|
69
85
|
assert available_disc_queue.discs, "Expected the disc_queue to have a discs attribute"
|
70
86
|
assert_equal 0, available_disc_queue.discs.size, "Expected discs to be empty array #{available_disc_queue.discs[0]}}"
|
87
|
+
new_queue = available_disc_queue.add("http://api.netflix.com/catalog/titles/movies/70167072")
|
71
88
|
end
|
72
89
|
|
73
90
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: netflix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
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: 2012-01-09 00:00:00.
|
12
|
+
date: 2012-01-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: oauth
|
16
|
-
requirement: &
|
16
|
+
requirement: &2155382740 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2155382740
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: json
|
27
|
-
requirement: &
|
27
|
+
requirement: &2155382320 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2155382320
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: launchy
|
38
|
-
requirement: &
|
38
|
+
requirement: &2155381900 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2155381900
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: fakeweb
|
49
|
-
requirement: &
|
49
|
+
requirement: &2155381480 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2155381480
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: yaml
|
60
|
-
requirement: &
|
60
|
+
requirement: &2155381060 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,24 +65,31 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2155381060
|
69
69
|
description: Ruby Netflix API wrapper
|
70
70
|
email: deanholdren@gmail.com
|
71
71
|
executables: []
|
72
72
|
extensions: []
|
73
73
|
extra_rdoc_files: []
|
74
74
|
files:
|
75
|
+
- .gitignore
|
75
76
|
- LICENSE
|
76
77
|
- README.rdoc
|
77
78
|
- Rakefile
|
78
79
|
- lib/netflix.rb
|
79
80
|
- lib/netflix/client.rb
|
80
81
|
- lib/netflix/disc.rb
|
82
|
+
- lib/netflix/errors.rb
|
81
83
|
- lib/netflix/json_resource.rb
|
82
84
|
- lib/netflix/queue.rb
|
85
|
+
- lib/netflix/response.rb
|
83
86
|
- lib/netflix/user.rb
|
87
|
+
- test/error_test.rb
|
84
88
|
- test/http_fixtures/netflix_queue_responses.yml
|
85
89
|
- test/http_fixtures/netflix_user_responses.yml
|
90
|
+
- test/integration/.gitignore
|
91
|
+
- test/integration/queue_test.rb
|
92
|
+
- test/integration/rake_test_helper.rb
|
86
93
|
- test/non_user_client.rb
|
87
94
|
- test/queue_test.rb
|
88
95
|
- test/test_helper.rb
|
@@ -107,13 +114,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
114
|
version: '0'
|
108
115
|
requirements: []
|
109
116
|
rubyforge_project:
|
110
|
-
rubygems_version: 1.8.
|
117
|
+
rubygems_version: 1.8.15
|
111
118
|
signing_key:
|
112
119
|
specification_version: 3
|
113
120
|
summary: Ruby Netflix API wrapper
|
114
121
|
test_files:
|
122
|
+
- test/error_test.rb
|
115
123
|
- test/http_fixtures/netflix_queue_responses.yml
|
116
124
|
- test/http_fixtures/netflix_user_responses.yml
|
125
|
+
- test/integration/.gitignore
|
126
|
+
- test/integration/queue_test.rb
|
127
|
+
- test/integration/rake_test_helper.rb
|
117
128
|
- test/non_user_client.rb
|
118
129
|
- test/queue_test.rb
|
119
130
|
- test/test_helper.rb
|