Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

first import

  • Loading branch information...
commit 5c958fce6d7cc6c41e4e3d3040047de8dc30efb0 1 parent 41992e4
@sadikzzz authored
Showing with 600 additions and 0 deletions.
  1. +20 −0 MIT-LICENSE
  2. +48 −0 README
  3. +532 −0 lib/heyspread.rb
View
20 MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008 Bruno Celeste
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
48 README
@@ -0,0 +1,48 @@
+= Hey!Spread: Video Promoting Web Service
+
+ * Address: http://heyspread.com
+ * Email: bruno.celeste@particle-s.com
+ * Blog: http://particle-s.com
+ * Twitter: http://twitter.com/HeyWatch
+
+ * API documentation: http://heyspread.com/page/api-documentation
+ * Valid site names to use the API: http://heyspread.com/page/api-documentation-sites
+
+= Usage
+
+== Upload a video to YouTube and Google Video:
+
+ HeySpread::Account.api_key = "api_key"
+
+ video = HeySpread::Video.new(
+ :title => "HS test",
+ :category => "Comedy",
+ :tags => "heyspread tag testing",
+ :file => "/home/user/video.avi",
+ :description => "Test the HeySpread API"
+ )
+
+ #Set the destination sites
+ #Not required if you saved you Credentials
+ video.destinations["youtube"] = ["login", "password"]
+ video.destinations["google"] = ["email", "password"]
+
+ video.upload
+
+
+== Save YouTube credentials:
+
+ HeySpread::Credentials.save(
+ :site => "youtube",
+ :login => "testyt",
+ :password => "test"
+ )
+ => true
+
+== Track videos
+
+ track = Track.new
+ video_urls is an Array of links
+ track.video_urls << "http://youtube.com/watch?v=fsdfsd"
+ track.video_urls << "http://dailymotion.com/video/xefds"
+ video = track.save
View
532 lib/heyspread.rb
@@ -0,0 +1,532 @@
+require "net/http"
+require "rubygems"
+require "hpricot"
+require "cgi"
+
+# Hey!Spread: Video Promoting Web Service
+#
+# * Address: http://heyspread.com
+# * Email: bruno.celeste@particle-s.com
+# * Blog: http://particle-s.com
+# * Twitter: http://twitter.com/HeyWatch
+#
+# * API documentation: http://heyspread.com/page/api-documentation
+# * Valid site names to use the API: http://heyspread.com/page/api-documentation-sites
+
+module HeySpread
+ URL = "http://heyspread.com/api2" unless HeySpread.const_defined?(:URL)
+
+
+ # Authenticate your account
+ #
+ # You can find the API key in your account page
+ # http://heyspread.com/account
+ #
+ # HeySpread::Account.api_key = "api_key"
+
+ class Account
+ def self.api_key=(api_key)
+ @@api_key = api_key
+ end
+
+ def self.api_key
+ @@api_key ||= nil
+ end
+ end
+
+
+ # Manage your videos
+ #
+ # Upload a video to YouTube and Google Video:
+ #
+ # HeySpread::Account.api_key = "api_key"
+ #
+ # video = HeySpread::Video.new(
+ # :title => "HS test",
+ # :category => "Comedy",
+ # :tags => "heyspread tag testing",
+ # :file => "/home/user/video.avi",
+ # :description => "Test the HeySpread API"
+ # )
+ #
+ # # Set the destination sites
+ # # Not required if you saved you Credentials
+ # video.destinations["youtube"] = ["login", "password"]
+ # video.destinations["google"] = ["email", "password"]
+ #
+ # video.upload
+ #
+
+ class Video
+ attr_accessor :id, :title, :description, :tags, :category, :file, :url,
+ :ping, :destinations
+
+ attr_reader :links, :errors, :uploads, :status, :stat, :created_at,
+ :updated_at, :auto_stat_updated_at, :total_views
+
+
+ # Attributes:
+ #
+ # * :title
+ # * :category: can be 'Auto & vehicles', 'Comedy', 'Entertainment',
+ # 'Film & Animation', 'Gadgets & Games', 'Howto & DIY', 'Music',
+ # 'News & Politics', 'People & Blogs', 'Pets & Animals', 'Sports',
+ # 'Travel & Places'
+ # * :tags
+ # * :description
+ # * :file
+ # * :url: video URL, can be direct link, YouTube or Google Video link
+ # * :ping: when the upload is done, you'll receive all the links and errors
+ # to this HTTP address
+ # * :destinations: Must be an Hash:
+ # {"site1" => ["login", "password"], "site2" => ["login", "password"]}
+ #
+ #
+ # video = HeySpread::Video.new(:title => "HS test", :category => "Comedy",
+ # :tags => "heyspread tag testing", :file => "/home/user/video.avi",
+ # :description => "Test the HeySpread API",
+ # :destinations => {"veoh" => ["login", "password"]}
+ # )
+ #
+ # video = HeySpread::Video.new
+ # video.title = "My super video"
+ # video.description = "A cool new video"
+ # ...
+ # video.destinations["dailymotion"] = ["login", password"]
+ def initialize(attributes={})
+ @destinations = {}
+ attributes_to_instance_variables(attributes)
+ end
+
+ # return an Hash with all the attributes
+ def attributes
+ attr = {}
+ instance_variables.each do |iv|
+ attr.merge!(iv.gsub("@", "").to_sym => instance_variable_get(iv))
+ end
+
+ attr
+ end
+
+ # Upload the video on all the sites.
+ def upload
+ credentials = {}
+ if @destinations
+ @destinations.each_pair do |site, c|
+ credentials.merge!(site => "#{c[0]}:#{c[1]}")
+ end
+ end
+
+ result = HTTP.post("/video", {
+ :title => @title,
+ :description => @description,
+ :tags => @tags,
+ :category => @category,
+ :file => @file,
+ :url => @url,
+ :ping => @ping
+ }.merge(credentials)
+ )
+
+ Video.new(Video.hpricot_to_hash(result))
+ end
+
+ # Reload the video object
+ def reload
+ if @id
+ attributes_to_instance_variables(Video.find(@id).attributes)
+ end
+ self
+ end
+
+ # Restart the failed uploads
+ #
+ # HeySpread::Video.find(555).restart
+ def restart
+ Video.restart(@id)
+ end
+
+ # Delete the video from all the sites
+ #
+ # HeySpread::Video.find(555).delete
+ def delete
+ Video.delete(@id)
+ end
+
+ # Enable statistics for this video
+ #
+ # HeySpread::Video.find(555).enable_statistics
+ def enable_statistics
+ HTTP.put("/video/#{@id}", {:stat => true})
+ true
+ end
+
+ # Get the stats for this video
+ #
+ # Arguments:
+ #
+ # * :from: Eg. 2008-05-01
+ # * :to: Eg. 2008-05-03
+ # * :format: can be "png", "csv", "rss" or "xml". Default is "xml"
+ #
+ # video = HeySpread::Video.find(555)
+ # video.statistics(:from => "2008-05-08", :to => "2008-05-09")
+ #
+ # => {"2008-05-08"=>{"putfile"=>2, "revver"=>20, "youtube"=>98, "veoh"=>12},
+ # "2008-05-09"=>{"putfile"=>16, "revver"=>46, "youtube"=>115, "veoh"=>22}}
+ #
+ # To access the YouTube stats of May 8, 2008:
+ #
+ # video.statistics["2008-05-08"]["youtube"]
+ # => 98
+ #
+ # Save the statistics graphic for the current month into a file:
+ #
+ # File.open("stats.png", "wb") do |f|
+ # f.write(video.statistics(:format => "png"))
+ # end
+ def statistics(options={})
+ format = options.delete(:format) || "xml"
+ result = HTTP.get("/video/#{@id}/stats.#{format}", options)
+ if format == "xml"
+ stats = {}
+ (result/"statistic").each do |stat|
+ views = {}
+ stat.each_child do |v|
+ views.merge!(v["site"] => v.inner_html.to_i) unless v.to_s.strip.empty?
+ end
+ stats.merge!(stat["date"] => views)
+ end
+
+ stats
+ else
+ result.to_html
+ end
+ end
+
+ # Update the statistics right now
+ #
+ # HeySpread::Video.find(555).update_statistics
+ def update_statistics
+ HTTP.post("/video/#{@id}/stats")
+ true
+ end
+
+ # Find a specific video by its ID
+ #
+ # HeySpread::Video.find(555)
+ def self.find(id)
+ result = HTTP.get("/video/#{id}")
+ Video.new(hpricot_to_hash(result))
+ end
+
+ # Restart the failed uploads
+ #
+ # HeySpread::Video.restart(555)
+ def self.restart(id)
+ HTTP.post("/video/#{id}/restart")
+ true
+ end
+
+ # Delete the video from all the sites
+ #
+ # HeySpread::Video.delete(555)
+ def self.delete(id)
+ HTTP.delete("/video/#{id}")
+ true
+ end
+
+ private
+
+ def attributes_to_instance_variables(attributes) #:nodoc:
+ attributes.each_pair do |key, value|
+ instance_variable_set("@#{key}", value)
+ end
+ end
+
+ def self.hpricot_to_hash(xml) #:nodoc:
+ attributes = {}
+ attributes[:id] = (xml/"id/").to_s.to_i
+ attributes[:title] = (xml/"title/").to_s
+ attributes[:description] = (xml/"description/").to_s
+ attributes[:tags] = (xml/"tags/").to_s
+ attributes[:category] = (xml/"category/").to_s.gsub("&amp;", "&")
+ attributes[:stat] = ((xml/"stat/").to_s == "true" ? true : false)
+ attributes[:status] = (xml/"status/").to_s
+ attributes[:total_views] = (xml/"total-views/").to_s.to_i
+ attributes[:created_at] = Time.parse((xml/"created-at/").to_s)
+ attributes[:updated_at] = Time.parse((xml/"updated-at/").to_s)
+
+ stat_updated_at = (xml/"auto-stat-updated-at/").to_s
+ if ! stat_updated_at.empty?
+ attributes[:auto_stat_updated_at] = Time.parse(stat_updated_at)
+ else
+ attributes[:auto_stat_updated_at] = nil
+ end
+
+ attributes[:links] = {}
+ attributes[:errors] = {}
+ attributes[:uploads] = {}
+
+ (xml/"links/link").each do |link|
+ attributes[:links].merge!(link["site"] => link.inner_html)
+ end
+
+ (xml/"errors/error").each do |error|
+ attributes[:errors].merge!(error["site"] => error.inner_html)
+ end
+
+ (xml/"uploads/upload").each do |upload|
+ attributes[:uploads].merge!(upload["site"] => {
+ :percent => upload["percent"], :speed => upload["speed"],
+ :time_left => upload["time-left"],
+ :transfered => upload["transfered"], :total => upload["total"]
+ }
+ )
+ end
+
+ attributes
+ end
+ end
+
+
+ # Check, save and delete your credentials
+ #
+ # Check if the YouTube credentials are valid:
+ #
+ # HeySpread::Credentials.valid?(
+ # :site => "youtube",
+ # :login => "testyt",
+ # :password => "test"
+ # )
+ #
+ # => false
+ #
+ # Save YouTube credentials:
+ # Return true if they're valid and saved.
+ # Otherwise raise an HTTPError, wrong login or password
+ #
+ # HeySpread::Credentials.save(
+ # :site => "youtube",
+ # :login => "testyt",
+ # :password => "test"
+ # )
+ # => true
+ #
+ # Delete the Dailymotion credentials:
+ #
+ # HeySpread::Credentials.delete("dailymotion")
+ # => true
+ class Credentials
+ # Create or update credentials
+ # Raise HTTPError wrong login or password
+ # if the credentials are not valid
+ def self.save(credentials={})
+ HTTP.post("/credentials", credentials)
+ true
+ end
+
+ # Delete credentials for the given site
+ def self.delete(site)
+ HTTP.delete("/credentials/#{site}")
+ true
+ end
+
+ # Check if the given credentials are valid
+ def self.valid?(credentials={})
+ result = HTTP.post("/credentials/check", credentials)
+ (result/"response/valid").inner_html == "true" ? true : false
+ end
+ end
+
+
+ # Track videos
+ #
+ # track = Track.new
+ # # video_urls is an Array of links
+ # track.video_urls << "http://youtube.com/watch?v=fsdfsd"
+ # track.video_urls << "http://dailymotion.com/video/xefds"
+ #
+ # # return a Video object
+ # video = track.save
+ #
+ # # enable the stats
+ # video.enable_statistics
+ #
+ # if there is no YouTube link, you must give the title, description,
+ # category and tags
+
+ class Track
+ attr_accessor :video_urls, :title, :description, :tags, :category
+
+ # Track the given video URLS
+ #
+ # track = Track.new
+ # track.title = "my title"
+ # track.description = "my description"
+ #
+ # track = Track.new(
+ # :title => "my title",
+ # #...
+ # :video_urls => ["http://youtube.com/watch?v=dsfsd"]
+ # )
+ def initialize(options={})
+ @video_urls = []
+ options.each_pair do |k,v|
+ instance_variable_set("@#{k}", v)
+ end
+ end
+
+ # Track the given video URL
+ def <<(url)
+ @video_urls << url
+ end
+
+ # Save all the video urls and return a Video object
+ def save
+ result = HTTP.post("/track", {
+ :video_urls => @video_urls.join(" "),
+ :title => @title,
+ :description => @description,
+ :tags => @tags,
+ :category => @category
+ }
+ )
+
+ Video.new(Video.hpricot_to_hash(result))
+ end
+ end
+
+
+ # Export videos from a YouTube account to any other video sites
+ #
+ # Export all the Youtube videos of a given account to Dailymotion:
+ #
+ # export = Export.new
+ # export.youtube_account = ["login", "password"]
+ # export.destinations["dailymotion"] = ["login", "password"]
+ # export.save
+ #
+ # If you don't set the destinations, you'll use your saved Credentials
+
+ class Export
+ attr_accessor :destinations
+
+ # Set the destinations (including YouTube)
+ #
+ # export = Export.new(
+ # "youtube" => ["login", "password"],
+ # "dailymotion" => ["login", "password"]
+ # )
+ def initialize(destinations={})
+ @destinations = destinations
+ end
+
+ # Set the YouTube account
+ #
+ # export.youtube_account = ["login", "password"]
+ def youtube_account=(credentials=[])
+ @destinations["youtube"] = credentials
+ end
+
+ # Export the videos of a YouTube account to any other video sites
+ def save
+ credentials = {}
+ if @destinations
+ @destinations.each_pair do |site, c|
+ credentials.merge!(site => "#{c[0]}:#{c[1]}")
+ end
+ end
+
+ HTTP.post("/export", credentials)
+
+ true
+ end
+ end
+
+
+ class HTTPError < RuntimeError #:nodoc:
+ end
+
+ class HTTP #:nodoc:
+ %w(get post delete put).each do |m|
+ HTTP.module_eval(%(
+ def self.#{m}(path, query={})
+ request(:method => '#{m}', :path => path, :query => query)
+ end
+ ))
+ end
+
+ private
+
+ class << self
+
+ def parse(str)
+ Hpricot.XML(str)
+ end
+
+ def request(options={})
+ uri = URI.parse(HeySpread::URL)
+ options[:query].merge!(:api_key => HeySpread::Account.api_key)
+ options[:path] = uri.path + options[:path]
+
+ http = Net::HTTP.new(uri.host, uri.port)
+ if options[:query][:file].nil?
+ res = http.send_request(options[:method].to_s.upcase, options[:path],
+ query_to_string(options[:query]))
+ else
+ boundary = rand(9).to_s * 36
+ res = http.send_request(options[:method].to_s.upcase, options[:path],
+ query_to_multipart(boundary, options[:query]),
+ "Content-Type" => "multipart/form-data; boundary=" + boundary
+ )
+ end
+
+ body = parse(res.body || "")
+
+ unless res.code =~ /^[2|3]/
+ error = (body/"errors/error").map{|e| e.inner_html}.join(", ") rescue ""
+ raise(HTTPError, "#{res.message}#{'. Reason: ' + error}")
+ end
+
+ body
+ end
+
+ def query_to_multipart(boundary, attributes={}) #:nodoc:
+ file = attributes.delete(:file)
+ params = [file_to_multipart("video", File.basename(file),
+ "application/octet-stream", File.read(file))]
+
+ attributes.each_pair{|k,v| params << text_to_multipart(k.to_s, v.to_s)}
+ params.map do |p|
+ '--' + boundary + "\r\n" + p
+ end.join('') + "--" + boundary + "--\r\n"
+ end
+
+ def text_to_multipart(key,value) #:nodoc:
+ return "Content-Disposition: form-data; name=\"#{CGI::escape(key.to_s)}\"\r\n" +
+ "\r\n" +
+ "#{value}\r\n"
+ end
+
+ def file_to_multipart(key,filename,mime_type,content) #:nodoc:
+ return "Content-Disposition: form-data; name=\"#{CGI::escape(key.to_s)}\"; filename=\"#{filename}\"\r\n" +
+ "Content-Transfer-Encoding: binary\r\n" +
+ "Content-Type: #{mime_type}\r\n" +
+ "\r\n" +
+ "#{content}\r\n"
+ end
+
+ def query_to_string(query)
+ str = ""
+ query.each do |key, value|
+ str << (str.empty? ? "" : "&")
+ if ! value.to_s.empty?
+ str << "#{key}=#{CGI::escape(value.to_s)}"
+ end
+ end
+ str
+ end
+ end
+ end
+end

0 comments on commit 5c958fc

Please sign in to comment.
Something went wrong with that request. Please try again.