heywatch 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt ADDED
@@ -0,0 +1,18 @@
1
+ Manifest.txt
2
+ README.txt
3
+ Rakefile
4
+ lib/heywatch.rb
5
+ lib/heywatch/video.rb
6
+ lib/heywatch/version.rb
7
+ lib/heywatch/job.rb
8
+ lib/heywatch/ext.rb
9
+ lib/heywatch/encoded_video.rb
10
+ lib/heywatch/download.rb
11
+ lib/heywatch/discover.rb
12
+ lib/heywatch/browser.rb
13
+ lib/heywatch/base.rb
14
+ lib/heywatch/auth.rb
15
+ lib/heywatch/account.rb
16
+ setup.rb
17
+ test/test_helper.rb
18
+ test/test_heywatch.rb
data/README.txt ADDED
@@ -0,0 +1,163 @@
1
+ =Hey!Watch - Video Encoding Web Service
2
+
3
+ Hey!Watch <http://heywatch.com> provides a simple and robust encoding plateform.
4
+ The service allows developers to access a fast, scalable and inexpensive web
5
+ service to encode videos easier. The API can be easily integrated
6
+ in any web or desktop applications.
7
+
8
+ The documentation of the API can be found at http://wiki.heywatch.com/API_Documentation
9
+
10
+
11
+ ==Getting started
12
+
13
+ ===Transfer a video, encode it in ipod format and download the encoded video
14
+
15
+ require 'heywatch'
16
+ include HeyWatch
17
+
18
+ Base::establish_connection! :login => 'login', :password => 'password'
19
+
20
+ raw_video = Discover.create(:url => 'http://youtube.com/watch?v=SXcpNZCyQJw', :download => true) do |percent, total_size, received|
21
+ puts "#{percent}%"
22
+ end
23
+
24
+ ipod_format = Format.find_by_name('iPod 4:3')
25
+ encoded_video = Job.create(:video_id => raw_video.id, :format_id => ipod_format.id) do |percent|
26
+ puts "#{percent}%"
27
+ end
28
+
29
+ puts "downloading {encoded_video.title}"
30
+ path = encoded_video.download
31
+ puts "video saved in {path}"
32
+
33
+
34
+ ===Upload a video from the disk, encode it with FTP auto transfer option
35
+
36
+ raw_video = Video.create(:file => 'videos/myvideo.avi', :title => 'Funny video') do |percent, total_size, received|
37
+ puts "#{percent}%"
38
+ end
39
+
40
+ Job.create :video_id => raw_video.id, :default_format => true, :ftp_directive => 'ftp://login:pass@host.com/heywatch_vids/'
41
+
42
+
43
+ ===Generate a thumbnail
44
+
45
+ v = EncodedVideo.find(5400)
46
+ v.thumbnail :start => 15, :width => 640, :height => 480
47
+
48
+
49
+ ===Update your account
50
+
51
+ account = Account.find
52
+ account.update_attributes :ping_url_after_encode => 'http://yourhost.com/ping/encode'
53
+
54
+
55
+
56
+ ==Integration in a rails application
57
+
58
+ This short HOWTO uses the ping options. So in your HeyWatch account, you must
59
+ configure all the ping URL (except transfer for this example).
60
+
61
+ Examples:
62
+
63
+ ping_url_after_encode => http://myhost.com/ping/encode
64
+ ping_url_if_error => http://myhost.com/ping/error
65
+
66
+
67
+ ===Config
68
+
69
+ In your config/environment.rb:
70
+
71
+ require 'heywatch'
72
+ HeyWatch::Base::establish_connection! :login => 'login', :password => 'passwd'
73
+
74
+
75
+ ===Item Model
76
+
77
+ create_table "items", :force => true do |t|
78
+ t.column "title", :string, :null => false
79
+ t.column "description", :text, :null => false
80
+ t.column "created_at", :datetime
81
+ t.column "updated_at", :datetime
82
+ t.column "status", :string, :default => "working"
83
+ t.column "url", :string
84
+ t.column "meta", :text
85
+ t.column "user_id", :integer
86
+ end
87
+
88
+ In app/models/item.rb:
89
+
90
+ class Item < ActiveRecord::Base
91
+ belongs_to :user
92
+ serialize :meta
93
+ after_create :convert
94
+
95
+ # When HeyWatch send videos to your FTP,
96
+ # they will be available to this HTTP url.
97
+ def base_url
98
+ "http://myhost.com/flv/#{self.id}/"
99
+ end
100
+
101
+ # Transfer the given URL and convert the video from
102
+ # this address in format 31 (flv format). When the encode
103
+ # is done, the video will be sent to the specified FTP
104
+ # with custom path.
105
+ #
106
+ # Note item_id which is a custom field.
107
+ def convert
108
+ HeyWatch::Discover.create(
109
+ :url => self.url,
110
+ :download => true,
111
+ :item_id => self.id,
112
+ :title => self.title,
113
+ :automatic_encode => true,
114
+ :format_id => 31,
115
+ :ftp_directive => "ftp://login:passwd@myhost.com/flv/#{self.id}/"
116
+ )
117
+ end
118
+ end
119
+
120
+
121
+ ===Ping Controller
122
+
123
+ In app/controllers/ping_controller.rb:
124
+
125
+ class PingController < ApplicationController
126
+ before_filter :find_item
127
+
128
+ def encode
129
+ @encoded_video = HeyWatch::EncodedVideo.find(params[:encoded_video_id])
130
+ @full_url = @item.base_url + @encoded_video.filename
131
+ @item.status = 'finished'
132
+ @item.meta = {
133
+ :url => @full_url,
134
+ :thumb => @full_url + ".jpg",
135
+ :size => @encoded_video.specs["size"],
136
+ :mime_type => @encoded_video.specs["mime_type"],
137
+ :length => @encoded_video.specs.video["length"]
138
+ }
139
+ @item.save
140
+ @encoded_video.job.video.destroy # delete the raw video
141
+ @encoded_video.destroy # delete the encoded video
142
+ render :nothing => true
143
+ end
144
+
145
+ def error
146
+ if params[:discover_id]
147
+ error_msg = "No video link found"
148
+ else
149
+ error_msg = HeyWatch::ErrorCode[params[:error_code].to_i]
150
+ end
151
+ @item.update_attributes :status => 'error'
152
+ ItemMailer.deliver_error(error_msg, @item.user)
153
+ render :nothing => true
154
+ end
155
+
156
+ private
157
+
158
+ # item_id is a custom_field sent in Item#convert.
159
+ # Thanks to it, we can track the item.
160
+ def find_item
161
+ @item = Item.find params[:item_id]
162
+ end
163
+ end
data/Rakefile ADDED
@@ -0,0 +1,74 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ require 'fileutils'
10
+ require 'hoe'
11
+ include FileUtils
12
+ require File.join(File.dirname(__FILE__), 'lib', 'heywatch', 'version')
13
+
14
+ AUTHOR = 'Bruno Celeste' # can also be an array of Authors
15
+ EMAIL = "bruno.celeste@heywatch.com"
16
+ DESCRIPTION = "Ruby Library for HeyWatch service (http://heywatch.com)."
17
+ GEM_NAME = 'heywatch' # what ppl will type to install your gem
18
+ RUBYFORGE_PROJECT = 'heywatch' # The unix name for your project
19
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
20
+
21
+
22
+ NAME = "heywatch"
23
+ REV = nil # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
24
+ VERS = ENV['VERSION'] || (HeyWatch::VERSION::STRING + (REV ? ".#{REV}" : ""))
25
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
26
+ RDOC_OPTS = ['--quiet', '--title', 'heywatch documentation',
27
+ "--opname", "index.html",
28
+ "--line-numbers",
29
+ "--main", "README.txt",
30
+ "--inline-source"]
31
+
32
+ class Hoe
33
+ def extra_deps
34
+ @extra_deps.reject { |x| Array(x).first == 'hoe' }
35
+ end
36
+ end
37
+
38
+ # Generate all the Rake tasks
39
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
40
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
41
+ p.author = AUTHOR
42
+ p.description = DESCRIPTION
43
+ p.email = EMAIL
44
+ p.summary = DESCRIPTION
45
+ p.url = HOMEPATH
46
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
47
+ p.test_globs = ["test/**/test_*.rb"]
48
+ p.clean_globs = CLEAN #An array of file patterns to delete on clean.
49
+
50
+ # == Optional
51
+ p.extra_deps = [ ['xml-simple', '>= 1.0.0'] ] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
52
+ p.spec_extras = {:extra_rdoc_files => ["README.txt"], :rdoc_options => RDOC_OPTS} # A hash of extra values to set in the gemspec.
53
+ end
54
+
55
+
56
+ desc 'Generate website files'
57
+ task :website_generate do
58
+ Dir['website/**/*.txt'].each do |txt|
59
+ sh %{ ruby scripts/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
60
+ end
61
+ end
62
+
63
+ desc 'Upload website files to rubyforge'
64
+ task :website_upload do
65
+ config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
66
+ host = "#{config["username"]}@rubyforge.org"
67
+ remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/"
68
+ # remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
69
+ local_dir = 'website'
70
+ sh %{rsync -av #{local_dir}/ #{host}:#{remote_dir}}
71
+ end
72
+
73
+ desc 'Generate and upload website files'
74
+ task :website => [:website_generate, :website_upload]
data/lib/heywatch.rb ADDED
@@ -0,0 +1,88 @@
1
+ #--
2
+ # Copyright (c) 2007 Bruno Celeste
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require "rubygems"
25
+ require "xmlsimple"
26
+ require "cgi"
27
+
28
+ module HeyWatch
29
+ Host = "heywatch.com" unless const_defined? :Host
30
+ OutFormat = "xml" unless const_defined? :OutFormat
31
+ Resources = %w{job format download discover encoded_video video account log} unless const_defined? :Resources
32
+
33
+ # These are error codes you receive if you use ping options
34
+ ErrorCode = {
35
+ 100 => "Unknown error",
36
+ 101 => "Unsupported audio codec",
37
+ 102 => "Unsupported video codec",
38
+ 103 => "This video cannot be encoded in this format",
39
+ 104 => "Wrong settings for audio",
40
+ 105 => "Wrong settings for video",
41
+ 106 => "Cannot retrieve info from this video",
42
+ 107 => "Not a video file",
43
+ 108 => "Video too long",
44
+ 109 => "The container of this video is not supported yet",
45
+ 110 => "The audio can't be resampled",
46
+ 201 => "404 Not Found",
47
+ 202 => "Bad address",
48
+ 300 => "No more credit available"
49
+ } unless const_defined? :ErrorCode
50
+
51
+ class NotAuthorized < RuntimeError; end
52
+ class RequestError < RuntimeError; end
53
+ class ResourceNotFound < RuntimeError; end
54
+ class ServerError < RuntimeError; end
55
+ class SessionNotFound < RuntimeError; end
56
+
57
+ # Convert the XML response into Hash
58
+ def self.response(xml)
59
+ XmlSimple.xml_in(xml, {'ForceArray' => false})
60
+ end
61
+
62
+ # sanitize url
63
+ def self.sanitize_url(url)
64
+ return url.gsub(/[^a-zA-Z0-9:\/\.\-\+_\?\=&]/) {|s| CGI::escape(s)}.gsub("+", "%20")
65
+ end
66
+ end
67
+
68
+ $: << File.dirname(File.expand_path(__FILE__))
69
+
70
+ require "heywatch/ext"
71
+ require "heywatch/version"
72
+ require "heywatch/browser"
73
+ require "heywatch/auth"
74
+ require "heywatch/base"
75
+ require "heywatch/encoded_video"
76
+ require "heywatch/video"
77
+ require "heywatch/account"
78
+ require "heywatch/download"
79
+ require "heywatch/discover"
80
+ require "heywatch/job"
81
+
82
+ class Hash
83
+ include HeyWatch::CoreExtension::HashExtension
84
+ end
85
+
86
+ class Array
87
+ include HeyWatch::CoreExtension::ArrayExtension
88
+ end
@@ -0,0 +1,32 @@
1
+ module HeyWatch
2
+ class Account < Base #:nodoc:
3
+ def new_record?
4
+ false
5
+ end
6
+
7
+ def update_attributes(attributes={})
8
+ attributes.delete "account"
9
+ attributes.keys.each do |k|
10
+ attributes.merge!("user[#{k.to_s}]" => attributes[k])
11
+ attributes.delete k
12
+ end
13
+
14
+ if Account.update(id, attributes)
15
+ reload
16
+ true
17
+ end
18
+ end
19
+
20
+ def reload
21
+ @attributes = Account.find.attributes
22
+ end
23
+
24
+ def id
25
+ ""
26
+ end
27
+
28
+ def self.find(*args)
29
+ new(HeyWatch::response(Browser::get(self.path, self.session).body))
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,83 @@
1
+ module HeyWatch
2
+ # Authenticate to the Hey!Watch service
3
+ #
4
+ # user = Auth.create("login", "password")
5
+ # user.account
6
+ #
7
+ # If you want to recover a session:
8
+ #
9
+ # user = Auth.recover(session_id)
10
+ # user.account
11
+ #
12
+ # The initialize and create methods can take blocks.
13
+ #
14
+ # Auth.create("login", "password") do |user|
15
+ # video = user.videos.find(:first)
16
+ # format = user.formats.find(:first, :conditions => {:name => "iPod 4:3"})
17
+ # user.jobs.create :video_id => video.id, :format_id => format.id
18
+ # end
19
+ #
20
+ # All the resources (pluralized) are available within the Auth class:
21
+ #
22
+ # jobs, encoded_videos, videos, formats, downloads, discovers, logs, account
23
+ #
24
+ class Auth
25
+ attr_reader :session
26
+ @@sessions = {}
27
+
28
+ # Authenticate to the Hey!Watch service
29
+ #
30
+ # options can be:
31
+ #
32
+ # * <tt>:login</tt> Hey!Watch username
33
+ # * <tt>:password</tt> Hey!Watch password
34
+ # * <tt>:session</tt> A previous session, using this option, you will not be reconnected, you will just recover your session
35
+ def initialize(options={}, &block)
36
+ if options[:session]
37
+ @session = options[:session]
38
+ else
39
+ @session = Browser::login(options[:login], options[:password])
40
+ @@sessions.merge!(@session => true)
41
+ end
42
+ yield self if block_given?
43
+ end
44
+
45
+ # Same as initialize
46
+ #
47
+ # Auth::create 'login', 'password'
48
+ def self.create(login, password, &block)
49
+ new(:login => login, :password => password, &block)
50
+ end
51
+
52
+ # Recover a session
53
+ #
54
+ # Auth.recover(session_id)
55
+ def self.recover(session, &block)
56
+ #raise SessionNotFound if @@sessions[session].nil?
57
+ new(:session => session, &block)
58
+ end
59
+
60
+ Resources.each do |k|
61
+ Auth.module_eval(%{
62
+ def #{k.to_s+"s"}
63
+ klass = #{k.to_s.camelize}
64
+ klass.session = @session
65
+ klass
66
+ end
67
+ }
68
+ )
69
+ end
70
+
71
+ # Delete the current session
72
+ def destroy
73
+ @@sessions.delete(@session)
74
+ @session = nil
75
+ end
76
+
77
+ # Show account info
78
+ def account
79
+ Account.session = @session
80
+ Account.find(:first)
81
+ end
82
+ end
83
+ end