hulu-show 0.1.0 → 0.2.0
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/README.md +51 -0
- data/VERSION +1 -1
- data/hulu-show.gemspec +10 -5
- data/lib/hulu/show.rb +40 -9
- data/lib/hulu/show/base.rb +8 -0
- data/lib/hulu/show/episode.rb +26 -7
- data/notes.txt +25 -0
- data/spec/hulu/base_spec.rb +13 -0
- data/spec/hulu/episode_spec.rb +18 -0
- data/spec/hulu/show_spec.rb +75 -19
- data/spec/spec_helper.rb +2 -1
- data/spec/support/vcr_cassettes/additional_attributes.yml +33 -0
- data/spec/support/vcr_cassettes/burn_notice.yml +5 -7
- data/spec/support/vcr_cassettes/non_existent_show.yml +791 -0
- metadata +28 -23
- data/README.rdoc +0 -20
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# hulu-show
|
2
|
+
|
3
|
+
Hulu::Show fetches all episodes for the current season of a specified show.
|
4
|
+
|
5
|
+
## Show attributes:
|
6
|
+
|
7
|
+
:network,
|
8
|
+
:title,
|
9
|
+
:genre,
|
10
|
+
:description,
|
11
|
+
:errors,
|
12
|
+
:episodes,
|
13
|
+
:url
|
14
|
+
|
15
|
+
## Episode attributes:
|
16
|
+
|
17
|
+
:title,
|
18
|
+
:episode,
|
19
|
+
:running_time,
|
20
|
+
:air_date,
|
21
|
+
:season,
|
22
|
+
:url,
|
23
|
+
:beaconid,
|
24
|
+
:thumbnail_url,
|
25
|
+
:embed_html
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
`gem install hulu-show`
|
30
|
+
|
31
|
+
`require 'hulu/show'`
|
32
|
+
|
33
|
+
`burn_notice = Hulu::Show.new('Burn Notice')`
|
34
|
+
|
35
|
+
#<Hulu::Show:0x007f972a04f740 @title="Burn Notice", @episodes=[#<Hulu::Episode:0x007f972a02c7b8 @episode="13", @title="Damned If You Do", @url="http://www.hulu.com/watch/296648/burn-notice-damned-if-you-do?c=Action-and-Adventure#x-4,cEpisodes,1,0", @beaconid="296648", @running_time="43:09", @air_date="11/03/2011", @embed_html="<object width=\"512\" height=\"296\"><param name=\"movie\" value=\"http://www.hulu.com/embed/c96sZQru3w567PP7t3cGZQ\"></param><param name=\"flashvars\" value=\"ap=1\"></param><embed src=\"http://www.hulu.com/embed/c96sZQru3w567PP7t3cGZQ\" type=\"application/x-shockwave-flash\" width=\"512\" height=\"296\" flashvars=\"ap=1\"></embed></object>", @thumbnail_url="http://thumbnails.hulu.com/8/60000008/60000008_145x80_generated.jpg">], @doc=nil, @errors=[], @network="USA", @genre="Action and Adventure", @description="A \"burned\" spy returns to Miami where he uses his special ops training to help those in need, and bring justice against the men who wrongly burned him.", @url="http://www.hulu.com/burn-notice">
|
36
|
+
|
37
|
+
## Retrieve show episodes
|
38
|
+
|
39
|
+
`burn_notice.episodes`
|
40
|
+
|
41
|
+
[#<Hulu::Episode:0x007f961a02be00 @episode="13", @title="Damned If You Do", @url="http://www.hulu.com/watch/296648/burn-notice-damned-if-you-do?c=Action-and-Adventure#x-4,cEpisodes,1,0", @beaconid="296648", @running_time="43:09", @air_date="11/03/2011", @embed_html="<object width=\"512\" height=\"296\"><param name=\"movie\" value=\"http://www.hulu.com/embed/c96sZQru3w567PP7t3cGZQ\"></param><param name=\"flashvars\" value=\"ap=1\"></param><embed src=\"http://www.hulu.com/embed/c96sZQru3w567PP7t3cGZQ\" type=\"application/x-shockwave-flash\" width=\"512\" height=\"296\" flashvars=\"ap=1\"></embed></object>", @thumbnail_url="http://thumbnails.hulu.com/8/60000008/60000008_145x80_generated.jpg">]
|
42
|
+
|
43
|
+
|
44
|
+
## Retrieve multiple shows with their episodes at one time.
|
45
|
+
|
46
|
+
`Hulu.shows(['Burn Notice', 'Warehouse 13'])`
|
47
|
+
|
48
|
+
|
49
|
+
Copyright (c) 2011 Craig Williams. See LICENSE.txt for
|
50
|
+
further details.
|
51
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/hulu-show.gemspec
CHANGED
@@ -5,16 +5,16 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "hulu-show"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Craig Williams"]
|
12
|
-
s.date = "2011-11-
|
12
|
+
s.date = "2011-11-27"
|
13
13
|
s.description = "Really, that is about it. For each show, Hulu::Show will return an array of Episode objects with details about the episode."
|
14
14
|
s.email = "cwilliams.allancraig@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE.txt",
|
17
|
-
"README.
|
17
|
+
"README.md"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".document",
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
"Gemfile",
|
24
24
|
"Gemfile.lock",
|
25
25
|
"LICENSE.txt",
|
26
|
-
"README.
|
26
|
+
"README.md",
|
27
27
|
"Rakefile",
|
28
28
|
"VERSION",
|
29
29
|
"hulu-show.gemspec",
|
@@ -31,9 +31,14 @@ Gem::Specification.new do |s|
|
|
31
31
|
"lib/hulu/show.rb",
|
32
32
|
"lib/hulu/show/base.rb",
|
33
33
|
"lib/hulu/show/episode.rb",
|
34
|
+
"notes.txt",
|
35
|
+
"spec/hulu/base_spec.rb",
|
36
|
+
"spec/hulu/episode_spec.rb",
|
34
37
|
"spec/hulu/show_spec.rb",
|
35
38
|
"spec/spec_helper.rb",
|
36
|
-
"spec/support/vcr_cassettes/
|
39
|
+
"spec/support/vcr_cassettes/additional_attributes.yml",
|
40
|
+
"spec/support/vcr_cassettes/burn_notice.yml",
|
41
|
+
"spec/support/vcr_cassettes/non_existent_show.yml"
|
37
42
|
]
|
38
43
|
s.homepage = "http://github.com/CraigWilliams/hulu-show"
|
39
44
|
s.licenses = ["BSD"]
|
data/lib/hulu/show.rb
CHANGED
@@ -1,21 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'hulu/show/base'
|
2
4
|
require 'hulu/show/episode'
|
3
5
|
|
4
6
|
class Hulu::Show < Hulu::Base
|
5
|
-
attr_accessor :
|
7
|
+
attr_accessor :network,
|
8
|
+
:title,
|
9
|
+
:genre,
|
10
|
+
:description,
|
11
|
+
:errors,
|
12
|
+
:episodes,
|
13
|
+
:url
|
6
14
|
|
7
|
-
def initialize(
|
8
|
-
@
|
15
|
+
def initialize(title)
|
16
|
+
@title = title
|
9
17
|
@episodes = []
|
18
|
+
@doc = Hulu.query(@title)
|
19
|
+
@errors = []
|
20
|
+
|
21
|
+
if error_404
|
22
|
+
@errors << "404: Show not found"
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
parse_show_details
|
27
|
+
parse_episodes
|
28
|
+
set_url
|
29
|
+
|
30
|
+
@doc = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_url
|
34
|
+
@url = "#{Hulu::BASE_URI}/#{Hulu::Base.prepare_name(@title)}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def error_404
|
38
|
+
error = @doc.css('.fixed-lg .section .gr').text.strip
|
39
|
+
error =~ /404/ ? true : false
|
10
40
|
end
|
11
41
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
42
|
+
def parse_show_details
|
43
|
+
details = @doc.css(".fixed-lg.container .section.details .relative .info")
|
44
|
+
@network = details[0].text.strip
|
45
|
+
@genre = details[2].text.split('|').first.gsub(/\302\240/, ' ').strip
|
46
|
+
@description = details[3].text.strip
|
15
47
|
end
|
16
48
|
|
17
|
-
def parse_episodes
|
18
|
-
episodes = doc.css("#show-expander table")
|
49
|
+
def parse_episodes
|
50
|
+
episodes = @doc.css("#show-expander table")
|
19
51
|
|
20
52
|
episodes.each_with_index do |episode, i|
|
21
53
|
# There are several tables under the show-expander
|
@@ -27,7 +59,6 @@ class Hulu::Show < Hulu::Base
|
|
27
59
|
end
|
28
60
|
end
|
29
61
|
end
|
30
|
-
@episodes
|
31
62
|
end
|
32
63
|
|
33
64
|
end
|
data/lib/hulu/show/base.rb
CHANGED
@@ -29,4 +29,12 @@ module Hulu
|
|
29
29
|
show_name = Hulu::Base.prepare_name(show_name)
|
30
30
|
Hulu::Fetcher::Page.get("#{BASE_URI}/#{show_name}")
|
31
31
|
end
|
32
|
+
|
33
|
+
def self.shows(titles)
|
34
|
+
shows = []
|
35
|
+
titles.each do |title|
|
36
|
+
shows << Hulu::Show.new(title)
|
37
|
+
end
|
38
|
+
shows
|
39
|
+
end
|
32
40
|
end
|
data/lib/hulu/show/episode.rb
CHANGED
@@ -3,15 +3,29 @@ class Hulu::Episode < Hulu::Base
|
|
3
3
|
:episode,
|
4
4
|
:running_time,
|
5
5
|
:air_date,
|
6
|
-
:season
|
7
|
-
|
6
|
+
:season,
|
7
|
+
:url,
|
8
|
+
:beaconid,
|
9
|
+
:thumbnail_url,
|
10
|
+
:embed_html
|
11
|
+
|
8
12
|
def initialize
|
9
13
|
yield self if block_given?
|
14
|
+
|
15
|
+
set_additional_attributes
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_additional_attributes
|
19
|
+
info = additional_attributes
|
20
|
+
@embed_html = info['html']
|
21
|
+
@thumbnail_url = info['thumbnail_url']
|
10
22
|
end
|
11
23
|
|
12
24
|
def process(episode)
|
13
|
-
@episode
|
14
|
-
@title
|
25
|
+
@episode = episode.css('td.c0').text.strip rescue ''
|
26
|
+
@title = episode.css('td.c1 a').text.strip rescue ''
|
27
|
+
@url = episode.css('td.c1 a').attr('href').text.strip rescue ''
|
28
|
+
@beaconid = episode.css('td.c1 a').attr('beaconid').text.strip rescue ''
|
15
29
|
parse_running_time(episode)
|
16
30
|
end
|
17
31
|
|
@@ -20,11 +34,16 @@ class Hulu::Episode < Hulu::Base
|
|
20
34
|
|
21
35
|
if run_time.include?(':')
|
22
36
|
@running_time = run_time
|
23
|
-
@air_date = episode.css('td.c4').text.strip
|
37
|
+
@air_date = episode.css('td.c4').text.strip rescue ''
|
24
38
|
else
|
25
|
-
@running_time = episode.css('td.c4').text.strip
|
26
|
-
@air_date = episode.css('td.c5').text.strip
|
39
|
+
@running_time = episode.css('td.c4').text.strip rescue ''
|
40
|
+
@air_date = episode.css('td.c5').text.strip rescue ''
|
27
41
|
end
|
28
42
|
end
|
29
43
|
|
44
|
+
def additional_attributes
|
45
|
+
url = "http://www.hulu.com/api/oembed.json?url=http://www.hulu.com/watch/#{@beaconid}/#{Hulu::Base.prepare_name(@title)}"
|
46
|
+
Hulu::Fetcher::Page.get(url).parsed_response
|
47
|
+
end
|
48
|
+
|
30
49
|
end
|
data/notes.txt
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#==============================================================
|
2
|
+
# Fetching more data about a show
|
3
|
+
#==============================================================
|
4
|
+
# http://www.hulu.com/api/oembed.json?url=http://www.hulu.com/watch/20807/late-night-with-conan-obrien-wed-may-21-2008
|
5
|
+
# http://www.hulu.com/api/oembed.json?url=http://www.hulu.com/watch/261293/burn-notice-mind-games
|
6
|
+
|
7
|
+
{
|
8
|
+
"thumbnail_width": 145,
|
9
|
+
"type": "video",
|
10
|
+
"title": "Shadows (Warehouse 13)",
|
11
|
+
"embed_url": "http://www.hulu.com/embed/Gp_eWf7PQr697Ol0j7OfEg",
|
12
|
+
"thumbnail_height": 80,
|
13
|
+
"height": 296,
|
14
|
+
"provider_name": "Hulu",
|
15
|
+
"width": 512,
|
16
|
+
"html": "<object width=\"512\" height=\"296\"><param name=\"movie\" value=\"http://www.hulu.com/embed/Gp_eWf7PQr697Ol0j7OfEg\"></param><param name=\"flashvars\" value=\"ap=1\"></param><embed src=\"http://www.hulu.com/embed/Gp_eWf7PQr697Ol0j7OfEg\" type=\"application/x-shockwave-flash\" width=\"512\" height=\"296\" flashvars=\"ap=1\"></embed></object>",
|
17
|
+
"provider_url": "http://www.hulu.com/",
|
18
|
+
"duration": 2584.25,
|
19
|
+
"version": "1.0",
|
20
|
+
"cache_age": 3600,
|
21
|
+
"air_date": "Mon Sep 12 00:00:00 UTC 2011",
|
22
|
+
"thumbnail_url": "http://thumbnails.hulu.com/188/40038188/40038188_145x80_generated.jpg",
|
23
|
+
"author_name": "Syfy"
|
24
|
+
}
|
25
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hulu do
|
4
|
+
|
5
|
+
it "returns an array of shows" do
|
6
|
+
titles = ['Burn Notice', 'Warehouse 13', 'Terra Nova']
|
7
|
+
shows = Hulu.shows(titles)
|
8
|
+
|
9
|
+
shows.count.should == 3
|
10
|
+
# shows.first.episodes.first.title.should == 'What'
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hulu::Episode do
|
4
|
+
|
5
|
+
before { VCR.insert_cassette('additional_attributes') }
|
6
|
+
after { VCR.eject_cassette }
|
7
|
+
|
8
|
+
it "episode can fetch additional attributes" do
|
9
|
+
episode = Hulu::Episode.new do |episode|
|
10
|
+
episode.beaconid = '296648'
|
11
|
+
episode.title = 'Damned If You Do'
|
12
|
+
episode.additional_attributes
|
13
|
+
end
|
14
|
+
|
15
|
+
episode.thumbnail_url.should == "http://thumbnails.hulu.com/8/60000008/60000008_145x80_generated.jpg"
|
16
|
+
episode.embed_html.should_not be_nil
|
17
|
+
end
|
18
|
+
end
|
data/spec/hulu/show_spec.rb
CHANGED
@@ -1,37 +1,93 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
1
5
|
require 'spec_helper'
|
2
6
|
|
3
7
|
describe Hulu::Show do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
context "When show is found" do
|
10
|
+
let(:burn_notice_erb) {
|
11
|
+
{
|
12
|
+
title: 'Burn baby burn',
|
13
|
+
running_time: '43:09',
|
14
|
+
air_date: '11/03/2011',
|
15
|
+
episode: '13',
|
16
|
+
network: 'USA',
|
17
|
+
genre: '<b><a href=\"http://www.hulu.com/genres/Action-and-Adventure\"
|
18
|
+
class=\"show-title\">Action and Adventure</a> | <a href=\"http://www.hulu.com/genres/Drama\"
|
19
|
+
class=\"show-title\">Drama</a></b>',
|
20
|
+
description: "A "burned" spy returns to Miami where he uses his special ops training to help those in need, and bring justice against the men who wrongly burned him."
|
21
|
+
}
|
10
22
|
}
|
11
|
-
}
|
12
23
|
|
13
|
-
|
14
|
-
|
15
|
-
|
24
|
+
let(:additional_attributes) {
|
25
|
+
{
|
26
|
+
"thumbnail_width" => 145,
|
27
|
+
"type" => "video",
|
28
|
+
"title" => "Shadows (Warehouse 13)",
|
29
|
+
"embed_url" => "http://www.hulu.com/embed/Gp_eWf7PQr697Ol0j7OfEg",
|
30
|
+
"thumbnail_height" => 80,
|
31
|
+
"height" => 296,
|
32
|
+
"provider_name" => "Hulu",
|
33
|
+
"width" => 512,
|
34
|
+
"html" => "<object width=\"512\" height=\"296\"><param name=\"movie\" value=\"http://www.hulu.com/embed/Gp_eWf7PQr697Ol0j7OfEg\"></param><param name=\"flashvars\" value=\"ap=1\"></param><embed src=\"http://www.hulu.com/embed/Gp_eWf7PQr697Ol0j7OfEg\" type=\"application/x-shockwave-flash\" width=\"512\" height=\"296\" flashvars=\"ap=1\"></embed></object>",
|
35
|
+
"provider_url" => "http://www.hulu.com/",
|
36
|
+
"duration" => 2584.25,
|
37
|
+
"version" => "1.0",
|
38
|
+
"cache_age" => 3600,
|
39
|
+
"air_date" => "Mon Sep 12 00:00:00 UTC 2011",
|
40
|
+
"thumbnail_url" => "http://thumbnails.hulu.com/188/40038188/40038188_145x80_generated.jpg",
|
41
|
+
"author_name" => "Syfy"
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
before do
|
46
|
+
Hulu::Episode.any_instance.stub(:additional_attributes).and_return(additional_attributes)
|
47
|
+
VCR.insert_cassette('burn_notice', erb: burn_notice_erb)
|
48
|
+
end
|
49
|
+
|
50
|
+
after { VCR.eject_cassette }
|
51
|
+
|
52
|
+
it "show attributes should be set" do
|
53
|
+
show = Hulu::Show.new('Burn Notice')
|
54
|
+
show.title.should == 'Burn Notice'
|
55
|
+
show.network.should == 'USA'
|
56
|
+
show.genre.should == 'Action and Adventure'
|
57
|
+
show.description.should == "A \"burned\" spy returns to Miami where he uses his special ops training to help those in need, and bring justice against the men who wrongly burned him."
|
58
|
+
show.url == "http://www.hulu.com/burn-notice"
|
59
|
+
end
|
16
60
|
|
17
|
-
|
18
|
-
VCR.use_cassette('burn_notice', erb: burn_notice_erb) do
|
61
|
+
it "episodes return correct attributes" do
|
19
62
|
episodes = Hulu::Show.new('Burn Notice').episodes
|
20
63
|
episode = episodes.first
|
21
64
|
|
22
|
-
episode.title.should
|
65
|
+
episode.title.should == 'Burn baby burn'
|
23
66
|
episode.running_time.should == '43:09'
|
24
|
-
episode.air_date.should
|
25
|
-
episode.episode.should
|
67
|
+
episode.air_date.should == '11/03/2011'
|
68
|
+
episode.episode.should == '13'
|
69
|
+
episode.url == "http://www.hulu.com/watch/296648/burn-notice-damned-if-you-do#x-4,cEpisodes,1,0"
|
70
|
+
episode.beaconid == '296648'
|
71
|
+
|
72
|
+
# additional_attributes
|
73
|
+
episode.thumbnail_url.should == "http://thumbnails.hulu.com/188/40038188/40038188_145x80_generated.jpg"
|
26
74
|
end
|
27
|
-
end
|
28
75
|
|
29
|
-
|
30
|
-
VCR.use_cassette('burn_notice', erb: burn_notice_erb) do
|
76
|
+
it "has the correct number of episodes" do
|
31
77
|
episodes = Hulu::Show.new('Burn Notice').episodes
|
32
|
-
|
33
78
|
episodes.count.should == 1
|
34
79
|
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
context "When show not found" do
|
84
|
+
before { VCR.insert_cassette('non_existent_show') }
|
85
|
+
after { VCR.eject_cassette }
|
86
|
+
|
87
|
+
it "contains an error when show not found" do
|
88
|
+
show = Hulu::Show.new("Non-existent show")
|
89
|
+
show.errors.should include("404: Show not found")
|
90
|
+
end
|
35
91
|
end
|
36
92
|
|
37
93
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -11,8 +11,9 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
|
11
11
|
VCR.config do |c|
|
12
12
|
c.cassette_library_dir = 'spec/support/vcr_cassettes'
|
13
13
|
c.stub_with :fakeweb
|
14
|
+
c.allow_http_connections_when_no_cassette = true
|
14
15
|
end
|
15
16
|
|
16
17
|
RSpec.configure do |config|
|
17
18
|
config.extend VCR::RSpec::Macros
|
18
|
-
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
---
|
2
|
+
- !ruby/struct:VCR::HTTPInteraction
|
3
|
+
request: !ruby/struct:VCR::Request
|
4
|
+
method: :get
|
5
|
+
uri: http://www.hulu.com:80/api/oembed.json?url=http://www.hulu.com/watch/296648/damned-if-you-do
|
6
|
+
body:
|
7
|
+
headers:
|
8
|
+
response: !ruby/struct:VCR::Response
|
9
|
+
status: !ruby/struct:VCR::ResponseStatus
|
10
|
+
code: 200
|
11
|
+
message: OK
|
12
|
+
headers:
|
13
|
+
server:
|
14
|
+
- nginx
|
15
|
+
content-type:
|
16
|
+
- application/json; charset=utf-8
|
17
|
+
status:
|
18
|
+
- 200 OK
|
19
|
+
x-ua-compatible:
|
20
|
+
- IE=EmulateIE9; IE=EmulateIE7
|
21
|
+
content-length:
|
22
|
+
- '803'
|
23
|
+
cache-control:
|
24
|
+
- max-age=3544
|
25
|
+
date:
|
26
|
+
- Sat, 26 Nov 2011 23:08:44 GMT
|
27
|
+
body: ! '{"author_name":"USA","type":"video","thumbnail_width":145,"thumbnail_height":80,"title":"Damned
|
28
|
+
If You Do (Burn Notice)","width":512,"provider_name":"Hulu","embed_url":"http://www.hulu.com/embed/c96sZQru3w567PP7t3cGZQ","version":"1.0","duration":2589.67,"height":296,"provider_url":"http://www.hulu.com/","air_date":"Thu
|
29
|
+
Nov 03 00:00:00 UTC 2011","html":"<object width=\"512\" height=\"296\"><param
|
30
|
+
name=\"movie\" value=\"http://www.hulu.com/embed/c96sZQru3w567PP7t3cGZQ\"></param><param
|
31
|
+
name=\"flashvars\" value=\"ap=1\"></param><embed src=\"http://www.hulu.com/embed/c96sZQru3w567PP7t3cGZQ\"
|
32
|
+
type=\"application/x-shockwave-flash\" width=\"512\" height=\"296\" flashvars=\"ap=1\"></embed></object>","cache_age":3600,"thumbnail_url":"http://thumbnails.hulu.com/8/60000008/60000008_145x80_generated.jpg"}'
|
33
|
+
http_version: '1.1'
|