em-sofa 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.document +5 -0
  2. data/.gitignore +22 -0
  3. data/.yardopts +6 -0
  4. data/LICENSE +20 -0
  5. data/README.md +110 -0
  6. data/Rakefile +75 -0
  7. data/doc/Em-sofa/Mapping.html +168 -0
  8. data/doc/Em-sofa/Mapping/ClassMethods.html +314 -0
  9. data/doc/Em-sofa/Mapping/InstanceMethods.html +358 -0
  10. data/doc/Em-sofa/TVRage.html +85 -0
  11. data/doc/Em-sofa/TVRage/Episode.html +358 -0
  12. data/doc/Em-sofa/TVRage/Schedule.html +207 -0
  13. data/doc/Em-sofa/TVRage/Season.html +236 -0
  14. data/doc/Em-sofa/TVRage/Show.html +904 -0
  15. data/doc/Em-sofa/TVRage/Show/ShowNotFound.html +92 -0
  16. data/doc/Em-sofa/Version.html +100 -0
  17. data/doc/Sofa.html +85 -0
  18. data/doc/_index.html +233 -0
  19. data/doc/class_list.html +36 -0
  20. data/doc/css/common.css +1 -0
  21. data/doc/css/full_list.css +50 -0
  22. data/doc/css/style.css +277 -0
  23. data/doc/file.README.html +150 -0
  24. data/doc/file_list.html +38 -0
  25. data/doc/index.html +150 -0
  26. data/doc/js/app.js +138 -0
  27. data/doc/js/full_list.js +117 -0
  28. data/doc/js/jquery.js +19 -0
  29. data/doc/method_list.html +195 -0
  30. data/doc/top-level-namespace.html +88 -0
  31. data/lib/em-sofa.rb +8 -0
  32. data/lib/em-sofa/mapping.rb +108 -0
  33. data/lib/em-sofa/tvrage.rb +14 -0
  34. data/lib/em-sofa/tvrage/episode.rb +41 -0
  35. data/lib/em-sofa/tvrage/schedule.rb +28 -0
  36. data/lib/em-sofa/tvrage/season.rb +38 -0
  37. data/lib/em-sofa/tvrage/show.rb +193 -0
  38. data/lib/em-sofa/version.rb +10 -0
  39. data/spec/fixtures/tvrage/cases/castle.xml +228 -0
  40. data/spec/fixtures/tvrage/cases/community.xml +109 -0
  41. data/spec/fixtures/tvrage/cases/live_with_regis_and_kelly.xml +56237 -0
  42. data/spec/fixtures/tvrage/episode_list.xml +1183 -0
  43. data/spec/fixtures/tvrage/episode_list_one_season.xml +17 -0
  44. data/spec/fixtures/tvrage/episode_list_two_episodes.xml +25 -0
  45. data/spec/fixtures/tvrage/full_schedule.xml +4731 -0
  46. data/spec/fixtures/tvrage/full_show_info.xml +1291 -0
  47. data/spec/fixtures/tvrage/quickinfo.html +17 -0
  48. data/spec/fixtures/tvrage/quickinfo_missing.html +1 -0
  49. data/spec/fixtures/tvrage/search.xml +151 -0
  50. data/spec/fixtures/tvrage/show_info.xml +42 -0
  51. data/spec/fixtures/tvrage/show_info_blank.xml +3 -0
  52. data/spec/fixtures/tvrage/single_episode.xml +8 -0
  53. data/spec/sofa/mapping_spec.rb +82 -0
  54. data/spec/sofa/tvrage/cases_spec.rb +29 -0
  55. data/spec/sofa/tvrage/episode_spec.rb +45 -0
  56. data/spec/sofa/tvrage/schedule_spec.rb +17 -0
  57. data/spec/sofa/tvrage/season_spec.rb +61 -0
  58. data/spec/sofa/tvrage/show_spec.rb +201 -0
  59. data/spec/sofa/version_spec.rb +11 -0
  60. data/spec/sofa_spec.rb +5 -0
  61. data/spec/spec.opts +1 -0
  62. data/spec/spec_helper.rb +20 -0
  63. metadata +165 -0
@@ -0,0 +1,28 @@
1
+ module EventMachine
2
+ module Sofa
3
+ module TVRage
4
+ # This class will hold the full/quick schedule information as per the TVRage API.
5
+ #
6
+ # @see http://services.tvrage.com/index.php?page=public&go=fullschedule TVRage API : Full Schedule
7
+ # @see http://services.tvrage.com/index.php?page=public&go=quickschedule TV Rage API : Quick Schedule
8
+ class Schedule
9
+ Base_Uri = 'services.tvrage.com/feeds'
10
+
11
+ extend TVRage
12
+
13
+ class << self
14
+ # Gets the full schedule for country
15
+ #
16
+ # @param country [String] The country to query in (US, UK, NL)
17
+ # @param &block [Block] Called back with result unless fibered
18
+ # @return [Hash] The parsed XML of schedule information
19
+ # @see http://services.tvrage.com/feeds/fullschedule.php?country=US US's Full Schedule
20
+ def full(country, &block)
21
+ return Request.fibered(method(__method__), country) if defined? Fiber and Fiber.respond_to? :current and not block
22
+ Request.new(Base_Uri, '/fullschedule.php', block, :return_element => 'schedule', :country => country)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,38 @@
1
+ module EventMachine
2
+ module Sofa
3
+ module TVRage
4
+ # This class holds the XML information of a single season as per the TVRage API.
5
+ #
6
+ # @see http://services.tvrage.com/index.php?page=public TVRage API : Episode List
7
+ class Season
8
+ include Mapping
9
+
10
+ # Maps :no to itself
11
+ # @see EM:Sofa::Mapping
12
+ maps(:no => nil)
13
+
14
+ # Maps :episode to :episodes
15
+ # @see EM:Sofa::Mapping
16
+ # @yieldparam value [Hash, Array] A Hash of info if there's only one. An Array of info if there's multiple
17
+ # @yieldreturn [Array] A list of episodes initialized with value
18
+ maps(:episode => :episodes) do |value|
19
+ case value
20
+ when Hash
21
+ [Episode.new(value)]
22
+ when Array
23
+ value.map { |info| Episode.new(info) }
24
+ end
25
+ end
26
+
27
+ # Returns a new instance of Season, mapping info from the TVRage API
28
+ #
29
+ # @param info [Hash<Symbol, Object>] Info to initialize with
30
+ # @option info [String] :no The season number
31
+ # @option info [String] :episode The collection of episodes
32
+ def initialize(info)
33
+ update_with_mapping(info)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,193 @@
1
+ module EventMachine
2
+ module Sofa
3
+ module TVRage
4
+ # This class holds the XML information of a single Show as per the TVRage API.
5
+ # It's also the root point for communicating with the API.
6
+ #
7
+ # @see http://services.tvrage.com/index.php?page=public TVRage API
8
+ class Show
9
+ Base_Uri = 'services.tvrage.com'
10
+
11
+ extend TVRage
12
+
13
+ class << self
14
+ # Gets the info for a Show.
15
+ #
16
+ # @param sid [String] The show's id
17
+ # @param &block [Block] Called back with the parsed XML when successful unless fibered
18
+ # @return [EM:TVRage::Request] TVRage request object or result hash if fibered
19
+ # @see http://services.tvrage.com/feeds/showinfo.php?sid=15614 Chuck's Show Info
20
+ def info(sid, &block)
21
+ return fibered_async(__method__, sid, options) if defined? Fiber and Fiber.respond_to? :current and not block
22
+ raise ArgumentError, "No block given for completion callback" unless block
23
+ Request.new(Base_Uri, '/feeds/showinfo.php', block, :return_element => 'Showinfo', :sid => sid)
24
+ end
25
+
26
+ # Gets the full show info (info + season list + episode list) for a Show.
27
+ #
28
+ # @param sid [String] The show's id
29
+ # @param &block [Block] Called back with the parsed XML when successful unless fibered
30
+ # @return [EM:TVRage::Request] TVRage request object or result hash if fibered
31
+ # @see http://services.tvrage.com/feeds/full_show_info.php?sid=15614 Chuck's Full Show Info
32
+ def full_info(sid, &block)
33
+ return fibered_async(__method__, sid, options) if defined? Fiber and Fiber.respond_to? :current and not block
34
+ raise ArgumentError, "No block given for completion callback" unless block
35
+ Request.new(Base_Uri, '/feeds/full_show_info.php', block, :return_element => 'Show', :sid => sid)
36
+ end
37
+
38
+ # Gets the episode list for a Show.
39
+ #
40
+ # @param sid [String] The show's id
41
+ # @param &block [Block] Called back with the parsed XML when successful unless fibered
42
+ # @return [EM:TVRage::Request] TVRage request object or result hash if fibered
43
+ # @see http://services.tvrage.com/feeds/episode_list.php?sid=15614 Chuck's Episode List
44
+ def episode_list(sid, &block)
45
+ return Request.fibered(method(__method__), sid) if defined? Fiber and Fiber.respond_to? :current and not block
46
+ raise ArgumentError, "No block given for completion callback" unless block
47
+ Request.new(Base_Uri, '/feeds/episode_list.php', block, :return_element => 'Show', :sid => sid)
48
+ end
49
+
50
+ # Finds the Show by name using TVRage's Quickinfo API.
51
+ #
52
+ # @param name [String] The name of the show to search for
53
+ # @option options [Boolean] :greedy Whether or not to eager load the Season and Episode info
54
+ # @param &block [Block] Called back with the show with id parsed from the Quickinfo search unless fibered
55
+ # @return [EM:TVRage::Request] TVRage request object or result Show object if fibered
56
+ # @see http://services.tvrage.com/index.php?page=public&go=quickinfo TVRage Quickinfo API
57
+ # @see http://services.tvrage.com/tools/quickinfo.php?show=Chuck Chuck's Quickinfo
58
+ def by_name(name, options = {}, &block)
59
+ return Request.fibered(method(__method__), name, options) if defined? Fiber and Fiber.respond_to? :current and not block
60
+ raise ArgumentError, "No block given for completion callback" unless block
61
+ Request.new(Base_Uri, '/tools/quickinfo.php', block, :parse_element => 'pre', :show => name) do |request, xml|
62
+ options[:info] = parsed_quickinfo(xml)
63
+ Show.new(options[:info]['showid'], options) {|show| request.succeed show }
64
+ end
65
+ end
66
+
67
+ def parsed_quickinfo(raw_info)
68
+ info = Hash[raw_info.split(/\n/).collect {|line| k, v = line.split /@/; [k.gsub(' ', '').downcase, v] }]
69
+ info['showlink'] = info.delete('showurl')
70
+ info.each_key do |key|
71
+ case key.to_sym
72
+ when :latestepisode, :nextepisode
73
+ info[key] = Hash[[:number, :name, :date].zip(info[key].split /\^/)]
74
+ info[key][:date] = Date.parse(info[key][:date])
75
+ when :genres
76
+ info[key] = info[key].split ' | '
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ include Mapping
83
+
84
+ # @see EM:Sofa::Mapping
85
+ maps(
86
+ :ended => nil,
87
+ :showid => :show_id,
88
+ :showname => :name,
89
+ :name => nil,
90
+ :showlink => :show_link,
91
+ :seasons => nil,
92
+ :started => nil,
93
+ :startdate => :start_date,
94
+ :ended => nil,
95
+ :origin_country => nil,
96
+ :status => nil,
97
+ :classification => nil,
98
+ :runtime => :run_time,
99
+ :network => nil,
100
+ :airtime => :air_time,
101
+ :airday => :air_day,
102
+ :timezone => :time_zone,
103
+ :latestepisode => :latest_episode,
104
+ :nextepisode => :next_episode
105
+ )
106
+ maps(:genres => nil) #{ |value| value["genre"] }
107
+ maps(:akas => nil) { |value| value["aka"] }
108
+
109
+ # Maps :Episodelist to :season_list
110
+ # @see EM:Sofa::Mapping
111
+ # @yieldparam value [Hash, Array] A Hash of info if there's only one. An Array of info if there's multiple
112
+ # @yieldreturn [Array] A list of seasons initialized with value
113
+ maps(:Episodelist => :season_list) do |value|
114
+ case seasons = value["Season"]
115
+ when Hash
116
+ [Season.new(seasons)]
117
+ when Array
118
+ seasons.map { |info| Season.new(info) }
119
+ end
120
+ end
121
+
122
+ # Stores all the info that was greedy-loaded
123
+ #
124
+ # @return [Hash] The full show info (including seasons and episodes)
125
+ # @see Show.full_info
126
+ attr_accessor :greedy
127
+
128
+ # Returns a new instance of Show, loading and then mapping info from the TVRage API.
129
+ #
130
+ # @param id [String] The show_id as per the TVRage API
131
+ # @option options [Boolean] :greedy Whether or not to eager load the Season and Episode info
132
+ # @param &block [Block] Called back with the show with parsed info unless fibered
133
+ def initialize(id, options = {}, &block)
134
+ raise RuntimeError.new("id is required") unless (@show_id = id)
135
+ return TVRage::Request.fibered(method(__method__), id, options) if defined? Fiber and Fiber.respond_to? :current and not block
136
+ raise ArgumentError, "No block given for completion callback" unless block
137
+ klass = self.class
138
+ if options[:greedy]
139
+ return block.call(self) if @greedy
140
+ klass.full_info(@show_id) do |full_info|
141
+ next block.call(nil) unless full_info
142
+ update_with_mapping(@greedy = full_info)
143
+ block.call(self)
144
+ end
145
+ elsif options[:info]
146
+ update_with_mapping(options[:info])
147
+ block.call(self)
148
+ else
149
+ klass.info(@show_id) do |info|
150
+ next block.call(nil) unless info
151
+ update_with_mapping(info)
152
+ block.call(self)
153
+ end
154
+ end
155
+ end
156
+
157
+ # @param &block [Block] Called back with the list of seasons
158
+ def season_list(&block)
159
+ if defined? Fiber and Fiber.respond_to? :current and not block
160
+ f = Fiber.current
161
+ method(__method__).call {|data| f.resume(data) }
162
+ return Fiber.yield
163
+ end
164
+ raise ArgumentError, "No block given for completion callback" unless block
165
+ puts "@season_list = #@season_list" if @season_list
166
+ return block.call(@season_list) if @season_list
167
+ self.class.episode_list(@show_id) do |episode_list|
168
+ update_with_mapping(episode_list)
169
+ block.call(@season_list)
170
+ end
171
+ true
172
+ end
173
+
174
+ # @param &block [Block] Called back with the list of episodes
175
+ def episode_list(&block)
176
+ if defined? Fiber and Fiber.respond_to? :current and not block
177
+ f = Fiber.current
178
+ method(__method__).call {|data| f.resume(data) }
179
+ return Fiber.yield
180
+ end
181
+ raise ArgumentError, "No block given for completion callback" unless block
182
+ season_list do |seasons|
183
+ block.call(seasons.collect { |season| season.episodes }.flatten)
184
+ end
185
+ true
186
+ end
187
+
188
+ class NotFound < RuntimeError
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,10 @@
1
+ module EventMachine
2
+ module Sofa
3
+ module Version
4
+ MAJOR = 0
5
+ MINOR = 1
6
+ PATCH = 0
7
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,228 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Show>
3
+ <name>Castle (2009)</name>
4
+ <totalseasons>2</totalseasons>
5
+ <showid>19267</showid>
6
+ <showlink>http://tvrage.com/Castle</showlink>
7
+ <started>Mar/09/2009</started>
8
+ <ended/>
9
+ <image>http://images.tvrage.com/shows/20/19267.jpg</image>
10
+ <origin_country>US</origin_country>
11
+ <status>Returning Series</status>
12
+ <classification>Scripted</classification>
13
+ <genres>
14
+ <genre>Crime</genre>
15
+ <genre>Drama</genre>
16
+ <genre>Mystery</genre>
17
+ </genres>
18
+ <runtime>60</runtime>
19
+ <network country="US">ABC</network>
20
+ <airtime>22:00</airtime>
21
+ <airday>Monday</airday>
22
+ <timezone>GMT-5 -DST</timezone>
23
+ <Episodelist>
24
+ <Season no="1">
25
+ <episode>
26
+ <epnum>1</epnum>
27
+ <seasonnum>01</seasonnum>
28
+ <prodnum>101</prodnum>
29
+ <airdate>2009-03-09</airdate>
30
+ <link>http://www.tvrage.com/Castle/episodes/703445</link>
31
+ <title>Flowers for Your Grave</title>
32
+ <screencap>http://images.tvrage.com/screencaps/97/19267/703445.jpg</screencap>
33
+ </episode>
34
+ <episode>
35
+ <epnum>2</epnum>
36
+ <seasonnum>02</seasonnum>
37
+ <prodnum>102</prodnum>
38
+ <airdate>2009-03-16</airdate>
39
+ <link>http://www.tvrage.com/Castle/episodes/781859</link>
40
+ <title>Nanny McDead</title>
41
+ <screencap>http://images.tvrage.com/screencaps/97/19267/781859.jpg</screencap>
42
+ </episode>
43
+ <episode>
44
+ <epnum>3</epnum>
45
+ <seasonnum>03</seasonnum>
46
+ <prodnum>103</prodnum>
47
+ <airdate>2009-03-23</airdate>
48
+ <link>http://www.tvrage.com/Castle/episodes/781860</link>
49
+ <title>Hedge Fund Homeboys</title>
50
+ <screencap>http://images.tvrage.com/screencaps/97/19267/781860.jpg</screencap>
51
+ </episode>
52
+ <episode>
53
+ <epnum>4</epnum>
54
+ <seasonnum>04</seasonnum>
55
+ <prodnum>104</prodnum>
56
+ <airdate>2009-03-30</airdate>
57
+ <link>http://www.tvrage.com/Castle/episodes/781861</link>
58
+ <title>Hell Hath No Fury</title>
59
+ <screencap>http://images.tvrage.com/screencaps/97/19267/781861.jpg</screencap>
60
+ </episode>
61
+ <episode>
62
+ <epnum>5</epnum>
63
+ <seasonnum>05</seasonnum>
64
+ <prodnum>105</prodnum>
65
+ <airdate>2009-04-06</airdate>
66
+ <link>http://www.tvrage.com/Castle/episodes/781862</link>
67
+ <title>A Chill Goes Through Her Veins</title>
68
+ <screencap>http://images.tvrage.com/screencaps/97/19267/781862.jpg</screencap>
69
+ </episode>
70
+ <episode>
71
+ <epnum>6</epnum>
72
+ <seasonnum>06</seasonnum>
73
+ <prodnum>106</prodnum>
74
+ <airdate>2009-04-13</airdate>
75
+ <link>http://www.tvrage.com/Castle/episodes/781864</link>
76
+ <title>Always Buy Retail</title>
77
+ </episode>
78
+ <episode>
79
+ <epnum>7</epnum>
80
+ <seasonnum>07</seasonnum>
81
+ <prodnum>107</prodnum>
82
+ <airdate>2009-04-20</airdate>
83
+ <link>http://www.tvrage.com/Castle/episodes/781863</link>
84
+ <title>Home Is Where the Heart Stops</title>
85
+ <screencap>http://images.tvrage.com/screencaps/97/19267/781863.jpg</screencap>
86
+ </episode>
87
+ <episode>
88
+ <epnum>8</epnum>
89
+ <seasonnum>08</seasonnum>
90
+ <prodnum>108</prodnum>
91
+ <airdate>2009-04-27</airdate>
92
+ <link>http://www.tvrage.com/Castle/episodes/781865</link>
93
+ <title>Ghosts</title>
94
+ <screencap>http://images.tvrage.com/screencaps/97/19267/781865.jpg</screencap>
95
+ </episode>
96
+ <episode>
97
+ <epnum>9</epnum>
98
+ <seasonnum>09</seasonnum>
99
+ <prodnum>109</prodnum>
100
+ <airdate>2009-05-04</airdate>
101
+ <link>http://www.tvrage.com/Castle/episodes/781866</link>
102
+ <title>Little Girl Lost</title>
103
+ <screencap>http://images.tvrage.com/screencaps/97/19267/781866.jpg</screencap>
104
+ </episode>
105
+ <episode>
106
+ <epnum>10</epnum>
107
+ <seasonnum>10</seasonnum>
108
+ <prodnum>110</prodnum>
109
+ <airdate>2009-05-11</airdate>
110
+ <link>http://www.tvrage.com/Castle/episodes/781867</link>
111
+ <title>A Death in the Family</title>
112
+ <screencap>http://images.tvrage.com/screencaps/97/19267/781867.jpg</screencap>
113
+ </episode>
114
+ </Season>
115
+ <Season no="2">
116
+ <episode>
117
+ <epnum>11</epnum>
118
+ <seasonnum>01</seasonnum>
119
+ <prodnum>201</prodnum>
120
+ <airdate>2009-09-21</airdate>
121
+ <link>http://www.tvrage.com/Castle/episodes/1064812069</link>
122
+ <title>Deep in Death</title>
123
+ <screencap>http://images.tvrage.com/screencaps/97/19267/1064812069.jpg</screencap>
124
+ </episode>
125
+ <episode>
126
+ <epnum>12</epnum>
127
+ <seasonnum>02</seasonnum>
128
+ <prodnum>202</prodnum>
129
+ <airdate>2009-09-28</airdate>
130
+ <link>http://www.tvrage.com/Castle/episodes/1064824888</link>
131
+ <title>The Double Down</title>
132
+ <screencap>http://images.tvrage.com/screencaps/97/19267/1064824888.jpg</screencap>
133
+ </episode>
134
+ <episode>
135
+ <epnum>13</epnum>
136
+ <seasonnum>03</seasonnum>
137
+ <prodnum>203</prodnum>
138
+ <airdate>2009-10-05</airdate>
139
+ <link>http://www.tvrage.com/Castle/episodes/1064824889</link>
140
+ <title>Inventing the Girl</title>
141
+ <screencap>http://images.tvrage.com/screencaps/97/19267/1064824889.jpg</screencap>
142
+ </episode>
143
+ <episode>
144
+ <epnum>14</epnum>
145
+ <seasonnum>04</seasonnum>
146
+ <prodnum>204</prodnum>
147
+ <airdate>2009-10-12</airdate>
148
+ <link>http://www.tvrage.com/Castle/episodes/1064824890</link>
149
+ <title>Fool Me Once</title>
150
+ <screencap>http://images.tvrage.com/screencaps/97/19267/1064824890.jpg</screencap>
151
+ </episode>
152
+ <episode>
153
+ <epnum>15</epnum>
154
+ <seasonnum>05</seasonnum>
155
+ <prodnum>205</prodnum>
156
+ <airdate>2009-10-19</airdate>
157
+ <link>http://www.tvrage.com/Castle/episodes/1064842856</link>
158
+ <title>When the Bough Breaks</title>
159
+ <screencap>http://images.tvrage.com/screencaps/97/19267/1064842856.jpg</screencap>
160
+ </episode>
161
+ <episode>
162
+ <epnum>16</epnum>
163
+ <seasonnum>06</seasonnum>
164
+ <prodnum>206</prodnum>
165
+ <airdate>2009-10-26</airdate>
166
+ <link>http://www.tvrage.com/Castle/episodes/1064842857</link>
167
+ <title>Vampire Weekend</title>
168
+ <screencap>http://images.tvrage.com/screencaps/97/19267/1064842857.jpg</screencap>
169
+ </episode>
170
+ <episode>
171
+ <epnum>17</epnum>
172
+ <seasonnum>07</seasonnum>
173
+ <prodnum>207</prodnum>
174
+ <airdate>2009-11-02</airdate>
175
+ <link>http://www.tvrage.com/Castle/episodes/1064842858</link>
176
+ <title>Famous Last Words</title>
177
+ </episode>
178
+ <episode>
179
+ <epnum>18</epnum>
180
+ <seasonnum>08</seasonnum>
181
+ <prodnum>208</prodnum>
182
+ <airdate>2009-11-09</airdate>
183
+ <link>http://www.tvrage.com/Castle/episodes/1064842859</link>
184
+ <title>Kill the Messenger</title>
185
+ </episode>
186
+ <episode>
187
+ <epnum>19</epnum>
188
+ <seasonnum>09</seasonnum>
189
+ <prodnum>209</prodnum>
190
+ <airdate>2009-11-16</airdate>
191
+ <link>http://www.tvrage.com/Castle/episodes/1064842860</link>
192
+ <title>Love Me Dead</title>
193
+ </episode>
194
+ <episode>
195
+ <epnum>20</epnum>
196
+ <seasonnum>10</seasonnum>
197
+ <prodnum>210</prodnum>
198
+ <airdate>2009-11-23</airdate>
199
+ <link>http://www.tvrage.com/Castle/episodes/1064842861</link>
200
+ <title>One Man's Treasure</title>
201
+ </episode>
202
+ <episode>
203
+ <epnum>21</epnum>
204
+ <seasonnum>11</seasonnum>
205
+ <prodnum>211</prodnum>
206
+ <airdate>2009-11-30</airdate>
207
+ <link>http://www.tvrage.com/Castle/episodes/1064842862</link>
208
+ <title>The Fifth Bullet</title>
209
+ </episode>
210
+ <episode>
211
+ <epnum>22</epnum>
212
+ <seasonnum>12</seasonnum>
213
+ <prodnum>212</prodnum>
214
+ <airdate>0000-00-00</airdate>
215
+ <link>http://www.tvrage.com/Castle/episodes/1064842863</link>
216
+ <title>Season 2, Episode 12</title>
217
+ </episode>
218
+ <episode>
219
+ <epnum>23</epnum>
220
+ <seasonnum>13</seasonnum>
221
+ <prodnum>213</prodnum>
222
+ <airdate>0000-00-00</airdate>
223
+ <link>http://www.tvrage.com/Castle/episodes/1064842864</link>
224
+ <title>Season 2, Episode 13</title>
225
+ </episode>
226
+ </Season>
227
+ </Episodelist>
228
+ </Show>