youtube_it 2.1.4 → 2.1.5
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.rdoc +57 -5
 - data/lib/youtube_it.rb +3 -3
 - data/lib/youtube_it/chain_io.rb +1 -1
 - data/lib/youtube_it/client.rb +48 -11
 - data/lib/youtube_it/model/comment.rb +3 -3
 - data/lib/youtube_it/model/playlist.rb +1 -1
 - data/lib/youtube_it/model/user.rb +7 -0
 - data/lib/youtube_it/model/video.rb +37 -4
 - data/lib/youtube_it/parser.rb +269 -218
 - data/lib/youtube_it/request/base_search.rb +4 -0
 - data/lib/youtube_it/request/video_search.rb +20 -4
 - data/lib/youtube_it/request/video_upload.rb +166 -70
 - data/lib/youtube_it/version.rb +1 -1
 - data/youtube_it.gemspec +20 -91
 - metadata +72 -134
 - data/Gemfile +0 -12
 - data/Gemfile.lock +0 -43
 - data/Manifest.txt +0 -37
 - data/Rakefile +0 -58
 - data/VERSION +0 -1
 - data/test/files/recorded_response.xml +0 -1
 - data/test/files/youtube_video_response.xml +0 -53
 - data/test/helper.rb +0 -9
 - data/test/test.mov +0 -0
 - data/test/test_chain_io.rb +0 -63
 - data/test/test_client.rb +0 -454
 - data/test/test_field_search.rb +0 -48
 - data/test/test_video.rb +0 -48
 - data/test/test_video_feed_parser.rb +0 -271
 - data/test/test_video_search.rb +0 -147
 
    
        data/lib/youtube_it/parser.rb
    CHANGED
    
    | 
         @@ -1,9 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # encoding: UTF-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            class YouTubeIt
         
     | 
| 
       2 
4 
     | 
    
         
             
              module Parser #:nodoc:
         
     | 
| 
       3 
5 
     | 
    
         
             
                class FeedParser #:nodoc:
         
     | 
| 
       4 
6 
     | 
    
         
             
                  def initialize(content)
         
     | 
| 
       5 
7 
     | 
    
         
             
                    @content = (content =~ URI::regexp(%w(http https)) ? open(content).read : content)
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
       7 
9 
     | 
    
         
             
                  rescue OpenURI::HTTPError => e
         
     | 
| 
       8 
10 
     | 
    
         
             
                    raise OpenURI::HTTPError.new(e.io.status[0],e)
         
     | 
| 
       9 
11 
     | 
    
         
             
                  rescue
         
     | 
| 
         @@ -16,23 +18,27 @@ class YouTubeIt 
     | 
|
| 
       16 
18 
     | 
    
         
             
                  end
         
     | 
| 
       17 
19 
     | 
    
         | 
| 
       18 
20 
     | 
    
         
             
                  def parse_videos
         
     | 
| 
       19 
     | 
    
         
            -
                    doc =  
     | 
| 
      
 21 
     | 
    
         
            +
                    doc = Nokogiri::XML(@content)
         
     | 
| 
       20 
22 
     | 
    
         
             
                    videos = []
         
     | 
| 
       21 
     | 
    
         
            -
                    doc. 
     | 
| 
      
 23 
     | 
    
         
            +
                    doc.css("entry").each do |video|
         
     | 
| 
       22 
24 
     | 
    
         
             
                      videos << parse_entry(video)
         
     | 
| 
       23 
25 
     | 
    
         
             
                    end
         
     | 
| 
       24 
26 
     | 
    
         
             
                    videos
         
     | 
| 
       25 
27 
     | 
    
         
             
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def remove_bom str
         
     | 
| 
      
 30 
     | 
    
         
            +
                    str.gsub /\xEF\xBB\xBF|/, ''
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
       26 
32 
     | 
    
         
             
                end
         
     | 
| 
       27 
33 
     | 
    
         | 
| 
       28 
34 
     | 
    
         
             
                class CommentsFeedParser < FeedParser #:nodoc:
         
     | 
| 
       29 
35 
     | 
    
         
             
                  # return array of comments
         
     | 
| 
       30 
36 
     | 
    
         
             
                  def parse_content(content)
         
     | 
| 
       31 
     | 
    
         
            -
                    doc =  
     | 
| 
       32 
     | 
    
         
            -
                    feed = doc. 
     | 
| 
      
 37 
     | 
    
         
            +
                    doc = Nokogiri::XML(content.body)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    feed = doc.at("feed")
         
     | 
| 
       33 
39 
     | 
    
         | 
| 
       34 
40 
     | 
    
         
             
                    comments = []
         
     | 
| 
       35 
     | 
    
         
            -
                    feed. 
     | 
| 
      
 41 
     | 
    
         
            +
                    feed.css("entry").each do |entry|
         
     | 
| 
       36 
42 
     | 
    
         
             
                      comments << parse_entry(entry)
         
     | 
| 
       37 
43 
     | 
    
         
             
                    end
         
     | 
| 
       38 
44 
     | 
    
         
             
                    return comments
         
     | 
| 
         @@ -41,31 +47,38 @@ class YouTubeIt 
     | 
|
| 
       41 
47 
     | 
    
         
             
                  protected
         
     | 
| 
       42 
48 
     | 
    
         
             
                    def parse_entry(entry)
         
     | 
| 
       43 
49 
     | 
    
         
             
                      author = YouTubeIt::Model::Author.new(
         
     | 
| 
       44 
     | 
    
         
            -
                        :name => (entry. 
     | 
| 
       45 
     | 
    
         
            -
                        :uri  => (entry. 
     | 
| 
      
 50 
     | 
    
         
            +
                        :name => (entry.at("author/name").text rescue nil),
         
     | 
| 
      
 51 
     | 
    
         
            +
                        :uri  => (entry.at("author/uri").text rescue nil)
         
     | 
| 
       46 
52 
     | 
    
         
             
                      )
         
     | 
| 
       47 
53 
     | 
    
         
             
                      YouTubeIt::Model::Comment.new(
         
     | 
| 
       48 
54 
     | 
    
         
             
                        :author    => author,
         
     | 
| 
       49 
     | 
    
         
            -
                        :content   => entry. 
     | 
| 
       50 
     | 
    
         
            -
                        :published => entry. 
     | 
| 
       51 
     | 
    
         
            -
                        :title     => entry. 
     | 
| 
       52 
     | 
    
         
            -
                        :updated   => entry. 
     | 
| 
       53 
     | 
    
         
            -
                        :url       => entry. 
     | 
| 
      
 55 
     | 
    
         
            +
                        :content   => remove_bom(entry.at("content").text),
         
     | 
| 
      
 56 
     | 
    
         
            +
                        :published => entry.at("published").text,
         
     | 
| 
      
 57 
     | 
    
         
            +
                        :title     => remove_bom(entry.at("title").text),
         
     | 
| 
      
 58 
     | 
    
         
            +
                        :updated   => entry.at("updated").text,
         
     | 
| 
      
 59 
     | 
    
         
            +
                        :url       => entry.at("id").text,
         
     | 
| 
      
 60 
     | 
    
         
            +
                        :reply_to  => parse_reply(entry)
         
     | 
| 
       54 
61 
     | 
    
         
             
                      )
         
     | 
| 
       55 
62 
     | 
    
         
             
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    def parse_reply(entry)
         
     | 
| 
      
 65 
     | 
    
         
            +
                      if link = entry.at_xpath("xmlns:link[@rel='http://gdata.youtube.com/schemas/2007#in-reply-to']")
         
     | 
| 
      
 66 
     | 
    
         
            +
                        link["href"].split('/').last.gsub(/\?client.*/, '')
         
     | 
| 
      
 67 
     | 
    
         
            +
                      end
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end
         
     | 
| 
       56 
69 
     | 
    
         
             
                end
         
     | 
| 
       57 
70 
     | 
    
         | 
| 
       58 
71 
     | 
    
         
             
                class PlaylistFeedParser < FeedParser #:nodoc:
         
     | 
| 
       59 
72 
     | 
    
         | 
| 
       60 
73 
     | 
    
         
             
                  def parse_content(content)
         
     | 
| 
       61 
     | 
    
         
            -
                    xml =  
     | 
| 
       62 
     | 
    
         
            -
                    entry = xml. 
     | 
| 
      
 74 
     | 
    
         
            +
                    xml = Nokogiri::XML(content.body)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    entry = xml.at("entry") || xml.at("feed")
         
     | 
| 
       63 
76 
     | 
    
         
             
                    YouTubeIt::Model::Playlist.new(
         
     | 
| 
       64 
     | 
    
         
            -
                      :title         => entry. 
     | 
| 
       65 
     | 
    
         
            -
                      :summary       => (entry. 
     | 
| 
       66 
     | 
    
         
            -
                      :description   => (entry. 
     | 
| 
       67 
     | 
    
         
            -
                      :playlist_id   => entry. 
     | 
| 
       68 
     | 
    
         
            -
                      :published     => entry. 
     | 
| 
      
 77 
     | 
    
         
            +
                      :title         => entry.at("title") && entry.at("title").text,
         
     | 
| 
      
 78 
     | 
    
         
            +
                      :summary       => ((entry.at("summary") || entry.at_xpath("media:group").at_xpath("media:description")).text rescue nil),
         
     | 
| 
      
 79 
     | 
    
         
            +
                      :description   => ((entry.at("summary") || entry.at_xpath("media:group").at_xpath("media:description")).text rescue nil),
         
     | 
| 
      
 80 
     | 
    
         
            +
                      :playlist_id   => (entry.at("id").text[/playlist:(\w+)/, 1] rescue nil),
         
     | 
| 
      
 81 
     | 
    
         
            +
                      :published     => entry.at("published") ? entry.at("published").text : nil,
         
     | 
| 
       69 
82 
     | 
    
         
             
                      :response_code => content.status,
         
     | 
| 
       70 
83 
     | 
    
         
             
                      :xml           => content.body)
         
     | 
| 
       71 
84 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -75,398 +88,433 @@ class YouTubeIt 
     | 
|
| 
       75 
88 
     | 
    
         | 
| 
       76 
89 
     | 
    
         
             
                  # return array of playlist objects
         
     | 
| 
       77 
90 
     | 
    
         
             
                  def parse_content(content)
         
     | 
| 
       78 
     | 
    
         
            -
                    doc =  
     | 
| 
       79 
     | 
    
         
            -
                    feed = doc. 
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
      
 91 
     | 
    
         
            +
                    doc = Nokogiri::XML(content.body)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    feed = doc.at("feed")
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
       81 
94 
     | 
    
         
             
                    playlists = []
         
     | 
| 
       82 
     | 
    
         
            -
                    feed. 
     | 
| 
      
 95 
     | 
    
         
            +
                    feed.css("entry").each do |entry|
         
     | 
| 
       83 
96 
     | 
    
         
             
                      playlists << parse_entry(entry)
         
     | 
| 
       84 
97 
     | 
    
         
             
                    end
         
     | 
| 
       85 
98 
     | 
    
         
             
                    return playlists
         
     | 
| 
       86 
99 
     | 
    
         
             
                  end
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
       88 
101 
     | 
    
         
             
                  protected
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
       90 
103 
     | 
    
         
             
                  def parse_entry(entry)
         
     | 
| 
       91 
104 
     | 
    
         
             
                    YouTubeIt::Model::Playlist.new(
         
     | 
| 
       92 
     | 
    
         
            -
                      :title         => entry. 
     | 
| 
       93 
     | 
    
         
            -
                      :summary       => (entry. 
     | 
| 
       94 
     | 
    
         
            -
                      :description   => (entry. 
     | 
| 
       95 
     | 
    
         
            -
                      :playlist_id   => entry. 
     | 
| 
       96 
     | 
    
         
            -
                      :published     => entry. 
     | 
| 
      
 105 
     | 
    
         
            +
                      :title         => entry.at("title").text,
         
     | 
| 
      
 106 
     | 
    
         
            +
                      :summary       => (entry.at("summary") || entry.at_xpath("media:group").at_xpath("media:description")).text,
         
     | 
| 
      
 107 
     | 
    
         
            +
                      :description   => (entry.at("summary") || entry.at_xpath("media:group").at_xpath("media:description")).text,
         
     | 
| 
      
 108 
     | 
    
         
            +
                      :playlist_id   => entry.at("id").text[/playlist([^<]+)/, 1].sub(':',''),
         
     | 
| 
      
 109 
     | 
    
         
            +
                      :published     => entry.at("published") ? entry.at("published").text : nil,
         
     | 
| 
       97 
110 
     | 
    
         
             
                      :response_code => nil,
         
     | 
| 
       98 
111 
     | 
    
         
             
                      :xml           => nil)
         
     | 
| 
       99 
112 
     | 
    
         
             
                  end
         
     | 
| 
       100 
113 
     | 
    
         
             
                end
         
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
       102 
115 
     | 
    
         
             
                # Returns an array of the user's activity
         
     | 
| 
       103 
116 
     | 
    
         
             
                class ActivityParser < FeedParser
         
     | 
| 
       104 
117 
     | 
    
         
             
                  def parse_content(content)
         
     | 
| 
       105 
     | 
    
         
            -
                    doc =  
     | 
| 
       106 
     | 
    
         
            -
                    feed = doc. 
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
                     
     | 
| 
       109 
     | 
    
         
            -
                    feed. 
     | 
| 
       110 
     | 
    
         
            -
                      parsed_activity = parse_activity(entry)
         
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
                        activity << parsed_activity
         
     | 
| 
      
 118 
     | 
    
         
            +
                    doc = Nokogiri::XML(content.body)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    feed = doc.at("feed")
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                    activities = []
         
     | 
| 
      
 122 
     | 
    
         
            +
                    feed.css("entry").each do |entry|
         
     | 
| 
      
 123 
     | 
    
         
            +
                      if parsed_activity = parse_activity(entry)
         
     | 
| 
      
 124 
     | 
    
         
            +
                        activities << parsed_activity
         
     | 
| 
       113 
125 
     | 
    
         
             
                      end
         
     | 
| 
       114 
126 
     | 
    
         
             
                    end
         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
                    return  
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                    return activities
         
     | 
| 
       117 
129 
     | 
    
         
             
                  end
         
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
       119 
131 
     | 
    
         
             
                  protected
         
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
       121 
133 
     | 
    
         
             
                  # Parses the user's activity feed.
         
     | 
| 
       122 
134 
     | 
    
         
             
                  def parse_activity(entry)
         
     | 
| 
       123 
135 
     | 
    
         
             
                    # Figure out what kind of activity we have
         
     | 
| 
       124 
136 
     | 
    
         
             
                    video_type = nil
         
     | 
| 
       125 
137 
     | 
    
         
             
                    parsed_activity = nil
         
     | 
| 
       126 
     | 
    
         
            -
                    entry. 
     | 
| 
       127 
     | 
    
         
            -
                      if category_tag 
     | 
| 
       128 
     | 
    
         
            -
                        video_type = category_tag 
     | 
| 
      
 138 
     | 
    
         
            +
                    entry.css("category").each do |category_tag|
         
     | 
| 
      
 139 
     | 
    
         
            +
                      if category_tag["scheme"] == "http://gdata.youtube.com/schemas/2007/userevents.cat"
         
     | 
| 
      
 140 
     | 
    
         
            +
                        video_type = category_tag["term"]
         
     | 
| 
       129 
141 
     | 
    
         
             
                      end
         
     | 
| 
       130 
142 
     | 
    
         
             
                    end
         
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
       132 
144 
     | 
    
         
             
                    if video_type
         
     | 
| 
       133 
145 
     | 
    
         
             
                      case video_type
         
     | 
| 
       134 
146 
     | 
    
         
             
                      when "video_rated"
         
     | 
| 
       135 
147 
     | 
    
         
             
                        parsed_activity = YouTubeIt::Model::Activity.new(
         
     | 
| 
       136 
148 
     | 
    
         
             
                          :type => "video_rated",
         
     | 
| 
       137 
     | 
    
         
            -
                          :time => entry. 
     | 
| 
       138 
     | 
    
         
            -
                          :author => entry. 
     | 
| 
      
 149 
     | 
    
         
            +
                          :time => entry.at("updated") ? entry.at("updated").text : nil,
         
     | 
| 
      
 150 
     | 
    
         
            +
                          :author => entry.at("author/name") ? entry.at("author/name").text : nil,
         
     | 
| 
       139 
151 
     | 
    
         
             
                          :videos => parse_activity_videos(entry),
         
     | 
| 
       140 
     | 
    
         
            -
                          :video_id => entry. 
     | 
| 
      
 152 
     | 
    
         
            +
                          :video_id => entry.at_xpath("yt:videoid") ? entry.at_xpath("yt:videoid").text : nil
         
     | 
| 
       141 
153 
     | 
    
         
             
                        )
         
     | 
| 
       142 
154 
     | 
    
         
             
                      when "video_shared"
         
     | 
| 
       143 
155 
     | 
    
         
             
                        parsed_activity = YouTubeIt::Model::Activity.new(
         
     | 
| 
       144 
156 
     | 
    
         
             
                          :type => "video_shared",
         
     | 
| 
       145 
     | 
    
         
            -
                          :time => entry. 
     | 
| 
       146 
     | 
    
         
            -
                          :author => entry. 
     | 
| 
      
 157 
     | 
    
         
            +
                          :time => entry.at("updated") ? entry.at("updated").text : nil,
         
     | 
| 
      
 158 
     | 
    
         
            +
                          :author => entry.at("author/name") ? entry.at("author/name").text : nil,
         
     | 
| 
       147 
159 
     | 
    
         
             
                          :videos => parse_activity_videos(entry),
         
     | 
| 
       148 
     | 
    
         
            -
                          :video_id => entry. 
     | 
| 
      
 160 
     | 
    
         
            +
                          :video_id => entry.at_xpath("yt:videoid") ? entry.at_xpath("yt:videoid").text : nil
         
     | 
| 
       149 
161 
     | 
    
         
             
                        )
         
     | 
| 
       150 
162 
     | 
    
         
             
                      when "video_favorited"
         
     | 
| 
       151 
163 
     | 
    
         
             
                        parsed_activity = YouTubeIt::Model::Activity.new(
         
     | 
| 
       152 
164 
     | 
    
         
             
                          :type => "video_favorited",
         
     | 
| 
       153 
     | 
    
         
            -
                          :time => entry. 
     | 
| 
       154 
     | 
    
         
            -
                          :author => entry. 
     | 
| 
      
 165 
     | 
    
         
            +
                          :time => entry.at("updated") ? entry.at("updated").text : nil,
         
     | 
| 
      
 166 
     | 
    
         
            +
                          :author => entry.at("author/name") ? entry.at("author/name").text : nil,
         
     | 
| 
       155 
167 
     | 
    
         
             
                          :videos => parse_activity_videos(entry),
         
     | 
| 
       156 
     | 
    
         
            -
                          :video_id => entry. 
     | 
| 
      
 168 
     | 
    
         
            +
                          :video_id => entry.at_xpath("yt:videoid") ? entry.at_xpath("yt:videoid").text : nil
         
     | 
| 
       157 
169 
     | 
    
         
             
                        )
         
     | 
| 
       158 
170 
     | 
    
         
             
                      when "video_commented"
         
     | 
| 
       159 
171 
     | 
    
         
             
                        # Load the comment and video URL
         
     | 
| 
       160 
172 
     | 
    
         
             
                        comment_thread_url = nil
         
     | 
| 
       161 
173 
     | 
    
         
             
                        video_url = nil
         
     | 
| 
       162 
     | 
    
         
            -
                        entry. 
     | 
| 
       163 
     | 
    
         
            -
                          case link_tag 
     | 
| 
      
 174 
     | 
    
         
            +
                        entry.css("link").each do |link_tag|
         
     | 
| 
      
 175 
     | 
    
         
            +
                          case link_tag["rel"]
         
     | 
| 
       164 
176 
     | 
    
         
             
                          when "http://gdata.youtube.com/schemas/2007#comments"
         
     | 
| 
       165 
     | 
    
         
            -
                            comment_thread_url = link_tag 
     | 
| 
      
 177 
     | 
    
         
            +
                            comment_thread_url = link_tag["href"]
         
     | 
| 
       166 
178 
     | 
    
         
             
                          when "http://gdata.youtube.com/schemas/2007#video"
         
     | 
| 
       167 
     | 
    
         
            -
                            video_url = link_tag 
     | 
| 
      
 179 
     | 
    
         
            +
                            video_url = link_tag["href"]
         
     | 
| 
       168 
180 
     | 
    
         
             
                          else
         
     | 
| 
       169 
181 
     | 
    
         
             
                            # Invalid rel type, do nothing
         
     | 
| 
       170 
182 
     | 
    
         
             
                          end
         
     | 
| 
       171 
183 
     | 
    
         
             
                        end
         
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
       173 
185 
     | 
    
         
             
                        parsed_activity = YouTubeIt::Model::Activity.new(
         
     | 
| 
       174 
186 
     | 
    
         
             
                          :type => "video_commented",
         
     | 
| 
       175 
     | 
    
         
            -
                          :time => entry. 
     | 
| 
       176 
     | 
    
         
            -
                          :author => entry. 
     | 
| 
      
 187 
     | 
    
         
            +
                          :time => entry.at("updated") ? entry.at("updated").text : nil,
         
     | 
| 
      
 188 
     | 
    
         
            +
                          :author => entry.at("author/name") ? entry.at("author/name").text : nil,
         
     | 
| 
       177 
189 
     | 
    
         
             
                          :videos => parse_activity_videos(entry),
         
     | 
| 
       178 
     | 
    
         
            -
                          :video_id => entry. 
     | 
| 
      
 190 
     | 
    
         
            +
                          :video_id => entry.at_xpath("yt:videoid") ? entry.at_xpath("yt:videoid").text : nil,
         
     | 
| 
       179 
191 
     | 
    
         
             
                          :comment_thread_url => comment_thread_url,
         
     | 
| 
       180 
192 
     | 
    
         
             
                          :video_url => video_url
         
     | 
| 
       181 
193 
     | 
    
         
             
                        )
         
     | 
| 
       182 
194 
     | 
    
         
             
                      when "video_uploaded"
         
     | 
| 
       183 
195 
     | 
    
         
             
                        parsed_activity = YouTubeIt::Model::Activity.new(
         
     | 
| 
       184 
196 
     | 
    
         
             
                          :type => "video_uploaded",
         
     | 
| 
       185 
     | 
    
         
            -
                          :time => entry. 
     | 
| 
       186 
     | 
    
         
            -
                          :author => entry. 
     | 
| 
      
 197 
     | 
    
         
            +
                          :time => entry.at("updated") ? entry.at("updated").text : nil,
         
     | 
| 
      
 198 
     | 
    
         
            +
                          :author => entry.at("author/name") ? entry.at("author/name").text : nil,
         
     | 
| 
       187 
199 
     | 
    
         
             
                          :videos => parse_activity_videos(entry),
         
     | 
| 
       188 
     | 
    
         
            -
                          :video_id => entry. 
     | 
| 
      
 200 
     | 
    
         
            +
                          :video_id => entry.at_xpath("yt:videoid") ? entry.at_xpath("yt:videoid").text : nil
         
     | 
| 
       189 
201 
     | 
    
         
             
                        )
         
     | 
| 
       190 
202 
     | 
    
         
             
                      when "friend_added"
         
     | 
| 
       191 
203 
     | 
    
         
             
                        parsed_activity = YouTubeIt::Model::Activity.new(
         
     | 
| 
       192 
204 
     | 
    
         
             
                          :type => "friend_added",
         
     | 
| 
       193 
     | 
    
         
            -
                          :time => entry. 
     | 
| 
       194 
     | 
    
         
            -
                          :author => entry. 
     | 
| 
       195 
     | 
    
         
            -
                          :username => entry. 
     | 
| 
      
 205 
     | 
    
         
            +
                          :time => entry.at("updated") ? entry.at("updated").text : nil,
         
     | 
| 
      
 206 
     | 
    
         
            +
                          :author => entry.at("author/name") ? entry.at("author/name").text : nil,
         
     | 
| 
      
 207 
     | 
    
         
            +
                          :username => entry.at_xpath("yt:username") ? entry.at_xpath("yt:username").text : nil
         
     | 
| 
       196 
208 
     | 
    
         
             
                        )
         
     | 
| 
       197 
209 
     | 
    
         
             
                      when "user_subscription_added"
         
     | 
| 
       198 
210 
     | 
    
         
             
                        parsed_activity = YouTubeIt::Model::Activity.new(
         
     | 
| 
       199 
211 
     | 
    
         
             
                          :type => "user_subscription_added",
         
     | 
| 
       200 
     | 
    
         
            -
                          :time => entry. 
     | 
| 
       201 
     | 
    
         
            -
                          :author => entry. 
     | 
| 
       202 
     | 
    
         
            -
                          :username => entry. 
     | 
| 
      
 212 
     | 
    
         
            +
                          :time => entry.at("updated") ? entry.at("updated").text : nil,
         
     | 
| 
      
 213 
     | 
    
         
            +
                          :author => entry.at("author/name") ? entry.at("author/name").text : nil,
         
     | 
| 
      
 214 
     | 
    
         
            +
                          :username => entry.at_xpath("yt:username") ? entry.at_xpath("yt:username").text : nil
         
     | 
| 
       203 
215 
     | 
    
         
             
                        )
         
     | 
| 
       204 
216 
     | 
    
         
             
                      else
         
     | 
| 
       205 
217 
     | 
    
         
             
                        # Invalid activity type, just let it return nil
         
     | 
| 
       206 
218 
     | 
    
         
             
                      end
         
     | 
| 
       207 
219 
     | 
    
         
             
                    end
         
     | 
| 
       208 
     | 
    
         
            -
             
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
       209 
221 
     | 
    
         
             
                    return parsed_activity
         
     | 
| 
       210 
222 
     | 
    
         
             
                  end
         
     | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
       212 
224 
     | 
    
         
             
                  # If a user enabled inline attribute videos may be included in results.
         
     | 
| 
       213 
225 
     | 
    
         
             
                  def parse_activity_videos(entry)
         
     | 
| 
       214 
226 
     | 
    
         
             
                    videos = []
         
     | 
| 
       215 
     | 
    
         
            -
             
     | 
| 
       216 
     | 
    
         
            -
                    entry. 
     | 
| 
       217 
     | 
    
         
            -
                      if link_tag. 
     | 
| 
       218 
     | 
    
         
            -
                        videos << YouTubeIt::Parser::VideoFeedParser.new(link_tag).parse
         
     | 
| 
       219 
     | 
    
         
            -
                      end
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
                    entry.css("link").each do |link_tag|
         
     | 
| 
      
 229 
     | 
    
         
            +
                      videos << YouTubeIt::Parser::VideoFeedParser.new(link_tag).parse if link_tag.at("entry")
         
     | 
| 
       220 
230 
     | 
    
         
             
                    end
         
     | 
| 
       221 
     | 
    
         
            -
             
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
       222 
232 
     | 
    
         
             
                    if videos.size <= 0
         
     | 
| 
       223 
233 
     | 
    
         
             
                      videos = nil
         
     | 
| 
       224 
234 
     | 
    
         
             
                    end
         
     | 
| 
       225 
     | 
    
         
            -
             
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
       226 
236 
     | 
    
         
             
                    return videos
         
     | 
| 
       227 
237 
     | 
    
         
             
                  end
         
     | 
| 
       228 
238 
     | 
    
         
             
                end
         
     | 
| 
       229 
     | 
    
         
            -
             
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
       230 
240 
     | 
    
         
             
                # Returns an array of the user's contacts
         
     | 
| 
       231 
241 
     | 
    
         
             
                class ContactsParser < FeedParser
         
     | 
| 
       232 
242 
     | 
    
         
             
                  def parse_content(content)
         
     | 
| 
       233 
     | 
    
         
            -
                    doc =  
     | 
| 
       234 
     | 
    
         
            -
                    feed = doc. 
     | 
| 
       235 
     | 
    
         
            -
             
     | 
| 
      
 243 
     | 
    
         
            +
                    doc = Nokogiri::XML(content.body)
         
     | 
| 
      
 244 
     | 
    
         
            +
                    feed = doc.at("feed")
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
       236 
246 
     | 
    
         
             
                    contacts = []
         
     | 
| 
       237 
     | 
    
         
            -
                    feed. 
     | 
| 
      
 247 
     | 
    
         
            +
                    feed.css("entry").each do |entry|
         
     | 
| 
       238 
248 
     | 
    
         
             
                      temp_contact = YouTubeIt::Model::Contact.new(
         
     | 
| 
       239 
     | 
    
         
            -
                        :title    => entry. 
     | 
| 
       240 
     | 
    
         
            -
                        :username => entry. 
     | 
| 
       241 
     | 
    
         
            -
                        :status   => entry. 
     | 
| 
      
 249 
     | 
    
         
            +
                        :title    => entry.at("title") ? entry.at("title").text : nil,
         
     | 
| 
      
 250 
     | 
    
         
            +
                        :username => entry.at_xpath("yt:username") ? entry.at_xpath("yt:username").text : nil,
         
     | 
| 
      
 251 
     | 
    
         
            +
                        :status   => entry.at_xpath("yt:status") ? entry.at_xpath("yt:status").text : nil
         
     | 
| 
       242 
252 
     | 
    
         
             
                      )
         
     | 
| 
       243 
     | 
    
         
            -
             
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
       244 
254 
     | 
    
         
             
                      contacts << temp_contact
         
     | 
| 
       245 
255 
     | 
    
         
             
                    end
         
     | 
| 
       246 
     | 
    
         
            -
             
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
       247 
257 
     | 
    
         
             
                    return contacts
         
     | 
| 
       248 
258 
     | 
    
         
             
                  end
         
     | 
| 
       249 
259 
     | 
    
         
             
                end
         
     | 
| 
       250 
     | 
    
         
            -
             
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
       251 
261 
     | 
    
         
             
                # Returns an array of the user's messages
         
     | 
| 
       252 
262 
     | 
    
         
             
                class MessagesParser < FeedParser
         
     | 
| 
       253 
263 
     | 
    
         
             
                  def parse_content(content)
         
     | 
| 
       254 
     | 
    
         
            -
                    doc =  
     | 
| 
       255 
     | 
    
         
            -
                     
     | 
| 
       256 
     | 
    
         
            -
             
     | 
| 
       257 
     | 
    
         
            -
                    puts doc.inspect
         
     | 
| 
       258 
     | 
    
         
            -
                    feed = doc.elements["feed"]
         
     | 
| 
       259 
     | 
    
         
            -
                    
         
     | 
| 
      
 264 
     | 
    
         
            +
                    doc = Nokogiri::XML(content.body)
         
     | 
| 
      
 265 
     | 
    
         
            +
                    feed = doc.at("feed")
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
       260 
267 
     | 
    
         
             
                    messages = []
         
     | 
| 
       261 
     | 
    
         
            -
                    feed. 
     | 
| 
       262 
     | 
    
         
            -
                      author = entry. 
     | 
| 
      
 268 
     | 
    
         
            +
                    feed.css("entry").each do |entry|
         
     | 
| 
      
 269 
     | 
    
         
            +
                      author = entry.at("author")
         
     | 
| 
       263 
270 
     | 
    
         
             
                      temp_message = YouTubeIt::Model::Message.new(
         
     | 
| 
       264 
     | 
    
         
            -
                        :id  => entry. 
     | 
| 
       265 
     | 
    
         
            -
                        :title    => entry. 
     | 
| 
       266 
     | 
    
         
            -
                        :name => author && author. 
     | 
| 
       267 
     | 
    
         
            -
                        :summary   => entry. 
     | 
| 
       268 
     | 
    
         
            -
                        :published   => entry. 
     | 
| 
      
 271 
     | 
    
         
            +
                        :id  => entry.at("id") ? entry.at("id").text.gsub(/.+:inbox:/, "") : nil,
         
     | 
| 
      
 272 
     | 
    
         
            +
                        :title    => entry.at("title") ? entry.at("title").text : nil,
         
     | 
| 
      
 273 
     | 
    
         
            +
                        :name => author && author.at("name") ? author.at("name").text : nil,
         
     | 
| 
      
 274 
     | 
    
         
            +
                        :summary   => entry.at("summary") ? entry.at("summary").text : nil,
         
     | 
| 
      
 275 
     | 
    
         
            +
                        :published   => entry.at("published") ? entry.at("published").text : nil
         
     | 
| 
       269 
276 
     | 
    
         
             
                      )
         
     | 
| 
       270 
     | 
    
         
            -
             
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
       271 
278 
     | 
    
         
             
                      messages << temp_message
         
     | 
| 
       272 
279 
     | 
    
         
             
                    end
         
     | 
| 
       273 
     | 
    
         
            -
             
     | 
| 
      
 280 
     | 
    
         
            +
             
     | 
| 
       274 
281 
     | 
    
         
             
                    return messages
         
     | 
| 
       275 
282 
     | 
    
         
             
                  end
         
     | 
| 
       276 
283 
     | 
    
         
             
                end
         
     | 
| 
       277 
284 
     | 
    
         | 
| 
       278 
285 
     | 
    
         
             
                class ProfileFeedParser < FeedParser #:nodoc:
         
     | 
| 
       279 
286 
     | 
    
         
             
                  def parse_content(content)
         
     | 
| 
       280 
     | 
    
         
            -
                    xml =  
     | 
| 
       281 
     | 
    
         
            -
                    entry = xml. 
     | 
| 
      
 287 
     | 
    
         
            +
                    xml = Nokogiri::XML(content.body)
         
     | 
| 
      
 288 
     | 
    
         
            +
                    entry = xml.at("entry") || xml.at("feed")
         
     | 
| 
      
 289 
     | 
    
         
            +
                    parse_entry(entry)
         
     | 
| 
      
 290 
     | 
    
         
            +
                  end
         
     | 
| 
      
 291 
     | 
    
         
            +
                  def parse_entry(entry)
         
     | 
| 
       282 
292 
     | 
    
         
             
                    YouTubeIt::Model::User.new(
         
     | 
| 
       283 
     | 
    
         
            -
                      :age            => entry. 
     | 
| 
       284 
     | 
    
         
            -
                      :username       => entry. 
     | 
| 
       285 
     | 
    
         
            -
                      : 
     | 
| 
       286 
     | 
    
         
            -
                      : 
     | 
| 
       287 
     | 
    
         
            -
                      : 
     | 
| 
       288 
     | 
    
         
            -
                      : 
     | 
| 
       289 
     | 
    
         
            -
                      : 
     | 
| 
       290 
     | 
    
         
            -
                      : 
     | 
| 
       291 
     | 
    
         
            -
                      : 
     | 
| 
       292 
     | 
    
         
            -
                      : 
     | 
| 
       293 
     | 
    
         
            -
                      : 
     | 
| 
       294 
     | 
    
         
            -
                      : 
     | 
| 
       295 
     | 
    
         
            -
                      : 
     | 
| 
       296 
     | 
    
         
            -
                      : 
     | 
| 
       297 
     | 
    
         
            -
                      : 
     | 
| 
       298 
     | 
    
         
            -
                      : 
     | 
| 
       299 
     | 
    
         
            -
                      : 
     | 
| 
       300 
     | 
    
         
            -
                      : 
     | 
| 
       301 
     | 
    
         
            -
                      : 
     | 
| 
      
 293 
     | 
    
         
            +
                      :age            => entry.at_xpath("yt:age") ? entry.at_xpath("yt:age").text : nil,
         
     | 
| 
      
 294 
     | 
    
         
            +
                      :username       => entry.at_xpath("yt:username") ? entry.at_xpath("yt:username").text : nil,
         
     | 
| 
      
 295 
     | 
    
         
            +
                      :username_display => (entry.at_xpath("yt:username")['display'] rescue nil),
         
     | 
| 
      
 296 
     | 
    
         
            +
                      :user_id        => (entry.at_xpath("xmlns:author/yt:userId").text rescue nil),
         
     | 
| 
      
 297 
     | 
    
         
            +
                      :last_name      => (entry.at_xpath("yt:lastName").text rescue nil),
         
     | 
| 
      
 298 
     | 
    
         
            +
                      :first_name     => (entry.at_xpath("yt:firstName").text rescue nil),
         
     | 
| 
      
 299 
     | 
    
         
            +
                      :company        => entry.at_xpath("yt:company") ? entry.at_xpath("yt:company").text : nil,
         
     | 
| 
      
 300 
     | 
    
         
            +
                      :gender         => entry.at_xpath("yt:gender") ? entry.at_xpath("yt:gender").text : nil,
         
     | 
| 
      
 301 
     | 
    
         
            +
                      :hobbies        => entry.at_xpath("yt:hobbies") ? entry.at_xpath("yt:hobbies").text : nil,
         
     | 
| 
      
 302 
     | 
    
         
            +
                      :hometown       => entry.at_xpath("yt:hometown") ? entry.at_xpath("yt:hometown").text : nil,
         
     | 
| 
      
 303 
     | 
    
         
            +
                      :location       => entry.at_xpath("yt:location") ? entry.at_xpath("yt:location").text : nil,
         
     | 
| 
      
 304 
     | 
    
         
            +
                      :last_login     => entry.at_xpath("yt:statistics")["lastWebAccess"],
         
     | 
| 
      
 305 
     | 
    
         
            +
                      :join_date      => entry.at("published") ? entry.at("published").text : nil,
         
     | 
| 
      
 306 
     | 
    
         
            +
                      :movies         => entry.at_xpath("yt:movies") ? entry.at_xpath("yt:movies").text : nil,
         
     | 
| 
      
 307 
     | 
    
         
            +
                      :music          => entry.at_xpath("yt:music") ? entry.at_xpath("yt:music").text : nil,
         
     | 
| 
      
 308 
     | 
    
         
            +
                      :occupation     => entry.at_xpath("yt:occupation") ? entry.at_xpath("yt:occupation").text : nil,
         
     | 
| 
      
 309 
     | 
    
         
            +
                      :relationship   => entry.at_xpath("yt:relationship") ? entry.at_xpath("yt:relationship").text : nil,
         
     | 
| 
      
 310 
     | 
    
         
            +
                      :school         => entry.at_xpath("yt:school") ? entry.at_xpath("yt:school").text : nil,
         
     | 
| 
      
 311 
     | 
    
         
            +
                      :avatar         => entry.at_xpath("media:thumbnail") ? entry.at_xpath("media:thumbnail")["url"] : nil,
         
     | 
| 
      
 312 
     | 
    
         
            +
                      :upload_count   => (entry.at_xpath('gd:feedLink[@rel="http://gdata.youtube.com/schemas/2007#user.uploads"]')['countHint'].to_i rescue nil),
         
     | 
| 
      
 313 
     | 
    
         
            +
                      :max_upload_duration => (entry.at_xpath("yt:maxUploadDuration")['seconds'].to_i rescue nil),
         
     | 
| 
      
 314 
     | 
    
         
            +
                      :subscribers    => entry.at_xpath("yt:statistics")["subscriberCount"],
         
     | 
| 
      
 315 
     | 
    
         
            +
                      :videos_watched => entry.at_xpath("yt:statistics")["videoWatchCount"],
         
     | 
| 
      
 316 
     | 
    
         
            +
                      :view_count     => entry.at_xpath("yt:statistics")["viewCount"],
         
     | 
| 
      
 317 
     | 
    
         
            +
                      :upload_views   => entry.at_xpath("yt:statistics")["totalUploadViews"],
         
     | 
| 
      
 318 
     | 
    
         
            +
                      :insight_uri    => (entry.at_xpath('xmlns:link[@rel="http://gdata.youtube.com/schemas/2007#insight.views"]')['href'] rescue nil)
         
     | 
| 
       302 
319 
     | 
    
         
             
                    )
         
     | 
| 
       303 
320 
     | 
    
         
             
                  end
         
     | 
| 
       304 
321 
     | 
    
         
             
                end
         
     | 
| 
       305 
     | 
    
         
            -
             
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
      
 323 
     | 
    
         
            +
                class BatchProfileFeedParser < ProfileFeedParser
         
     | 
| 
      
 324 
     | 
    
         
            +
                  def parse_content(content)
         
     | 
| 
      
 325 
     | 
    
         
            +
                    Nokogiri::XML(content.body).xpath("//xmlns:entry").map do |entry|
         
     | 
| 
      
 326 
     | 
    
         
            +
                      entry.namespaces.each {|name, url| entry.document.root.add_namespace name, url }
         
     | 
| 
      
 327 
     | 
    
         
            +
                      username = entry.at_xpath('batch:id', entry.namespaces).text
         
     | 
| 
      
 328 
     | 
    
         
            +
                      result = catch(:result) do
         
     | 
| 
      
 329 
     | 
    
         
            +
                        case entry.at_xpath('batch:status', entry.namespaces)['code'].to_i
         
     | 
| 
      
 330 
     | 
    
         
            +
                        when 200...300 then parse_entry(entry)
         
     | 
| 
      
 331 
     | 
    
         
            +
                        else nil
         
     | 
| 
      
 332 
     | 
    
         
            +
                        end
         
     | 
| 
      
 333 
     | 
    
         
            +
                      end
         
     | 
| 
      
 334 
     | 
    
         
            +
                      { username => result }
         
     | 
| 
      
 335 
     | 
    
         
            +
                    end.reduce({},:merge)
         
     | 
| 
      
 336 
     | 
    
         
            +
                  end
         
     | 
| 
      
 337 
     | 
    
         
            +
                end
         
     | 
| 
      
 338 
     | 
    
         
            +
             
     | 
| 
       306 
339 
     | 
    
         
             
                class SubscriptionFeedParser < FeedParser #:nodoc:
         
     | 
| 
       307 
340 
     | 
    
         | 
| 
       308 
341 
     | 
    
         
             
                  def parse_content(content)
         
     | 
| 
       309 
     | 
    
         
            -
                    doc =  
     | 
| 
       310 
     | 
    
         
            -
                    feed = doc. 
     | 
| 
       311 
     | 
    
         
            -
             
     | 
| 
      
 342 
     | 
    
         
            +
                    doc = Nokogiri::XML(content.body)
         
     | 
| 
      
 343 
     | 
    
         
            +
                    feed = doc.at("feed")
         
     | 
| 
      
 344 
     | 
    
         
            +
             
     | 
| 
       312 
345 
     | 
    
         
             
                    subscriptions = []
         
     | 
| 
       313 
     | 
    
         
            -
                    feed. 
     | 
| 
      
 346 
     | 
    
         
            +
                    feed.css("entry").each do |entry|
         
     | 
| 
       314 
347 
     | 
    
         
             
                      subscriptions << parse_entry(entry)
         
     | 
| 
       315 
348 
     | 
    
         
             
                    end
         
     | 
| 
       316 
349 
     | 
    
         
             
                    return subscriptions
         
     | 
| 
       317 
350 
     | 
    
         
             
                  end
         
     | 
| 
       318 
     | 
    
         
            -
             
     | 
| 
      
 351 
     | 
    
         
            +
             
     | 
| 
       319 
352 
     | 
    
         
             
                  protected
         
     | 
| 
       320 
     | 
    
         
            -
             
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
       321 
354 
     | 
    
         
             
                  def parse_entry(entry)
         
     | 
| 
       322 
355 
     | 
    
         
             
                    YouTubeIt::Model::Subscription.new(
         
     | 
| 
       323 
     | 
    
         
            -
                      :title        => entry. 
     | 
| 
       324 
     | 
    
         
            -
                      :id           => entry. 
     | 
| 
       325 
     | 
    
         
            -
                      :published    => entry. 
     | 
| 
      
 356 
     | 
    
         
            +
                      :title        => entry.at("title").text,
         
     | 
| 
      
 357 
     | 
    
         
            +
                      :id           => entry.at("id").text[/subscription([^<]+)/, 1].sub(':',''),
         
     | 
| 
      
 358 
     | 
    
         
            +
                      :published    => entry.at("published") ? entry.at("published").text : nil
         
     | 
| 
       326 
359 
     | 
    
         
             
                    )
         
     | 
| 
       327 
360 
     | 
    
         
             
                  end
         
     | 
| 
       328 
361 
     | 
    
         
             
                end
         
     | 
| 
       329 
     | 
    
         
            -
             
     | 
| 
      
 362 
     | 
    
         
            +
             
     | 
| 
       330 
363 
     | 
    
         | 
| 
       331 
364 
     | 
    
         
             
                class VideoFeedParser < FeedParser #:nodoc:
         
     | 
| 
       332 
365 
     | 
    
         | 
| 
       333 
366 
     | 
    
         
             
                  def parse_content(content)
         
     | 
| 
       334 
     | 
    
         
            -
                    doc = (content.is_a?( 
     | 
| 
       335 
     | 
    
         
            -
             
     | 
| 
       336 
     | 
    
         
            -
                    entry = doc. 
     | 
| 
      
 367 
     | 
    
         
            +
                    doc = (content.is_a?(Nokogiri::XML::Document)) ? content : Nokogiri::XML(content)
         
     | 
| 
      
 368 
     | 
    
         
            +
             
     | 
| 
      
 369 
     | 
    
         
            +
                    entry = doc.at "entry"
         
     | 
| 
       337 
370 
     | 
    
         
             
                    parse_entry(entry)
         
     | 
| 
       338 
371 
     | 
    
         
             
                  end
         
     | 
| 
       339 
372 
     | 
    
         | 
| 
       340 
373 
     | 
    
         
             
                  protected
         
     | 
| 
       341 
374 
     | 
    
         
             
                  def parse_entry(entry)
         
     | 
| 
       342 
     | 
    
         
            -
                    video_id = entry. 
     | 
| 
       343 
     | 
    
         
            -
                    published_at 
     | 
| 
       344 
     | 
    
         
            -
                     
     | 
| 
      
 375 
     | 
    
         
            +
                    video_id = entry.at("id").text
         
     | 
| 
      
 376 
     | 
    
         
            +
                    published_at = entry.at("published") ? Time.parse(entry.at("published").text) : nil
         
     | 
| 
      
 377 
     | 
    
         
            +
                    uploaded_at = entry.at_xpath("media:group/yt:uploaded") ? Time.parse(entry.at_xpath("media:group/yt:uploaded").text) : nil
         
     | 
| 
      
 378 
     | 
    
         
            +
                    updated_at = entry.at("updated") ? Time.parse(entry.at("updated").text) : nil
         
     | 
| 
       345 
379 
     | 
    
         | 
| 
       346 
380 
     | 
    
         
             
                    # parse the category and keyword lists
         
     | 
| 
       347 
381 
     | 
    
         
             
                    categories = []
         
     | 
| 
       348 
382 
     | 
    
         
             
                    keywords = []
         
     | 
| 
       349 
     | 
    
         
            -
                    entry. 
     | 
| 
      
 383 
     | 
    
         
            +
                    entry.css("category").each do |category|
         
     | 
| 
       350 
384 
     | 
    
         
             
                      # determine if  it's really a category, or just a keyword
         
     | 
| 
       351 
     | 
    
         
            -
                      scheme = category 
     | 
| 
      
 385 
     | 
    
         
            +
                      scheme = category["scheme"]
         
     | 
| 
       352 
386 
     | 
    
         
             
                      if (scheme =~ /\/categories\.cat$/)
         
     | 
| 
       353 
387 
     | 
    
         
             
                        # it's a category
         
     | 
| 
       354 
388 
     | 
    
         
             
                        categories << YouTubeIt::Model::Category.new(
         
     | 
| 
       355 
     | 
    
         
            -
                                        :term => category 
     | 
| 
       356 
     | 
    
         
            -
                                        :label => category 
     | 
| 
      
 389 
     | 
    
         
            +
                                        :term => category["term"],
         
     | 
| 
      
 390 
     | 
    
         
            +
                                        :label => category["label"])
         
     | 
| 
       357 
391 
     | 
    
         | 
| 
       358 
392 
     | 
    
         
             
                      elsif (scheme =~ /\/keywords\.cat$/)
         
     | 
| 
       359 
393 
     | 
    
         
             
                        # it's a keyword
         
     | 
| 
       360 
     | 
    
         
            -
                        keywords << category 
     | 
| 
      
 394 
     | 
    
         
            +
                        keywords << category["term"]
         
     | 
| 
       361 
395 
     | 
    
         
             
                      end
         
     | 
| 
       362 
396 
     | 
    
         
             
                    end
         
     | 
| 
       363 
397 
     | 
    
         | 
| 
       364 
     | 
    
         
            -
                    title = entry. 
     | 
| 
       365 
     | 
    
         
            -
                    html_content = entry. 
     | 
| 
      
 398 
     | 
    
         
            +
                    title = entry.at("title").text
         
     | 
| 
      
 399 
     | 
    
         
            +
                    html_content = nil #entry.at("content") ? entry.at("content").text : nil
         
     | 
| 
       366 
400 
     | 
    
         | 
| 
       367 
401 
     | 
    
         
             
                    # parse the author
         
     | 
| 
       368 
     | 
    
         
            -
                    author_element = entry. 
     | 
| 
      
 402 
     | 
    
         
            +
                    author_element = entry.at("author")
         
     | 
| 
       369 
403 
     | 
    
         
             
                    author = nil
         
     | 
| 
       370 
404 
     | 
    
         
             
                    if author_element
         
     | 
| 
       371 
405 
     | 
    
         
             
                      author = YouTubeIt::Model::Author.new(
         
     | 
| 
       372 
     | 
    
         
            -
                                 :name => author_element. 
     | 
| 
       373 
     | 
    
         
            -
                                 :uri => author_element. 
     | 
| 
      
 406 
     | 
    
         
            +
                                 :name => author_element.at("name").text,
         
     | 
| 
      
 407 
     | 
    
         
            +
                                 :uri => author_element.at("uri").text)
         
     | 
| 
       374 
408 
     | 
    
         
             
                    end
         
     | 
| 
       375 
     | 
    
         
            -
                    media_group = entry. 
     | 
| 
      
 409 
     | 
    
         
            +
                    media_group = entry.at_xpath('media:group')
         
     | 
| 
       376 
410 
     | 
    
         | 
| 
       377 
411 
     | 
    
         
             
                    ytid = nil
         
     | 
| 
       378 
     | 
    
         
            -
                    unless media_group. 
     | 
| 
       379 
     | 
    
         
            -
                      ytid = media_group. 
     | 
| 
       380 
     | 
    
         
            -
                    end 
     | 
| 
      
 412 
     | 
    
         
            +
                    unless media_group.at_xpath("yt:videoid").nil?
         
     | 
| 
      
 413 
     | 
    
         
            +
                      ytid = media_group.at_xpath("yt:videoid").text
         
     | 
| 
      
 414 
     | 
    
         
            +
                    end
         
     | 
| 
       381 
415 
     | 
    
         | 
| 
       382 
416 
     | 
    
         
             
                    # if content is not available on certain region, there is no media:description, media:player or yt:duration
         
     | 
| 
       383 
417 
     | 
    
         
             
                    description = ""
         
     | 
| 
       384 
     | 
    
         
            -
                    unless media_group. 
     | 
| 
       385 
     | 
    
         
            -
                      description = media_group. 
     | 
| 
      
 418 
     | 
    
         
            +
                    unless media_group.at_xpath("media:description").nil?
         
     | 
| 
      
 419 
     | 
    
         
            +
                      description = media_group.at_xpath("media:description").text
         
     | 
| 
       386 
420 
     | 
    
         
             
                    end
         
     | 
| 
       387 
421 
     | 
    
         | 
| 
       388 
422 
     | 
    
         
             
                    # if content is not available on certain region, there is no media:description, media:player or yt:duration
         
     | 
| 
       389 
423 
     | 
    
         
             
                    duration = 0
         
     | 
| 
       390 
     | 
    
         
            -
                    unless media_group. 
     | 
| 
       391 
     | 
    
         
            -
                      duration = media_group. 
     | 
| 
      
 424 
     | 
    
         
            +
                    unless media_group.at_xpath("yt:duration").nil?
         
     | 
| 
      
 425 
     | 
    
         
            +
                      duration = media_group.at_xpath("yt:duration")["seconds"].to_i
         
     | 
| 
       392 
426 
     | 
    
         
             
                    end
         
     | 
| 
       393 
427 
     | 
    
         | 
| 
       394 
428 
     | 
    
         
             
                    # if content is not available on certain region, there is no media:description, media:player or yt:duration
         
     | 
| 
       395 
429 
     | 
    
         
             
                    player_url = ""
         
     | 
| 
       396 
     | 
    
         
            -
                    unless media_group. 
     | 
| 
       397 
     | 
    
         
            -
                      player_url = media_group. 
     | 
| 
      
 430 
     | 
    
         
            +
                    unless media_group.at_xpath("media:player").nil?
         
     | 
| 
      
 431 
     | 
    
         
            +
                      player_url = media_group.at_xpath("media:player")["url"]
         
     | 
| 
       398 
432 
     | 
    
         
             
                    end
         
     | 
| 
       399 
433 
     | 
    
         | 
| 
       400 
     | 
    
         
            -
                    unless media_group. 
     | 
| 
       401 
     | 
    
         
            -
                      widescreen = media_group. 
     | 
| 
      
 434 
     | 
    
         
            +
                    unless media_group.at_xpath("yt:aspectRatio").nil?
         
     | 
| 
      
 435 
     | 
    
         
            +
                      widescreen = media_group.at_xpath("yt:aspectRatio").text == 'widescreen' ? true : false
         
     | 
| 
       402 
436 
     | 
    
         
             
                    end
         
     | 
| 
       403 
437 
     | 
    
         | 
| 
       404 
438 
     | 
    
         
             
                    media_content = []
         
     | 
| 
       405 
     | 
    
         
            -
                    media_group. 
     | 
| 
      
 439 
     | 
    
         
            +
                    media_group.xpath("media:content").each do |mce|
         
     | 
| 
       406 
440 
     | 
    
         
             
                      media_content << parse_media_content(mce)
         
     | 
| 
       407 
441 
     | 
    
         
             
                    end
         
     | 
| 
       408 
442 
     | 
    
         | 
| 
       409 
443 
     | 
    
         
             
                    # parse thumbnails
         
     | 
| 
       410 
444 
     | 
    
         
             
                    thumbnails = []
         
     | 
| 
       411 
     | 
    
         
            -
                    media_group. 
     | 
| 
      
 445 
     | 
    
         
            +
                    media_group.xpath("media:thumbnail").each do |thumb_element|
         
     | 
| 
       412 
446 
     | 
    
         
             
                      # TODO: convert time HH:MM:ss string to seconds?
         
     | 
| 
       413 
447 
     | 
    
         
             
                      thumbnails << YouTubeIt::Model::Thumbnail.new(
         
     | 
| 
       414 
     | 
    
         
            -
                                      :url    => thumb_element 
     | 
| 
       415 
     | 
    
         
            -
                                      :height => thumb_element 
     | 
| 
       416 
     | 
    
         
            -
                                      :width  => thumb_element 
     | 
| 
       417 
     | 
    
         
            -
                                      :time   => thumb_element 
     | 
| 
      
 448 
     | 
    
         
            +
                                      :url    => thumb_element["url"],
         
     | 
| 
      
 449 
     | 
    
         
            +
                                      :height => thumb_element["height"].to_i,
         
     | 
| 
      
 450 
     | 
    
         
            +
                                      :width  => thumb_element["width"].to_i,
         
     | 
| 
      
 451 
     | 
    
         
            +
                                      :time   => thumb_element["time"])
         
     | 
| 
       418 
452 
     | 
    
         
             
                    end
         
     | 
| 
       419 
453 
     | 
    
         | 
| 
       420 
     | 
    
         
            -
                    rating_element = entry. 
     | 
| 
       421 
     | 
    
         
            -
                    extended_rating_element = entry. 
     | 
| 
      
 454 
     | 
    
         
            +
                    rating_element = entry.at_xpath("gd:rating")
         
     | 
| 
      
 455 
     | 
    
         
            +
                    extended_rating_element = entry.at_xpath("yt:rating")
         
     | 
| 
       422 
456 
     | 
    
         | 
| 
       423 
457 
     | 
    
         
             
                    rating = nil
         
     | 
| 
       424 
458 
     | 
    
         
             
                    if rating_element
         
     | 
| 
       425 
459 
     | 
    
         
             
                      rating_values = {
         
     | 
| 
       426 
     | 
    
         
            -
                        :min         => rating_element 
     | 
| 
       427 
     | 
    
         
            -
                        :max         => rating_element 
     | 
| 
       428 
     | 
    
         
            -
                        :rater_count => rating_element 
     | 
| 
       429 
     | 
    
         
            -
                        :average     => rating_element 
     | 
| 
      
 460 
     | 
    
         
            +
                        :min         => rating_element["min"].to_i,
         
     | 
| 
      
 461 
     | 
    
         
            +
                        :max         => rating_element["max"].to_i,
         
     | 
| 
      
 462 
     | 
    
         
            +
                        :rater_count => rating_element["numRaters"].to_i,
         
     | 
| 
      
 463 
     | 
    
         
            +
                        :average     => rating_element["average"].to_f
         
     | 
| 
       430 
464 
     | 
    
         
             
                      }
         
     | 
| 
       431 
465 
     | 
    
         | 
| 
       432 
466 
     | 
    
         
             
                      if extended_rating_element
         
     | 
| 
       433 
     | 
    
         
            -
                        rating_values[:likes] = extended_rating_element 
     | 
| 
       434 
     | 
    
         
            -
                        rating_values[:dislikes] = extended_rating_element 
     | 
| 
      
 467 
     | 
    
         
            +
                        rating_values[:likes] = extended_rating_element["numLikes"].to_i
         
     | 
| 
      
 468 
     | 
    
         
            +
                        rating_values[:dislikes] = extended_rating_element["numDislikes"].to_i
         
     | 
| 
       435 
469 
     | 
    
         
             
                      end
         
     | 
| 
       436 
470 
     | 
    
         | 
| 
       437 
471 
     | 
    
         
             
                      rating = YouTubeIt::Model::Rating.new(rating_values)
         
     | 
| 
       438 
472 
     | 
    
         
             
                    end
         
     | 
| 
       439 
473 
     | 
    
         | 
| 
       440 
     | 
    
         
            -
                    if (el = entry. 
     | 
| 
       441 
     | 
    
         
            -
                      view_count, favorite_count = el 
     | 
| 
      
 474 
     | 
    
         
            +
                    if (el = entry.at_xpath("yt:statistics"))
         
     | 
| 
      
 475 
     | 
    
         
            +
                      view_count, favorite_count = el["viewCount"].to_i, el["favoriteCount"].to_i
         
     | 
| 
       442 
476 
     | 
    
         
             
                    else
         
     | 
| 
       443 
477 
     | 
    
         
             
                      view_count, favorite_count = 0,0
         
     | 
| 
       444 
478 
     | 
    
         
             
                    end
         
     | 
| 
       445 
479 
     | 
    
         | 
| 
       446 
     | 
    
         
            -
                     
     | 
| 
       447 
     | 
    
         
            -
                     
     | 
| 
      
 480 
     | 
    
         
            +
                    comment_feed = entry.at_xpath('gd:comments/gd:feedLink[@rel="http://gdata.youtube.com/schemas/2007#comments"]')
         
     | 
| 
      
 481 
     | 
    
         
            +
                    comment_count = comment_feed ? comment_feed['countHint'].to_i : 0
         
     | 
| 
      
 482 
     | 
    
         
            +
                    #puts comment_count.inspect
         
     | 
| 
      
 483 
     | 
    
         
            +
             
     | 
| 
      
 484 
     | 
    
         
            +
                    access_control = entry.xpath('yt:accessControl').map do |e|
         
     | 
| 
      
 485 
     | 
    
         
            +
                      { e['action'] => e['permission'] }
         
     | 
| 
      
 486 
     | 
    
         
            +
                    end.compact.reduce({},:merge)
         
     | 
| 
       448 
487 
     | 
    
         | 
| 
       449 
     | 
    
         
            -
                     
     | 
| 
       450 
     | 
    
         
            -
             
     | 
| 
       451 
     | 
    
         
            -
             
     | 
| 
      
 488 
     | 
    
         
            +
                    noembed     = entry.at_xpath("yt:noembed") ? true : false
         
     | 
| 
      
 489 
     | 
    
         
            +
                    safe_search = entry.at_xpath("media:rating") ? true : false
         
     | 
| 
      
 490 
     | 
    
         
            +
             
     | 
| 
      
 491 
     | 
    
         
            +
                    if entry.namespaces['xmlns:georss'] and where = entry.at_xpath("georss:where")
         
     | 
| 
      
 492 
     | 
    
         
            +
                      position = where.at_xpath("gml:Point").at_xpath("gml:pos").text
         
     | 
| 
      
 493 
     | 
    
         
            +
                      latitude, longitude = position.split.map &:to_f
         
     | 
| 
       452 
494 
     | 
    
         
             
                    end
         
     | 
| 
       453 
     | 
    
         
            -
             
     | 
| 
       454 
     | 
    
         
            -
                     
     | 
| 
       455 
     | 
    
         
            -
             
     | 
| 
       456 
     | 
    
         
            -
             
     | 
| 
       457 
     | 
    
         
            -
                       
     | 
| 
       458 
     | 
    
         
            -
                         
     | 
| 
       459 
     | 
    
         
            -
             
     | 
| 
       460 
     | 
    
         
            -
             
     | 
| 
       461 
     | 
    
         
            -
             
     | 
| 
       462 
     | 
    
         
            -
             
     | 
| 
       463 
     | 
    
         
            -
             
     | 
| 
      
 495 
     | 
    
         
            +
             
     | 
| 
      
 496 
     | 
    
         
            +
                    if entry.namespaces['xmlns:app']
         
     | 
| 
      
 497 
     | 
    
         
            +
                      control = entry.at_xpath("app:control")
         
     | 
| 
      
 498 
     | 
    
         
            +
                      state = { :name => "published" }
         
     | 
| 
      
 499 
     | 
    
         
            +
                      if control && control.at_xpath("yt:state")
         
     | 
| 
      
 500 
     | 
    
         
            +
                        state = {
         
     | 
| 
      
 501 
     | 
    
         
            +
                          :name        => control.at_xpath("yt:state")["name"],
         
     | 
| 
      
 502 
     | 
    
         
            +
                          :reason_code => control.at_xpath("yt:state")["reasonCode"],
         
     | 
| 
      
 503 
     | 
    
         
            +
                          :help_url    => control.at_xpath("yt:state")["helpUrl"],
         
     | 
| 
      
 504 
     | 
    
         
            +
                          :copy        => control.at_xpath("yt:state").text
         
     | 
| 
      
 505 
     | 
    
         
            +
                        }
         
     | 
| 
      
 506 
     | 
    
         
            +
                      end
         
     | 
| 
       464 
507 
     | 
    
         
             
                    end
         
     | 
| 
       465 
508 
     | 
    
         | 
| 
      
 509 
     | 
    
         
            +
                    insight_uri = (entry.at_xpath('xmlns:link[@rel="http://gdata.youtube.com/schemas/2007#insight.views"]')['href'] rescue nil)
         
     | 
| 
      
 510 
     | 
    
         
            +
             
     | 
| 
      
 511 
     | 
    
         
            +
                    perm_private = media_group.at_xpath("yt:private") ? true : false
         
     | 
| 
      
 512 
     | 
    
         
            +
             
     | 
| 
       466 
513 
     | 
    
         
             
                    YouTubeIt::Model::Video.new(
         
     | 
| 
       467 
514 
     | 
    
         
             
                      :video_id       => video_id,
         
     | 
| 
       468 
515 
     | 
    
         
             
                      :published_at   => published_at,
         
     | 
| 
       469 
516 
     | 
    
         
             
                      :updated_at     => updated_at,
         
     | 
| 
      
 517 
     | 
    
         
            +
                      :uploaded_at    => uploaded_at,
         
     | 
| 
       470 
518 
     | 
    
         
             
                      :categories     => categories,
         
     | 
| 
       471 
519 
     | 
    
         
             
                      :keywords       => keywords,
         
     | 
| 
       472 
520 
     | 
    
         
             
                      :title          => title,
         
     | 
| 
         @@ -480,24 +528,27 @@ class YouTubeIt 
     | 
|
| 
       480 
528 
     | 
    
         
             
                      :rating         => rating,
         
     | 
| 
       481 
529 
     | 
    
         
             
                      :view_count     => view_count,
         
     | 
| 
       482 
530 
     | 
    
         
             
                      :favorite_count => favorite_count,
         
     | 
| 
      
 531 
     | 
    
         
            +
                      :comment_count  => comment_count,
         
     | 
| 
      
 532 
     | 
    
         
            +
                      :access_control => access_control,
         
     | 
| 
       483 
533 
     | 
    
         
             
                      :widescreen     => widescreen,
         
     | 
| 
       484 
534 
     | 
    
         
             
                      :noembed        => noembed,
         
     | 
| 
       485 
     | 
    
         
            -
                      : 
     | 
| 
       486 
     | 
    
         
            -
                      :where          => where,
         
     | 
| 
      
 535 
     | 
    
         
            +
                      :safe_search    => safe_search,
         
     | 
| 
       487 
536 
     | 
    
         
             
                      :position       => position,
         
     | 
| 
       488 
537 
     | 
    
         
             
                      :latitude       => latitude,
         
     | 
| 
       489 
538 
     | 
    
         
             
                      :longitude      => longitude,
         
     | 
| 
       490 
539 
     | 
    
         
             
                      :state          => state,
         
     | 
| 
       491 
     | 
    
         
            -
                      : 
     | 
| 
      
 540 
     | 
    
         
            +
                      :insight_uri    => insight_uri,
         
     | 
| 
      
 541 
     | 
    
         
            +
                      :unique_id      => ytid,
         
     | 
| 
      
 542 
     | 
    
         
            +
                      :perm_private   => perm_private)
         
     | 
| 
       492 
543 
     | 
    
         
             
                  end
         
     | 
| 
       493 
544 
     | 
    
         | 
| 
       494 
     | 
    
         
            -
                  def parse_media_content ( 
     | 
| 
       495 
     | 
    
         
            -
                    content_url =  
     | 
| 
       496 
     | 
    
         
            -
                    format_code =  
     | 
| 
      
 545 
     | 
    
         
            +
                  def parse_media_content (elem)
         
     | 
| 
      
 546 
     | 
    
         
            +
                    content_url = elem["url"]
         
     | 
| 
      
 547 
     | 
    
         
            +
                    format_code = elem["format"].to_i
         
     | 
| 
       497 
548 
     | 
    
         
             
                    format = YouTubeIt::Model::Video::Format.by_code(format_code)
         
     | 
| 
       498 
     | 
    
         
            -
                    duration =  
     | 
| 
       499 
     | 
    
         
            -
                    mime_type =  
     | 
| 
       500 
     | 
    
         
            -
                    default = ( 
     | 
| 
      
 549 
     | 
    
         
            +
                    duration = elem["duration"].to_i
         
     | 
| 
      
 550 
     | 
    
         
            +
                    mime_type = elem["type"]
         
     | 
| 
      
 551 
     | 
    
         
            +
                    default = (elem["isDefault"] == "true")
         
     | 
| 
       501 
552 
     | 
    
         | 
| 
       502 
553 
     | 
    
         
             
                    YouTubeIt::Model::Content.new(
         
     | 
| 
       503 
554 
     | 
    
         
             
                      :url       => content_url,
         
     | 
| 
         @@ -513,16 +564,16 @@ class YouTubeIt 
     | 
|
| 
       513 
564 
     | 
    
         
             
                private
         
     | 
| 
       514 
565 
     | 
    
         
             
                  def parse_content(content)
         
     | 
| 
       515 
566 
     | 
    
         
             
                    videos  = []
         
     | 
| 
       516 
     | 
    
         
            -
                    doc     =  
     | 
| 
       517 
     | 
    
         
            -
                    feed    = doc. 
     | 
| 
      
 567 
     | 
    
         
            +
                    doc     = Nokogiri::XML(content)
         
     | 
| 
      
 568 
     | 
    
         
            +
                    feed    = doc.at "feed"
         
     | 
| 
       518 
569 
     | 
    
         
             
                    if feed
         
     | 
| 
       519 
     | 
    
         
            -
                      feed_id            = feed. 
     | 
| 
       520 
     | 
    
         
            -
                      updated_at         = Time.parse(feed. 
     | 
| 
       521 
     | 
    
         
            -
                      total_result_count = feed. 
     | 
| 
       522 
     | 
    
         
            -
                      offset             = feed. 
     | 
| 
       523 
     | 
    
         
            -
                      max_result_count   = feed. 
     | 
| 
      
 570 
     | 
    
         
            +
                      feed_id            = feed.at("id").text
         
     | 
| 
      
 571 
     | 
    
         
            +
                      updated_at         = Time.parse(feed.at("updated").text)
         
     | 
| 
      
 572 
     | 
    
         
            +
                      total_result_count = feed.at_xpath("openSearch:totalResults").text.to_i
         
     | 
| 
      
 573 
     | 
    
         
            +
                      offset             = feed.at_xpath("openSearch:startIndex").text.to_i
         
     | 
| 
      
 574 
     | 
    
         
            +
                      max_result_count   = feed.at_xpath("openSearch:itemsPerPage").text.to_i
         
     | 
| 
       524 
575 
     | 
    
         | 
| 
       525 
     | 
    
         
            -
                      feed. 
     | 
| 
      
 576 
     | 
    
         
            +
                      feed.css("entry").each do |entry|
         
     | 
| 
       526 
577 
     | 
    
         
             
                        videos << parse_entry(entry)
         
     | 
| 
       527 
578 
     | 
    
         
             
                      end
         
     | 
| 
       528 
579 
     | 
    
         
             
                    end
         
     |