feedzirra 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -18
  3. data/README.md +153 -128
  4. data/benchmarks/README.md +90 -0
  5. data/benchmarks/basic.rb +31 -0
  6. data/benchmarks/feed_list.txt +10 -0
  7. data/benchmarks/feed_xml/apple.xml +149 -0
  8. data/benchmarks/feed_xml/cnn.xml +278 -0
  9. data/benchmarks/feed_xml/daring_fireball.xml +1697 -0
  10. data/benchmarks/feed_xml/engadget.xml +604 -0
  11. data/benchmarks/feed_xml/feedzirra_commits.xml +370 -0
  12. data/benchmarks/feed_xml/gizmodo.xml +2 -0
  13. data/benchmarks/feed_xml/loop.xml +441 -0
  14. data/benchmarks/feed_xml/rails.xml +1938 -0
  15. data/benchmarks/feed_xml/white_house.xml +951 -0
  16. data/benchmarks/feed_xml/xkcd.xml +2 -0
  17. data/benchmarks/fetching_systems.rb +23 -0
  18. data/benchmarks/other_libraries.rb +73 -0
  19. data/feedzirra.gemspec +5 -6
  20. data/lib/feedzirra.rb +0 -1
  21. data/lib/feedzirra/feed_utilities.rb +1 -1
  22. data/lib/feedzirra/parser/atom.rb +1 -1
  23. data/lib/feedzirra/parser/itunes_rss.rb +1 -1
  24. data/lib/feedzirra/parser/itunes_rss_item.rb +2 -0
  25. data/lib/feedzirra/version.rb +1 -1
  26. data/spec/feedzirra/feed_spec.rb +13 -14
  27. data/spec/feedzirra/feed_utilities_spec.rb +44 -0
  28. data/spec/feedzirra/parser/atom_spec.rb +4 -0
  29. data/spec/feedzirra/parser/itunes_rss_item_spec.rb +8 -0
  30. data/spec/feedzirra/parser/itunes_rss_spec.rb +4 -0
  31. data/spec/sample_feeds/AtomFeedWithSpacesAroundEquals.xml +60 -0
  32. data/spec/sample_feeds/ITunesWithSpacesInAttributes.xml +62 -0
  33. data/spec/sample_feeds/itunes.xml +2 -0
  34. data/spec/spec_helper.rb +8 -0
  35. metadata +24 -34
  36. data/spec/benchmarks/feed_benchmarks.rb +0 -98
  37. data/spec/benchmarks/feedzirra_benchmarks.rb +0 -40
  38. data/spec/benchmarks/fetching_benchmarks.rb +0 -28
  39. data/spec/benchmarks/parsing_benchmark.rb +0 -30
  40. data/spec/benchmarks/updating_benchmarks.rb +0 -33
  41. data/spec/sample_feeds/run_against_sample.rb +0 -20
  42. data/spec/sample_feeds/top5kfeeds.dat +0 -2170
  43. data/spec/sample_feeds/trouble_feeds.txt +0 -16
@@ -0,0 +1,2 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title>xkcd.com</title><link href="http://xkcd.com/" rel="alternate"></link><id>http://xkcd.com/</id><updated>2013-11-29T00:00:00Z</updated><entry><title>Oort Cloud</title><link href="http://xkcd.com/1297/" rel="alternate"></link><updated>2013-11-29T00:00:00Z</updated><id>http://xkcd.com/1297/</id><summary type="html">&lt;img src="http://imgs.xkcd.com/comics/oort_cloud.png" title="... I wanna try. Hang on, be right back." alt="... I wanna try. Hang on, be right back." /&gt;</summary></entry><entry><title>Git Commit</title><link href="http://xkcd.com/1296/" rel="alternate"></link><updated>2013-11-27T00:00:00Z</updated><id>http://xkcd.com/1296/</id><summary type="html">&lt;img src="http://imgs.xkcd.com/comics/git_commit.png" title="Merge branch 'asdfasjkfdlas/alkdjf' into sdkjfls-final" alt="Merge branch 'asdfasjkfdlas/alkdjf' into sdkjfls-final" /&gt;</summary></entry><entry><title>New Study</title><link href="http://xkcd.com/1295/" rel="alternate"></link><updated>2013-11-25T00:00:00Z</updated><id>http://xkcd.com/1295/</id><summary type="html">&lt;img src="http://imgs.xkcd.com/comics/new_study.png" title="When the results are published, no one will be sure whether to report on them again." alt="When the results are published, no one will be sure whether to report on them again." /&gt;</summary></entry><entry><title>Telescope Names</title><link href="http://xkcd.com/1294/" rel="alternate"></link><updated>2013-11-22T00:00:00Z</updated><id>http://xkcd.com/1294/</id><summary type="html">&lt;img src="http://imgs.xkcd.com/comics/telescope_names.png" title="The Thirty Meter Telescope will be renamed The Flesh-Searing Eye on the Volcano." alt="The Thirty Meter Telescope will be renamed The Flesh-Searing Eye on the Volcano." /&gt;</summary></entry></feed>
@@ -0,0 +1,23 @@
1
+ require 'benchmark'
2
+ require 'net/http'
3
+ require 'curb'
4
+
5
+ urls = ['http://www.google.com'] * 100
6
+
7
+ Benchmark.bm(11) do |b|
8
+ b.report('Net::HTTP') do
9
+ urls.each do |url|
10
+ Net::HTTP.get URI.parse url
11
+ end
12
+ end
13
+
14
+ b.report('Curl::Easy') do
15
+ urls.each do |url|
16
+ Curl::Easy.perform url
17
+ end
18
+ end
19
+
20
+ b.report('Curl::Multi') do
21
+ Curl::Multi.get urls
22
+ end
23
+ end
@@ -0,0 +1,73 @@
1
+ require 'benchmark'
2
+ require 'feedzirra'
3
+ require 'simple-rss'
4
+ require 'feed-normalizer'
5
+ require 'feed_me'
6
+
7
+ iterations = 10
8
+ urls = File.readlines(File.dirname(__FILE__) + '/feed_list.txt')
9
+ files = Dir.glob(File.dirname(__FILE__) + '/feed_xml/*.xml')
10
+ xmls = files.map { |file| File.open(file).read }
11
+
12
+ # suppress warnings
13
+ $VERBOSE = nil
14
+
15
+ puts 'Parsing benchmarks'
16
+
17
+ Benchmark.bm(15) do |b|
18
+ b.report('feedzirra') do
19
+ iterations.times do
20
+ xmls.each { |xml| Feedzirra::Feed.parse xml }
21
+ end
22
+ end
23
+
24
+ b.report('simple-rss') do
25
+ iterations.times do
26
+ xmls.each { |xml| SimpleRSS.parse xml }
27
+ end
28
+ end
29
+
30
+ b.report('feed-normalizer') do
31
+ iterations.times do
32
+ xmls.each { |xml| FeedNormalizer::FeedNormalizer.parse xml }
33
+ end
34
+ end
35
+
36
+ # incompatible with `ruby-feedparser`, same constant used
37
+ require 'feed_parser'
38
+ b.report('feed_parser') do
39
+ iterations.times do
40
+ xmls.each { |xml| FeedParser.new(feed_xml: xml).parse }
41
+ end
42
+ end
43
+
44
+ b.report('feed_me') do
45
+ iterations.times do
46
+ xmls.each { |xml| FeedMe.parse xml }
47
+ end
48
+ end
49
+
50
+ # incompatible with `feed_parser`, same constant used
51
+ # require 'feedparser'
52
+ # b.report('ruby-feedparser') do
53
+ # iterations.times do
54
+ # xmls.each { |xml| FeedParser::Feed::new xml }
55
+ # end
56
+ # end
57
+ end
58
+
59
+ puts "\nFetch and parse benchmarks"
60
+
61
+ Benchmark.bm(15) do |b|
62
+ b.report('feedzirra') do
63
+ iterations.times { Feedzirra::Feed.fetch_and_parse urls }
64
+ end
65
+
66
+ # incompatible with `ruby-feedparser`, same constant used
67
+ require 'feed_parser'
68
+ b.report('feed_parser') do
69
+ iterations.times do
70
+ urls.each { |url| FeedParser.new(url: url).parse }
71
+ end
72
+ end
73
+ end
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.version = Feedzirra::VERSION
7
7
  s.license = 'MIT'
8
8
 
9
- s.authors = ['Paul Dix', 'Julien Kirch', "Ezekiel Templin"]
9
+ s.authors = ['Paul Dix', 'Julien Kirch', 'Ezekiel Templin', 'Jon Allured']
10
10
  s.email = 'feedzirra@googlegroups.com'
11
11
  s.homepage = 'http://github.com/pauldix/feedzirra'
12
12
 
@@ -19,10 +19,9 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.platform = Gem::Platform::RUBY
21
21
 
22
- s.add_dependency 'nokogiri', '~> 1.6.0'
23
- s.add_dependency 'sax-machine', '~> 0.2.1'
24
- s.add_dependency 'curb', '~> 0.8.1'
25
- s.add_dependency 'loofah', '~> 1.2.1'
22
+ s.add_dependency 'sax-machine', '~> 0.2.1'
23
+ s.add_dependency 'curb', '~> 0.8.1'
24
+ s.add_dependency 'loofah', '~> 1.2.1'
26
25
 
27
- s.add_development_dependency 'rspec', '~> 2.13.0'
26
+ s.add_development_dependency 'rspec', '~> 2.14.0'
28
27
  end
@@ -2,7 +2,6 @@ require 'zlib'
2
2
  require 'curb'
3
3
  require 'sax-machine'
4
4
  require 'loofah'
5
- require 'uri'
6
5
 
7
6
  require 'feedzirra/core_ext'
8
7
  require 'feedzirra/version'
@@ -62,7 +62,7 @@ module Feedzirra
62
62
  latest_entry = self.entries.first
63
63
  found_new_entries = []
64
64
  feed.entries.each do |entry|
65
- break if entry.id == latest_entry.id
65
+ break if entry.entry_id == latest_entry.entry_id || entry.url == latest_entry.url
66
66
  found_new_entries << entry
67
67
  end
68
68
  found_new_entries
@@ -14,7 +14,7 @@ module Feedzirra
14
14
  elements :entry, :as => :entries, :class => AtomEntry
15
15
 
16
16
  def self.able_to_parse?(xml) #:nodoc:
17
- /\<feed[^\>]+xmlns=[\"|\'](http:\/\/www\.w3\.org\/2005\/Atom|http:\/\/purl\.org\/atom\/ns\#)[\"|\'][^\>]*\>/ =~ xml
17
+ /\<feed[^\>]+xmlns\s?=\s?[\"|\'](http:\/\/www\.w3\.org\/2005\/Atom|http:\/\/purl\.org\/atom\/ns\#)[\"|\'][^\>]*\>/ =~ xml
18
18
  end
19
19
 
20
20
  def url
@@ -40,7 +40,7 @@ module Feedzirra
40
40
  elements :item, :as => :entries, :class => ITunesRSSItem
41
41
 
42
42
  def self.able_to_parse?(xml)
43
- /xmlns:itunes=\"http:\/\/www.itunes.com\/dtds\/podcast-1.0.dtd\"/i =~ xml
43
+ /xmlns:itunes\s?=\s?\"http:\/\/www.itunes.com\/dtds\/podcast-1.0.dtd\"/i =~ xml
44
44
  end
45
45
 
46
46
  end
@@ -22,6 +22,8 @@ module Feedzirra
22
22
  element :"itunes:keywords", :as => :itunes_keywords
23
23
  element :"itunes:subtitle", :as => :itunes_subtitle
24
24
  element :"itunes:image", :value => :href, :as => :itunes_image
25
+ element :"itunes:isClosedCaptioned", :as => :itunes_closed_captioned
26
+ element :"itunes:order", :as => :itunes_order
25
27
  # If summary is not present, use the description tag
26
28
  element :"itunes:summary", :as => :itunes_summary
27
29
  element :enclosure, :value => :length, :as => :enclosure_length
@@ -1,3 +1,3 @@
1
1
  module Feedzirra
2
- VERSION = '0.4.0'
2
+ VERSION = '0.5.0'
3
3
  end
@@ -675,19 +675,14 @@ describe Feedzirra::Feed do
675
675
  end
676
676
 
677
677
  describe "#fetch_and_parse" do
678
- it 'should initiate the fetching and parsing using multicurl'
679
- it "should pass any request options through to add_url_to_multi"
680
- it 'should slice the feeds into groups of thirty for processing'
681
- it "should return a feed object if a single feed is passed in"
682
- it "should return an return an array of feed objects if multiple feeds are passed in"
678
+ it "passes options to multicurl" do
679
+ options = { user_agent: '007' }
683
680
 
684
- it "should set if modified since as an option if passed" do
685
- modified_time = Time.parse_safely("Wed, 28 Jan 2009 04:10:32 GMT")
686
- Feedzirra::Feed.should_receive(:add_url_to_multi).with(anything, anything, anything, anything, {:if_modified_since => modified_time})
681
+ Feedzirra::Feed.should_receive(:add_url_to_multi).
682
+ with(anything, anything, anything, anything, options)
687
683
 
688
- @feed = Feedzirra::Feed.fetch_and_parse(sample_feedburner_atom_feed, {:if_modified_since => modified_time})
684
+ Feedzirra::Feed.fetch_and_parse(sample_rss_feed, options)
689
685
  end
690
-
691
686
  end
692
687
 
693
688
  describe "#decode_content" do
@@ -730,10 +725,14 @@ describe Feedzirra::Feed do
730
725
  end
731
726
 
732
727
  describe "#update" do
733
- it 'should perform the updating using multicurl'
734
- it "should pass any request options through to add_feed_to_multi"
735
- it "should return a feed object if a single feed is passed in"
736
- it "should return an return an array of feed objects if multiple feeds are passed in"
728
+ it "passes options to multicurl" do
729
+ options = { user_agent: '007' }
730
+
731
+ Feedzirra::Feed.should_receive(:add_feed_to_multi).
732
+ with(anything, anything, anything, anything, options)
733
+
734
+ Feedzirra::Feed.update(sample_rss_feed, options)
735
+ end
737
736
  end
738
737
  end
739
738
  end
@@ -122,9 +122,11 @@ describe Feedzirra::FeedUtilities do
122
122
  @old_entry = Feedzirra::Parser::AtomEntry.new
123
123
  @old_entry.url = "http://pauldix.net/old.html"
124
124
  @old_entry.published = Time.now.to_s
125
+ @old_entry.entry_id = "entry_id_old"
125
126
  @new_entry = Feedzirra::Parser::AtomEntry.new
126
127
  @new_entry.url = "http://pauldix.net/new.html"
127
128
  @new_entry.published = (Time.now + 10).to_s
129
+ @new_entry.entry_id = "entry_id_new"
128
130
  @feed.entries << @old_entry
129
131
  @updated_feed.entries << @new_entry
130
132
  @updated_feed.entries << @old_entry
@@ -189,5 +191,47 @@ describe Feedzirra::FeedUtilities do
189
191
  @feed.new_entries.size.should_not == 2
190
192
  end
191
193
  end
194
+
195
+ describe 'updating with a feed' do
196
+ let(:id_one) { '1' }
197
+ let(:id_two) { '2' }
198
+
199
+ let(:url_one) { 'http://example.com/post_one.html' }
200
+ let(:url_two) { 'http://example.com/post_two.html' }
201
+
202
+ let(:entry_one) { double 'Entry One', entry_id: id_one, url: url_one }
203
+ let(:entry_two) { double 'Entry Two', entry_id: id_two, url: url_two }
204
+
205
+ let(:feed_one) { Feedzirra::Parser::Atom.new }
206
+ let(:feed_two) { double 'Feed Two', entries: [entry_two] }
207
+
208
+ before do
209
+ stub_const("Feedzirra::FeedUtilities::UPDATABLE_ATTRIBUTES", [])
210
+ feed_one.entries << entry_one
211
+ end
212
+
213
+ it 'finds entries with unique ids and urls' do
214
+ feed_one.update_from_feed feed_two
215
+ feed_one.new_entries.should eq [entry_two]
216
+ end
217
+
218
+ context 'when the entries have the same id' do
219
+ let(:id_two) { id_one }
220
+
221
+ it 'does not find a new entry' do
222
+ feed_one.update_from_feed feed_two
223
+ feed_one.new_entries.should eq []
224
+ end
225
+ end
226
+
227
+ context 'when the entries have the same url' do
228
+ let(:url_two) { url_one }
229
+
230
+ it 'does not find a new entry' do
231
+ feed_one.update_from_feed feed_two
232
+ feed_one.new_entries.should eq []
233
+ end
234
+ end
235
+ end
192
236
  end
193
237
  end
@@ -13,6 +13,10 @@ describe Feedzirra::Parser::Atom do
13
13
  it "should return false for an rss feedburner feed" do
14
14
  Feedzirra::Parser::Atom.should_not be_able_to_parse(sample_rss_feed_burner_feed)
15
15
  end
16
+
17
+ it "should return true for an atom feed that has line breaks in between attributes in the <feed> node" do
18
+ Feedzirra::Parser::Atom.should be_able_to_parse(sample_atom_feed_line_breaks)
19
+ end
16
20
  end
17
21
 
18
22
  describe "parsing" do
@@ -48,4 +48,12 @@ describe Feedzirra::Parser::ITunesRSSItem do
48
48
  it "should parse the image" do
49
49
  @item.itunes_image.should == "http://example.com/podcasts/everything/AllAboutEverything.jpg"
50
50
  end
51
+
52
+ it "should parse the order" do
53
+ @item.itunes_order.should eq '12'
54
+ end
55
+
56
+ it "should parse the closed captioned flag" do
57
+ @item.itunes_closed_captioned.should eq 'yes'
58
+ end
51
59
  end
@@ -6,6 +6,10 @@ describe Feedzirra::Parser::ITunesRSS do
6
6
  Feedzirra::Parser::ITunesRSS.should be_able_to_parse(sample_itunes_feed)
7
7
  end
8
8
 
9
+ it "should return true for an itunes RSS feed with spaces between attribute names, equals sign, and values" do
10
+ Feedzirra::Parser::ITunesRSS.should be_able_to_parse(sample_itunes_feed_with_spaces)
11
+ end
12
+
9
13
  it "should return fase for an atom feed" do
10
14
  Feedzirra::Parser::ITunesRSS.should_not be_able_to_parse(sample_atom_feed)
11
15
  end
@@ -0,0 +1,60 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <!--
3
+ This atom/xml feed is an index to active advisories, watches and warnings
4
+ issued by the National Weather Service. This index file is not the complete
5
+ Common Alerting Protocol (CAP) alert message. To obtain the complete CAP
6
+ alert, please follow the links for each entry in this index. Also note the
7
+ CAP message uses a style sheet to convey the information in a human readable
8
+ format. Please view the source of the CAP message to see the complete data
9
+ set. Not all information in the CAP message is contained in this index of
10
+ active alerts.
11
+ -->
12
+ <feed
13
+ xmlns = "http://www.w3.org/2005/Atom"
14
+ xmlns:cap = "urn:oasis:names:tc:emergency:cap:1.1"
15
+ xmlns:ha = "http://www.alerting.net/namespace/index_1.0"
16
+ >
17
+ <!-- TZN = <EST> -->
18
+ <!-- TZO = <-5> -->
19
+ <!-- http-date = Wed, 07 Nov 2012 02:17:00 GMT -->
20
+ <id>http://alerts.weather.gov/cap/wwaatmget.php?x=MEC015&amp;y=0</id>
21
+ <generator>NWS CAP Server</generator>
22
+ <updated>2012-11-07T09:17:00-05:00</updated>
23
+ <author>
24
+ <name>w-nws.webmaster@noaa.gov</name>
25
+ </author>
26
+ <title>Current Watches, Warnings and Advisories for Lincoln (MEC015) Maine Issued by the National Weather Service</title>
27
+ <link href="http://alerts.weather.gov/cap/wwaatmget.php?x=MEC015&amp;y=0"/>
28
+ <entry>
29
+ <id>http://alerts.weather.gov/cap/wwacapget.php?x=ME124CCF70CDD4.WinterWeatherAdvisory.124CCF729F10ME.CARWSWCAR.b113b32cf3dd0946aab63451118d16e7</id>
30
+ <updated>2012-11-07T04:09:00-05:00</updated>
31
+ <published>2012-11-07T04:09:00-05:00</published>
32
+ <author>
33
+ <name>w-nws.webmaster@noaa.gov</name>
34
+ </author>
35
+ <title>Winter Weather Advisory issued November 07 at 4:09AM EST until November 08 at 12:00PM EST by NWS</title>
36
+ <link href="http://alerts.weather.gov/cap/wwacapget.php?x=ME124CCF70CDD4.WinterWeatherAdvisory.124CCF729F10ME.CARWSWCAR.b113b32cf3dd0946aab63451118d16e7"/>
37
+ <summary>...WINTER WEATHER ADVISORY IN EFFECT FROM 7 PM THIS EVENING TO NOON EST THURSDAY... THE NATIONAL WEATHER SERVICE IN CARIBOU HAS ISSUED A WINTER WEATHER ADVISORY FOR SNOW AND MIXED PRECIPITATION...WHICH IS IN EFFECT FROM 7 PM THIS EVENING TO NOON EST THURSDAY. * PRECIPITATION TYPE...SNOW...SLEET AND FREEZING RAIN</summary>
38
+ <cap:event>Winter Weather Advisory</cap:event>
39
+ <cap:effective>2012-11-07T04:09:00-05:00</cap:effective>
40
+ <cap:expires>2012-11-07T16:00:00-05:00</cap:expires>
41
+ <cap:status>Actual</cap:status>
42
+ <cap:msgType>Alert</cap:msgType>
43
+ <cap:category>Met</cap:category>
44
+ <cap:urgency>Expected</cap:urgency>
45
+ <cap:severity>Minor</cap:severity>
46
+ <cap:certainty>Likely</cap:certainty>
47
+ <cap:areaDesc>Central Penobscot; Central Washington; Interior Hancock; Northern Penobscot; Northern Washington; Southeast Aroostook; Southern Penobscot; Southern Piscataquis</cap:areaDesc>
48
+ <cap:polygon/>
49
+ <cap:geocode>
50
+ <valueName>FIPS6</valueName>
51
+ <value>023003 023009 023019 023021 023029</value>
52
+ <valueName>UGC</valueName>
53
+ <value>MEZ005 MEZ006 MEZ011 MEZ015 MEZ016 MEZ017 MEZ031 MEZ032</value>
54
+ </cap:geocode>
55
+ <cap:parameter>
56
+ <valueName>VTEC</valueName>
57
+ <value>/O.NEW.KCAR.WW.Y.0024.121108T0000Z-121108T1700Z/</value>
58
+ </cap:parameter>
59
+ </entry>
60
+ </feed>
@@ -0,0 +1,62 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <rss
3
+ xmlns:itunes = "http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0"
4
+ >
5
+
6
+ <channel>
7
+ <title>All About Everything</title>
8
+ <link>http://www.example.com/podcasts/everything/index.html</link>
9
+ <language>en-us</language>
10
+ <copyright>&#x2117; &amp; &#xA9; 2005 John Doe &amp; Family</copyright>
11
+ <itunes:subtitle>A show about everything</itunes:subtitle>
12
+ <itunes:author>John Doe</itunes:author>
13
+ <itunes:summary>All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our Podcast in the iTunes Music Store</itunes:summary>
14
+ <description>All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our Podcast in the iTunes Music Store</description>
15
+ <itunes:owner>
16
+ <itunes:name>John Doe</itunes:name>
17
+ <itunes:email>john.doe@example.com</itunes:email>
18
+ </itunes:owner>
19
+ <itunes:image href="http://example.com/podcasts/everything/AllAboutEverything.jpg" />
20
+ <itunes:category text="Technology">
21
+ <itunes:category text="Gadgets"/>
22
+ </itunes:category>
23
+ <itunes:category text="TV &amp; Film"/>
24
+
25
+ <item>
26
+ <title>Shake Shake Shake Your Spices</title>
27
+ <itunes:author>John Doe</itunes:author>
28
+ <itunes:subtitle>A short primer on table spices</itunes:subtitle>
29
+ <itunes:summary>This week we talk about salt and pepper shakers, comparing and contrasting pour rates, construction materials, and overall aesthetics. Come and join the party!</itunes:summary>
30
+ <enclosure url="http://example.com/podcasts/everything/AllAboutEverythingEpisode3.m4a" length="8727310" type="audio/x-m4a" />
31
+ <guid>http://example.com/podcasts/archive/aae20050615.m4a</guid>
32
+ <pubDate>Wed, 15 Jun 2005 19:00:00 GMT</pubDate>
33
+ <itunes:duration>7:04</itunes:duration>
34
+ <itunes:keywords>salt, pepper, shaker, exciting</itunes:keywords>
35
+ </item>
36
+
37
+ <item>
38
+ <title>Socket Wrench Shootout</title>
39
+ <itunes:author>Jane Doe</itunes:author>
40
+ <itunes:subtitle>Comparing socket wrenches is fun!</itunes:subtitle>
41
+ <itunes:summary>This week we talk about metric vs. old english socket wrenches. Which one is better? Do you really need both? Get all of your answers here.</itunes:summary>
42
+ <enclosure url="http://example.com/podcasts/everything/AllAboutEverythingEpisode2.mp3" length="5650889" type="audio/mpeg" />
43
+ <guid>http://example.com/podcasts/archive/aae20050608.mp3</guid>
44
+ <pubDate>Wed, 8 Jun 2005 19:00:00 GMT</pubDate>
45
+ <itunes:duration>4:34</itunes:duration>
46
+ <itunes:keywords>metric, socket, wrenches, tool</itunes:keywords>
47
+ </item>
48
+
49
+ <item>
50
+ <title>Red, Whine, &amp; Blue</title>
51
+ <itunes:author>Various</itunes:author>
52
+ <itunes:subtitle>Red + Blue != Purple</itunes:subtitle>
53
+ <itunes:summary>This week we talk about surviving in a Red state if you are a Blue person. Or vice versa.</itunes:summary>
54
+ <enclosure url="http://example.com/podcasts/everything/AllAboutEverythingEpisode1.mp3" length="4989537" type="audio/mpeg" />
55
+ <guid>http://example.com/podcasts/archive/aae20050601.mp3</guid>
56
+ <pubDate>Wed, 1 Jun 2005 19:00:00 GMT</pubDate>
57
+ <itunes:duration>3:59</itunes:duration>
58
+ <itunes:keywords>politics, red, blue, state</itunes:keywords>
59
+ </item>
60
+
61
+ </channel>
62
+ </rss>
@@ -31,6 +31,8 @@
31
31
  <itunes:duration>7:04</itunes:duration>
32
32
  <itunes:keywords>salt, pepper, shaker, exciting</itunes:keywords>
33
33
  <itunes:image href="http://example.com/podcasts/everything/AllAboutEverything.jpg" />
34
+ <itunes:order>12</itunes:order>
35
+ <itunes:isClosedCaptioned>yes</itunes:isClosedCaptioned>
34
36
  </item>
35
37
 
36
38
  <item>