<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>generators/youtube_model/templates/config.yml</filename>
    </added>
    <added>
      <filename>generators/youtube_model/templates/initializer.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -10,10 +10,18 @@ to solve this though.
 
 Just apply the patch to your frozen copy of rails:
 
-  curl http://rails.lighthouseapp.com/attachments/46005/accept_http_header.diff | git am
+  curl http://rails.lighthouseapp.com/attachments/46685/http_accept_header.diff | git am
 
 See details &quot;here&quot;:http://groups.google.com/group/rubyonrails-core/browse_thread/thread/38a853b997202b3
 
+**Note about wikis and docs**
+
+Currently, the wikis are empty. So I'd appreciate if you want to contribute with wikis documentation; just drop me
+a line at edgar.js[at]gmail.com.
+
+But, it doesn't mean there isn't enough documentation. The full plugin is _rdoced_ so you just can @rake rdoc@ and
+check the details.
+
 *********************************************************************
 
 h2. Repository
@@ -28,15 +36,19 @@ Simply as:
 
   ./script/plugin install git://github.com/edgarjs/youtube-model.git
 
-h3. Generating the model
+h3. Generating the system
 
 The plugin includes a generator to create a model based on ActiveResource
 
   ./script/generate youtube_model &lt;ModelName&gt;
 
-This generator will create a file under the app/models directory. It is not an ActiveRecord model but an
-ActiveResource. (To see more about ActiveResource check out the
-&quot;Rails API&quot;:http://api.rubyonrails.org/classes/ActiveResource.html
+This generator will create four files:
+* An ActiveResource based model under app/models directory.
+* A yaml configuration file under config directory.
+* An initializer that loads the configuration file, under config/initializers directory.
+
+And that's all, but be sure to check the configuration file to set up your Developer and Client Keys.
+You can get these keys at the &quot;YouTube APIs and Tools&quot;:http://code.google.com/apis/youtube/dashboard/ page.
 
 h3. Listing videos
 
@@ -63,7 +75,7 @@ The returned model instance has a main mehod: **videos**, wich is more than an a
 **Example**
 
   &lt;pre&gt;&lt;code&gt;
-  # --controller--
+  # VideosController
   def index
     @youtube = YouTube.find('ruby on rails', :max_results =&gt; 5)
   end
@@ -72,13 +84,11 @@ The returned model instance has a main mehod: **videos**, wich is more than an a
     @video = YouTube.find_by_id(params[:id])
   end
   
-  # --views--
-  
-  # index.html.erb:
+  # app/views/videos/index.html.erb
   &lt;p&gt;&lt;%= image_tag @youtube.logo %&gt;&lt;/p&gt;
   &lt;h1&gt;&lt;%= @youtube.title %&gt;&lt;/h1&gt;
   &lt;p&gt;&lt;%= &quot;Displaying #{@youtube.startIndex} - #{@youtube.itemsPerPage} of #{@youtube.totalResults}&quot; %&gt;&lt;/p&gt;
-  &lt;p&gt;&lt;%= link_to 'Upload', new_video_path %&gt;&lt;/p&gt;
+  &lt;p&gt;&lt;%= link_to 'Upload', youtube_auth_url(new_video_url) %&gt;&lt;/p&gt;
   &lt;%- for video in @youtube.videos -%&gt;
     &lt;strong&gt;&lt;%= video.title %&gt;&lt;/strong&gt; &lt;small&gt;in &lt;%= video.group.category %&gt;&lt;/small&gt;
     by &lt;%= link_to video.author.name, &quot;http://youtube.com/#{video.author.name}&quot; %&gt;&lt;br /&gt;
@@ -88,18 +98,86 @@ The returned model instance has a main mehod: **videos**, wich is more than an a
     &lt;p&gt;&amp;nbsp;&lt;/p&gt;
   &lt;%- end -%&gt;
   
-  # show.html.erb
+  # app/views/videos/show.html.erb
   &lt;h1&gt;&lt;%= @video.title %&gt;&lt;/h1&gt;
   &lt;em&gt;by &lt;%= link_to @video.author.name, &quot;http://youtube.com/#{@video.author.name}&quot; %&gt;&lt;/em&gt;
   &lt;p&gt;&lt;%= youtube_embed @video %&gt;&lt;/p&gt;
   &lt;%= link_to 'Back', videos_path %&gt;
+  &lt;/code&gt;&lt;/pre&gt;
 
 As you can see, the @youtube_embed@ method is used to display a video.
 
 h3. Uploading videos
 
-TODO
+As seen in the @index@ example above, there is a helper named @youtube_auth_url@ wich generates an url to the
+YouTube authentication page. Pass another url as param to wich be redirected after authentication.
+This helper method takes the session and secure options from the configuration file. See the details of this options
+at the &quot;YouTube API&quot;:http://code.google.com/apis/youtube/developers_guide_protocol.html#AuthSub_Authentication
+
+Upload process has two steps:
+# Meta-info for the video.
+# File choose.
+
+So basically we have two actions in our controller to upload a video. Here's a quick code example:
+
+  &lt;pre&gt;&lt;code&gt;
+  # routes.rb
+  map.resources :videos, :new =&gt; {:upload =&gt; :post}
+  
+  # VideosController
+  def new
+    @categories ||= YouTube.categories_collection
+  end
+  
+  def upload
+    @upload_info = YouTube.get_upload_url(params[:video])
+  end
+  
+  # app/views/videos/new.html.erb
+  &lt;% form_for 'video', :url =&gt; upload_new_video_path do |f| %&gt;
+    &lt;%= f.hidden_field :auth_sub, :value =&gt; params[:token] %&gt;
+    &lt;p&gt;&lt;%= f.label :title %&gt;&lt;br /&gt;
+    &lt;%= f.text_field :title %&gt;&lt;/p&gt;
+  
+    &lt;p&gt;&lt;%= f.label :description %&gt;&lt;br /&gt;
+    &lt;%= f.text_area :description, :rows =&gt; 10 %&gt;&lt;/p&gt;
+  
+    &lt;p&gt;&lt;%= f.label :category %&gt;&lt;br /&gt;
+    &lt;%= f.select :category, @categories %&gt;&lt;/p&gt;
+  
+    &lt;p&gt;&lt;%= f.label :keywords %&gt;&lt;br /&gt;
+    &lt;%= f.text_field :keywords %&gt;&lt;/p&gt;
+  
+    &lt;p&gt;&lt;%= f.submit 'Continue to Step 2' %&gt;&lt;/p&gt;
+  &lt;% end %&gt;
+  
+  # app/views/videos/upload.html.erb
+  &lt;% form_tag @upload_info[:url], :multipart =&gt; true do %&gt;
+    &lt;%= hidden_field_tag :token, :value =&gt; @upload_info[:token] %&gt;
+    &lt;p&gt;&lt;%= label_tag :file %&gt;&lt;br /&gt;
+    &lt;%= file_field_tag :file %&gt;&lt;/p&gt;
+    &lt;p&gt;&lt;%= submit_tag 'Upload video' %&gt;&lt;/p&gt;
+  &lt;% end %&gt;
+  &lt;/code&gt;&lt;/pre&gt;
+
+Pay special attention to the routes file, I've added a new route called @:upload@ so I can use it
+in the first step to set the form post url by calling @upload_new_video_path@.
+Also don't forget to set @:multipart =&gt; true@ in the second step.
+
+Very easy isn't it? Yep, that is all.
+
+And for a more specific speech... the class method @get_upload_url@ receives a hash containing
+the meta-info of the first step, and returns a hash with the upload url and token.
+
+For extra information don't forget to read the &quot;wikis&quot;:http://github.com/edgarjs/youtube-model/wikis
+or if you wanna go further just generate the rdoc for the plugin, it will be uber helpful.
 
 h2. Feedback
 
-I'll really appreciate your feedback, please contact me at edgar.js@gmail.com
\ No newline at end of file
+I'll really appreciate your feedback, please contact me at edgar.js[at]gmail.com
+
+h2. License
+
+This code is released under Creative Commons Attribution-Share Alike 3.0 license.
+
+!http://i.creativecommons.org/l/by-sa/3.0/88x31.png!:http://creativecommons.org/licenses/by-sa/3.0/
\ No newline at end of file</diff>
      <filename>README.textile</filename>
    </modified>
    <modified>
      <diff>@@ -1,11 +1,13 @@
 class YoutubeModelGenerator &lt; Rails::Generator::NamedBase  
   def manifest
     record do |m|
-      m.class_collisions class_path, &quot;#{class_name}&quot;
+      m.class_collisions class_path, class_name
       m.directory File.join('app/models', class_path)
       m.directory File.join('test/unit', class_path)
       m.template 'model.rb', File.join('app/models', class_path, &quot;#{file_name}.rb&quot;)
       m.template 'unit_test.rb', File.join('test/unit', class_path, &quot;#{file_name}_test.rb&quot;)
+      m.file 'config.yml', File.join('config', &quot;#{file_name}_config.yml&quot;)
+      m.template 'initializer.rb', File.join('config/initializers', &quot;#{file_name}_initalizer.rb&quot;)
     end
   end
   </diff>
      <filename>generators/youtube_model/youtube_model_generator.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 require 'you_tube_model'
 require 'you_tube_helpers'
 
-ActiveResource::Base.send(:include, Mimbles::YouTubeModel)
-ActionView::Base.send(:include, Mimbles::YouTubeModel::Helpers)
\ No newline at end of file
+ActiveResource::Base.send(:include, YouTubeModel)
+ActionView::Base.send(:include, YouTubeModel::Helpers)
\ No newline at end of file</diff>
      <filename>init.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,49 +1,58 @@
-module Mimbles # :nodoc:
-  module YouTubeModel # :nodoc:
-    module Helpers
-      DEFAULT_OPTIONS = {
-        :border =&gt; false,
-        :related =&gt; true,
-        :colors =&gt; ['2b405b', '6b8ab6'],
-        :language =&gt; 'en',
-        :width =&gt; 425, :height =&gt; 373
-      }
-      
-      # This helper returns the required html to embed a youtube video.
-      # You can customize it with the following options:
-      # * &lt;tt&gt;:border&lt;/tt&gt; Specifies if the player is bordered or not.
-      # * &lt;tt&gt;:related&lt;/tt&gt; Specifies if the player will include related videos.
-      # * &lt;tt&gt;:colors&lt;/tt&gt; Array with the desired colors of the player.
-      # * &lt;tt&gt;:language&lt;/tt&gt; Specifies the language of the player.
-      # * &lt;tt&gt;:width&lt;/tt&gt; Specifies the player's width.
-      # * &lt;tt&gt;:height&lt;/tt&gt; Specifies the player's height.
-      # 
-      # Example:
-      #   # in controller:
-      #   @top_rated = YouTube.top_rated(:today)
-      #   
-      #   # in view:
-      #   &lt;% @top_rated.videos.each do |video| -%&gt;
-      #     &lt;p&gt;&lt;%= youtube_embed video, :border =&gt; true %&gt;&lt;/p&gt;
-      #   &lt;% end -%&gt;
-      def youtube_embed(video, options = {})
-        options = DEFAULT_OPTIONS.merge(options)
-        settings = [&quot;hl=#{options[:language]}&quot;]
-        settings &lt;&lt; 'border=1' if options[:border]
-        settings &lt;&lt; 'rel=0' if options[:related]
-        unless options[:colors][0] == DEFAULT_OPTIONS[:colors][0]
-          settings &lt;&lt; &quot;color1=0x#{options[:colors][0]}&quot;
-          settings &lt;&lt; &quot;color2=0x#{options[:colors][1]}&quot;
-        end
-        config = settings.join('&amp;')
-        %Q(
-        &lt;object width=&quot;#{options[:width]}&quot; height=&quot;#{options[:height]}&quot;&gt;
-            &lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/#{video.id}&amp;#{config}&quot;&gt;&lt;/param&gt;
-            &lt;param name=&quot;wmode&quot; value=&quot;transparent&quot;&gt;&lt;/param&gt;
-            &lt;embed src=&quot;http://www.youtube.com/v/#{video.id}&amp;#{config}&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot; width=&quot;#{options[:width]}&quot; height=&quot;#{options[:height]}&quot;&gt;&lt;/embed&gt;
-        &lt;/object&gt;
-        )
-      end
+module YouTubeModel # :nodoc:
+  module Helpers
+    # This helper returns the required html to embed a youtube video.
+    # You can customize it with the following options:
+    # * &lt;tt&gt;:border&lt;/tt&gt; Specifies if the player is bordered or not.
+    # * &lt;tt&gt;:related&lt;/tt&gt; Specifies if the player will include related videos.
+    # * &lt;tt&gt;:colors&lt;/tt&gt; Array with the desired colors of the player.
+    # * &lt;tt&gt;:language&lt;/tt&gt; Specifies the language of the player.
+    # * &lt;tt&gt;:width&lt;/tt&gt; Specifies the player's width.
+    # * &lt;tt&gt;:height&lt;/tt&gt; Specifies the player's height.
+    # 
+    # Example:
+    #   # in controller:
+    #   @top_rated = YouTube.top_rated(:today)
+    #   
+    #   # in view:
+    #   &lt;% @top_rated.videos.each do |video| -%&gt;
+    #     &lt;p&gt;&lt;%= youtube_embed video, :border =&gt; true %&gt;&lt;/p&gt;
+    #   &lt;% end -%&gt;
+    def youtube_embed(video, options = {})
+      settings = {
+        :border =&gt; '0',
+        :rel =&gt; '0',
+        :color1 =&gt; '0x666666',
+        :color2 =&gt; '0x666666',
+        :hl =&gt; 'en',
+        :width =&gt; 425,
+        :height =&gt; 373
+      }.merge(options)
+    
+      params = settings.to_query
+      %Q(
+    &lt;object width=&quot;#{settings[:width]}&quot; height=&quot;#{settings[:height]}&quot;&gt;
+        &lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/#{video.id}&amp;#{params}&quot;&gt;&lt;/param&gt;
+        &lt;param name=&quot;wmode&quot; value=&quot;transparent&quot;&gt;&lt;/param&gt;
+        &lt;embed src=&quot;http://www.youtube.com/v/#{video.id}&amp;#{params}&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot; width=&quot;#{settings[:width]}&quot; height=&quot;#{settings[:height]}&quot;&gt;&lt;/embed&gt;
+    &lt;/object&gt;
+      )
     end
+  
+    # Returns a link to the authentication Google page.
+    # 
+    # Pass the new_&lt;your-controller&gt;_url or whatever url you use to the Upload's step 1
+    #
+    # Example:
+    #   &lt;%= link_to 'Upload a new video', youtube_auth_url(new_videos_url) %&gt;
+    #
+    def youtube_auth_url(next_url)
+      params = {
+        :session =&gt; YT_CONFIG['auth_sub']['session'],
+        :secure =&gt; YT_CONFIG['auth_sub']['secure'],
+        :scope =&gt; 'http://gdata.youtube.com',
+        :next =&gt; next_url
+      }
+      &quot;https://www.google.com/accounts/AuthSubRequest?#{params.to_query}&quot;
+    end 
   end
 end
\ No newline at end of file</diff>
      <filename>lib/you_tube_helpers.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,210 +1,275 @@
-module Mimbles # :nodoc:
-  module YouTubeModel # :nodoc:
-    def self.included(base)
-      base.extend ClassMethods
-    end
+module YouTubeModel # :nodoc:
+  def self.included(base)
+    base.extend ClassMethods
+  end
     
-    module ClassMethods
-      # Call this method to make an ActiveResource model ready to roll with YouTube
-      def acts_as_youtube_model
-        self.site = &quot;http://gdata.youtube.com/feeds/api&quot;
-        self.timeout = 5
+  module ClassMethods
+    # Call this method to make an ActiveResource model ready to roll with YouTube
+    def acts_as_youtube_model
+      self.site = &quot;http://gdata.youtube.com/feeds/api&quot;
+      self.timeout = 5
         
-        extend Mimbles::YouTubeModel::SingletonMethods
-        include Mimbles::YouTubeModel::InstanceMethods
-      end
+      extend Mimbles::YouTubeModel::SingletonMethods
+      include Mimbles::YouTubeModel::InstanceMethods
     end
+  end
     
-    module InstanceMethods
-      # Returns an array of +entry+, or an empty array when there's no such +entry+
-      def videos
-        if respond_to?(:entry)
-          entry.is_a?(Array) ? entry : [entry]
-        else
-          []
-        end
+  module InstanceMethods
+    # Returns an array of +entry+, or an empty array when there's no such +entry+
+    def videos
+      if respond_to?(:entry)
+        entry.is_a?(Array) ? entry : [entry]
+      else
+        []
       end
     end
+  end
     
-    module SingletonMethods
-      # Retrieve the top rated videos for a time. Valid times are:
-      # * :today (1 day)
-      # * :this_week (7 days)
-      # * :this_month (1 month)
-      # * :all_time (default)
-      def top_rated(time = :all_time)
-        request(&quot;standardfeeds/top_rated#{query_string(:time =&gt; time)}&quot;)
-      end
+  module SingletonMethods
+    # Retrieve the top rated videos for a time. Valid times are:
+    # * :today (1 day)
+    # * :this_week (7 days)
+    # * :this_month (1 month)
+    # * :all_time (default)
+    def top_rated(time = :all_time)
+      request(&quot;standardfeeds/top_rated#{query_string(:time =&gt; time)}&quot;)
+    end
       
-      # Retrieve the top favorited videos for a time. Valid times are:
-      # * :today (1 day)
-      # * :this_week (7 days)
-      # * :this_month (1 month)
-      # * :all_time (default)
-      def top_favorites(time = :all_time)
-        request(&quot;standardfeeds/top_favorites#{query_string(:time =&gt; time)}&quot;)
-      end
+    # Retrieve the top favorited videos for a time. Valid times are:
+    # * :today (1 day)
+    # * :this_week (7 days)
+    # * :this_month (1 month)
+    # * :all_time (default)
+    def top_favorites(time = :all_time)
+      request(&quot;standardfeeds/top_favorites#{query_string(:time =&gt; time)}&quot;)
+    end
       
-      # Retrieve the most viewed videos for a time. Valid times are:
-      # * :today (1 day)
-      # * :this_week (7 days)
-      # * :this_month (1 month)
-      # * :all_time (default)
-      def most_viewed(time = :all_time)
-        request(&quot;standardfeeds/most_viewed#{query_string(:time =&gt; time)}&quot;)
-      end
+    # Retrieve the most viewed videos for a time. Valid times are:
+    # * :today (1 day)
+    # * :this_week (7 days)
+    # * :this_month (1 month)
+    # * :all_time (default)
+    def most_viewed(time = :all_time)
+      request(&quot;standardfeeds/most_viewed#{query_string(:time =&gt; time)}&quot;)
+    end
       
-      # Retrieve the most recent videos for a time. Valid times are:
-      # * :today (1 day)
-      # * :this_week (7 days)
-      # * :this_month (1 month)
-      # * :all_time (default)
-      def most_recent(time = :all_time)
-        request(&quot;standardfeeds/most_recent#{query_string(:time =&gt; time)}&quot;)
-      end
+    # Retrieve the most recent videos for a time. Valid times are:
+    # * :today (1 day)
+    # * :this_week (7 days)
+    # * :this_month (1 month)
+    # * :all_time (default)
+    def most_recent(time = :all_time)
+      request(&quot;standardfeeds/most_recent#{query_string(:time =&gt; time)}&quot;)
+    end
       
-      # Retrieve the most discussed videos for a time. Valid times are:
-      # * :today (1 day)
-      # * :this_week (7 days)
-      # * :this_month (1 month)
-      # * :all_time (default)
-      def most_discussed(time = :all_time)
-        request(&quot;standardfeeds/most_discussed#{query_string(:time =&gt; time)}&quot;)
-      end
+    # Retrieve the most discussed videos for a time. Valid times are:
+    # * :today (1 day)
+    # * :this_week (7 days)
+    # * :this_month (1 month)
+    # * :all_time (default)
+    def most_discussed(time = :all_time)
+      request(&quot;standardfeeds/most_discussed#{query_string(:time =&gt; time)}&quot;)
+    end
       
-      # Retrieve the most linked videos for a time. Valid times are:
-      # * :today (1 day)
-      # * :this_week (7 days)
-      # * :this_month (1 month)
-      # * :all_time (default)
-      def most_linked(time = :all_time)
-        request(&quot;standardfeeds/most_linked#{query_string(:time =&gt; time)}&quot;)
-      end
+    # Retrieve the most linked videos for a time. Valid times are:
+    # * :today (1 day)
+    # * :this_week (7 days)
+    # * :this_month (1 month)
+    # * :all_time (default)
+    def most_linked(time = :all_time)
+      request(&quot;standardfeeds/most_linked#{query_string(:time =&gt; time)}&quot;)
+    end
       
-      # Retrieve the most responded videos for a time. Valid times are:
-      # * :today (1 day)
-      # * :this_week (7 days)
-      # * :this_month (1 month)
-      # * :all_time (default)
-      def most_responded(time = :all_time)
-        request(&quot;standardfeeds/most_responded#{query_string(:time =&gt; time)}&quot;)
-      end
+    # Retrieve the most responded videos for a time. Valid times are:
+    # * :today (1 day)
+    # * :this_week (7 days)
+    # * :this_month (1 month)
+    # * :all_time (default)
+    def most_responded(time = :all_time)
+      request(&quot;standardfeeds/most_responded#{query_string(:time =&gt; time)}&quot;)
+    end
       
-      # Retrieve the recently featured videos.
-      def recently_featured
-        request(&quot;standardfeeds/recently_featured&quot;)
-      end
+    # Retrieve the recently featured videos.
+    def recently_featured
+      request(&quot;standardfeeds/recently_featured&quot;)
+    end
       
-      # Retrieve the videos watchables on mobile.
-      def watch_on_mobile
-        request(&quot;standardfeeds/watch_on_mobile&quot;)
-      end
+    # Retrieve the videos watchables on mobile.
+    def watch_on_mobile
+      request(&quot;standardfeeds/watch_on_mobile&quot;)
+    end
       
-      # Finds videos by categories or keywords.
-      # 
-      # Capitalize words if you refer to a category.
-      # 
-      # You can use the operators +NOT+(-) and +OR+(|). For example:
-      #   find_by_category_and_tag('cats|dogs', '-rats', 'Comedy')
-      def find_by_category_and_tag(*tags_and_cats)
-        request(&quot;videos/-/#{tags_and_cats.map{ |t| CGI::escape(t) }.join('/')}&quot;)
-      end
+    # Finds videos by categories or keywords.
+    # 
+    # Capitalize words if you refer to a category.
+    # 
+    # You can use the operators +NOT+(-) and +OR+(|). For example:
+    #   find_by_category_and_tag('cats|dogs', '-rats', 'Comedy')
+    def find_by_category_and_tag(*tags_and_cats)
+      request(&quot;videos/-/#{tags_and_cats.map{ |t| CGI::escape(t) }.join('/')}&quot;)
+    end
       
-      # Finds videos by tags (keywords).
-      # 
-      # You can use the operators +NOT+(-) and +OR+(|). For example:
-      #   find_by_tag('cats|dogs', '-rats')
-      def find_by_tag(*tags)
-        url = &quot;videos/-/%7Bhttp%3A%2F%2Fgdata.youtube.com%2Fschemas%2F2007%2Fkeywords.cat%7D&quot;
-        keywords = tags.map{ |t| CGI::escape(t) }.join('/')
-        request(&quot;#{url}#{keywords}&quot;)
-      end
+    # Finds videos by tags (keywords).
+    # 
+    # You can use the operators +NOT+(-) and +OR+(|). For example:
+    #   find_by_tag('cats|dogs', '-rats')
+    def find_by_tag(*tags)
+      url = &quot;videos/-/%7Bhttp%3A%2F%2Fgdata.youtube.com%2Fschemas%2F2007%2Fkeywords.cat%7D&quot;
+      keywords = tags.map{ |t| CGI::escape(t) }.join('/')
+      request(&quot;#{url}#{keywords}&quot;)
+    end
       
-      # Finds videos by tags (keywords).
-      # 
-      # You can use the operators +NOT+(-) and +OR+(|). For example:
-      #   find_by_tag('cats|dogs', '-rats')
-      def find_by_category(*categories)
-        url = &quot;videos/-/%7Bhttp%3A%2F%2Fgdata.youtube.com%2Fschemas%2F2007%2Fcategories.cat%7D&quot;
-        keywords = categories.map{ |c| CGI::escape(c) }.join('/')
-        request(&quot;#{url}#{keywords}&quot;)
-      end
+    # Finds videos by tags (keywords).
+    # 
+    # You can use the operators +NOT+(-) and +OR+(|). For example:
+    #   find_by_tag('cats|dogs', '-rats')
+    def find_by_category(*categories)
+      url = &quot;videos/-/%7Bhttp%3A%2F%2Fgdata.youtube.com%2Fschemas%2F2007%2Fcategories.cat%7D&quot;
+      keywords = categories.map{ |c| CGI::escape(c) }.join('/')
+      request(&quot;#{url}#{keywords}&quot;)
+    end
   
-      # Find uploaded videos by a user.
-      def uploaded_by(username)
-        request(&quot;users/#{username}/uploads&quot;)
-      end
+    # Find uploaded videos by a user.
+    def uploaded_by(username)
+      request(&quot;users/#{username}/uploads&quot;)
+    end
   
-      # Comments for a video.
-      def comments_for(video)
-        request(video.comments.feedLink.href)
-      end
+    # Comments for a video.
+    def comments_for(video)
+      request(video.comments.feedLink.href)
+    end
   
-      # Related videos for a video.
-      def related_to(video)
-        request(video.link[2].href)
-      end
+    # Related videos for a video.
+    def related_to(video)
+      request(video.link[2].href)
+    end
   
-      # Responses videos for a video.
-      def responses_to(video)
-        request(video.link[1].href)
-      end
+    # Responses videos for a video.
+    def responses_to(video)
+      request(video.link[1].href)
+    end
   
-      # Find a video through a search query. Options are:
-      # * :orderby (:relevance, :published, :viewCount, :rating)
-      # * :start_index
-      # * :max_results
-      # * :author
-      # * :lr
-      # * :racy (:include, :exclude)
-      # * :restriction
-      # 
-      # See options details at {YouTube API}[http://code.google.com/apis/youtube/developers_guide_protocol.html#Searching_for_Videos]
-      # 
-      # Note: +alt+ option is still in researching because it causes some errors.
-      def find(query, options = {})
-        options[:vq] = CGI::escape(query)
-        options[:orderby] ||= :relevance
-        options.delete(:alt) # causes some errors
-        params = {}
-        options.each{ |k, v| params[k.to_s.dasherize] = v.to_s }
-        request(&quot;videos#{query_string(params)}&quot;)
-      end
+    # Find a video through a search query. Options are:
+    # * :orderby (:relevance, :published, :viewCount, :rating)
+    # * :start_index
+    # * :max_results
+    # * :author
+    # * :lr
+    # * :racy (:include, :exclude)
+    # * :restriction
+    # 
+    # See options details at {YouTube API}[http://code.google.com/apis/youtube/developers_guide_protocol.html#Searching_for_Videos]
+    # 
+    # Note: +alt+ option is still in researching because it causes some errors.
+    def find(query, options = {})
+      options[:vq] = query
+      options[:orderby] ||= :relevance
+      options.delete(:alt)
+      params = Hash[*options.stringify_keys.collect{ |k, v|
+          [k.dasherize, v] }.flatten
+      ]
+      request(&quot;videos#{query_string(params)}&quot;)
+    end
 
-      # Search for a specific video by its ID.
-      #   http://www.youtube.com/watch?v=JMDcOViViNY
-      # Here the id is: *JMDcOViViNY* NOTE: this method returns the video itself,
-      # no need to call @yt.video
-      def find_by_id(id)
-        request(&quot;videos/#{id}&quot;)
-      end
+    # Search for a specific video by its ID.
+    #   http://www.youtube.com/watch?v=JMDcOViViNY
+    # Here the id is: *JMDcOViViNY* NOTE: this method returns the video itself,
+    # no need to call @yt.video
+    def find_by_id(id)
+      request(&quot;videos/#{id}&quot;)
+    end
+    
+    # Fetchs all YouTube categories
+    def categories
+      connection.get('/schemas/2007/categories.cat')['category']
+    end
+    
+    # Returns an array with only the +label+ and +term+ attributes of categories.
+    def categories_collection
+      categories.collect { |cat|
+        [cat['label'], cat['term']]
+      }
+    end
+    
+    # Sends a POST to YouTube to get the upload url and token.
+    # 
+    # Receives a hash with the following keys:
+    # * &lt;tt&gt;:title&lt;/tt&gt; Title of the video.
+    # * &lt;tt&gt;:description&lt;/tt&gt; Description of the video.
+    # * &lt;tt&gt;:category&lt;/tt&gt; Category of the video.
+    # * &lt;tt&gt;:keywords&lt;/tt&gt; Keywords for the video.
+    # * &lt;tt&gt;:auth_sub&lt;/tt&gt; Authentication token.
+    # * &lt;tt&gt;:nexturl&lt;/tt&gt; Url to redirect after the video has been uploaded. Leave it nil to go to http://www.youtube.com/my_videos
+    # 
+    # Returns a hash with the keys:
+    # * &lt;tt&gt;:url&lt;/tt&gt; url for upload the video to.
+    # * &lt;tt&gt;:token&lt;/tt&gt; token hash necessary to upload.
+    # * &lt;tt&gt;:code&lt;/tt&gt; response code of the POST.
+    def get_upload_url(meta)
+      xml_entry = build_xml_entry(meta)
+      headers = {
+        'Authorization' =&gt; %Q(AuthSub token=&quot;#{meta[:auth_sub]}&quot;),
+        'X-GData-Client' =&gt; YT_CONFIG['auth_sub']['client_key'],
+        'X-GData-Key' =&gt; &quot;key=#{YT_CONFIG['auth_sub']['developer_key']}&quot;,
+        'Content-Length' =&gt; xml_entry.length.to_s,
+        'Content-Type' =&gt; &quot;application/atom+xml; charset=UTF-8&quot;
+      }
+      response = connection.post('/action/GetUploadToken', xml_entry, headers)
+      meta[:nexturl] ||= 'http://www.youtube.com/my_videos'
+      upload = {}
+      (Hpricot.XML(response.body)/:response).each do |elm|
+        upload[:url] = &quot;#{(elm/:url).text}?#{{:nexturl =&gt; meta[:nexturl]}.to_query}&quot;
+        upload[:token] = (elm/:token).text
+      end if response.code == &quot;200&quot;
+      upload[:code] = response.code
       
-      protected
+      upload
+    end
       
-      # Loads a response into a new Object of this class
-      def request(url)
-        url = &quot;#{self.prefix}#{url}&quot; unless url =~ /\Ahttp:/
-        new.load(extend_attributes(connection.get(url)))
-      end
+    protected
+      
+    # Loads a response into a new Object of this class
+    def request(url)
+      url = &quot;#{self.prefix}#{url}&quot; unless url =~ /\Ahttp:/
+      new.load(extend_attributes(connection.get(url, 'Accept' =&gt; '*/*')))
+    end
     
-      private
+    private
   
-      # Adds some extra keys to the +attributes+ hash
-      def extend_attributes(yt)
-        unless yt['entry'].nil?
-          (yt['entry'].is_a?(Array) ? yt['entry'] : [yt['entry']]).each { |v| scan_id(v) }
-        else
-          scan_id(yt)
-        end
-        yt
+    # Adds some extra keys to the +attributes+ hash
+    def extend_attributes(yt)
+      unless yt['entry'].nil?
+        (yt['entry'].is_a?(Array) ? yt['entry'] : [yt['entry']]).each { |v| scan_id(v) }
+      else
+        scan_id(yt)
       end
+      yt
+    end
     
-      # Renames the +id+ key to +api_id+ and leaves the simple video id on the +id+ key
-      def scan_id(attrs)
-        attrs['api_id'] = attrs['id']
-        attrs['id'] = attrs['api_id'].scan(/[\w-]+$/).to_s
-        attrs
+    # Renames the +id+ key to +api_id+ and leaves the simple video id on the
+    # +id+ key
+    def scan_id(attrs)
+      attrs['api_id'] = attrs['id']
+      attrs['id'] = attrs['api_id'].scan(/[\w-]+$/).to_s
+      attrs
+    end
+    
+    # Builds the XML content to do the POST to obtain the upload url and token.
+    def build_xml_entry(attrs)
+      xml = Builder::XmlMarkup.new(:indent =&gt; 2)
+      xml.instruct! :xml, :version =&gt; '1.0', :encoding =&gt; nil
+      xml.entry :xmlns =&gt; 'http://www.w3.org/2005/Atom',
+        'xmlns:media' =&gt; 'http://search.yahoo.com/mrss/',
+        'xmlns:yt' =&gt; 'http://gdata.youtube.com/schemas/2007' do
+        xml.media :group do
+          xml.tag! 'media:title', attrs[:title]
+          xml.media :description, attrs[:description], :type =&gt; 'plain'
+          xml.media :category, attrs[:category], :scheme =&gt; 'http://gdata.youtube.com/schemas/2007/categories.cat'
+          xml.media :category, &quot;ytm_#{YT_CONFIG['developer_tag']}&quot;, :scheme =&gt; 'http://gdata.youtube.com/schemas/2007/developertags.cat'
+          xml.tag! 'media:keywords', attrs[:keywords]
+        end
       end
+      xml.target!
     end
   end
 end
\ No newline at end of file</diff>
      <filename>lib/you_tube_model.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>README~</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>25dc651871d8ec2cce09d1b9283824e475dc89c4</id>
    </parent>
  </parents>
  <author>
    <name>Edgar J. Suarez</name>
    <email>edgar.js@gmail.com</email>
  </author>
  <url>http://github.com/edgarjs/youtube-model/commit/87417a75ff2e9a34c7315c030e5820ea6bb58fe2</url>
  <id>87417a75ff2e9a34c7315c030e5820ea6bb58fe2</id>
  <committed-date>2008-09-17T21:23:46-07:00</committed-date>
  <authored-date>2008-09-17T21:23:46-07:00</authored-date>
  <message>uploading is supported now. README completed. Version 1.0.0 functional. Need tests though</message>
  <tree>176215f283c84db5402ac713524d43011cc0d6eb</tree>
  <committer>
    <name>Edgar J. Suarez</name>
    <email>edgar.js@gmail.com</email>
  </committer>
</commit>
