heywatch 0.0.1

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/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