captured 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,10 +10,10 @@ While I would love to tinker with this to make it easy to install (it is really
10
10
 
11
11
  So, I am making some assumptions about the environment that captured runs in. In particular it expects:
12
12
 
13
- * A decent understanding of scp and ssh
13
+ * A decent understanding of installing ruby gems
14
14
  * That [Growl](http://growl.info/) (and the [growlnotify](http://growl.info/documentation/growlnotify.php) command-line tool) are installed
15
15
 
16
- With that said, once things are installed and configured it really is handy.
16
+ With that said, once things are installed and configured it really is handy.
17
17
 
18
18
  Install
19
19
  =======
@@ -28,7 +28,19 @@ Then you will need to exit that config file with the appropriate settings for yo
28
28
 
29
29
  When you install it will copy an example config file to ~/.captured.yml, which has a few examples of possible configuration types.
30
30
 
31
- The simplest of this is to the scp type:
31
+ Install Type: Imageshack
32
+ ------------------------
33
+ The easiest way to do this is to use the image shack service. This service is a little slower, but is free and easy.
34
+
35
+ <pre>
36
+ upload:
37
+ type: scp
38
+ </pre>
39
+
40
+ Install Type: scp
41
+ -----------------
42
+
43
+ If you have you own web server scp is a very handy way to host your own captures.
32
44
 
33
45
  * user - optional if your remote user is the same as your local user
34
46
  * password - optional if you have setup key pair authentication
@@ -46,14 +58,11 @@ The simplest of this is to the scp type:
46
58
  url: "http://example.com/captured/"
47
59
  </pre>
48
60
 
49
-
50
-
51
61
  Icons
52
62
  =====
53
63
 
54
64
  Icons from the [Crystal Clear](http://www.everaldo.com/crystal/) icon set by [Everaldo Coelho](http://en.wikipedia.org/wiki/Everaldo_Coelho). – The icons are [licensed](http://www.everaldo.com/crystal/?action=license) under the [GNU Lesser General Public License (LGPL)](http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License).
55
65
 
56
-
57
66
  Copyright
58
67
  =========
59
68
 
@@ -1,11 +1,40 @@
1
1
  # Example captured configuration file
2
2
  #
3
- # Eval
4
- # ====
3
+ # Standard upload type: Image Shack
4
+ # =================================
5
5
  #
6
- # Complete control for the complete nerd. This allows you to execute arbtrary
7
- # ruby code when a matching file is found. Normally this would be used to
8
- # invoke a command line upload (such as scp, curl, etc).
6
+ # The default option is to post your images to imageshack.us, if you want to
7
+ # use one of the more advances and felxable types simply comment this out.
8
+
9
+ upload:
10
+ type: imageshack
11
+
12
+ #
13
+ # Powerful upload type: scp
14
+ # =========================
15
+ #
16
+ # Standard scp, using the ruby net/ssh library.
17
+ #
18
+ # * user - optinal if your remote user is the same as your local user
19
+ # * password - optional if you have setup key pair authentication
20
+ # * host - the remote host name
21
+ # * url - the public url to the remote host+path
22
+ # * path - the remote path to upload to
23
+
24
+ #upload:
25
+ # type: scp
26
+ # user: user
27
+ # host: example.com
28
+ # path: example.com/captured/
29
+ # url: "http://example.com/captured/"
30
+
31
+ #
32
+ # Advanced upload type: Eval
33
+ # ==========================
34
+ #
35
+ # Complete control for the complete nerd. This allows you to execute arbtrary
36
+ # ruby code when a matching file is found. Normally this would be used to
37
+ # invoke a command line upload (such as scp, curl, etc).
9
38
  #
10
39
  # One advantage with calling scp this way is it will be aware of all the custom
11
40
  # settings made in ~/.ssh/config.
@@ -30,21 +59,3 @@
30
59
  # remote_path="http://twitter.com/user"
31
60
  # system "curl -F media='@#{file}' -F username=user -F password=secret -F message=Captured http://twitpic.com/api/uploadAndPost"
32
61
  #
33
- # scp
34
- # ===
35
- #
36
- # Standard scp, using the ruby net/ssh library.
37
- #
38
- # * user - optinal if your remote user is the same as your local user
39
- # * password - optional if you have setup key pair authentication
40
- # * host - the remote host name
41
- # * url - the public url to the remote host+path
42
- # * path - the remote path to upload to
43
-
44
- #upload:
45
- # type: scp
46
- # user: user
47
- # host: example.com
48
- # path: example.com/captured/
49
- # url: "http://example.com/captured/"
50
-
@@ -21,6 +21,7 @@ class Captured
21
21
  end
22
22
  end
23
23
 
24
+ # Depricated this is now handeled by launchd
24
25
  def self.run_and_watch!(options)
25
26
  require 'captured/fs_events'
26
27
  watch_path = options[:watch_path] || "#{ENV['HOME']}/Desktop/"
@@ -12,42 +12,19 @@ class FileUploader
12
12
  @config = YAML.load_file(options[:config_file])
13
13
  case @config['upload']['type']
14
14
  when"eval"
15
- @upload_proc = eval_proc
15
+ require File.expand_path(File.dirname(__FILE__) + '/uploaders/eval_uploader')
16
+ @uploader = EvalUploader.new(@config)
16
17
  when"scp"
17
- @upload_proc = scp_proc
18
- when"ftp"
18
+ require File.expand_path(File.dirname(__FILE__) + '/uploaders/scp_uploader')
19
+ @uploader = ScpUploader.new(@config)
20
+ when"imageshack"
21
+ require File.expand_path(File.dirname(__FILE__) + '/uploaders/imageshack_uploader')
22
+ @uploader = ImageshackUploader.new(@config)
19
23
  else
20
24
  raise "Invalid Type"
21
25
  end
22
26
  end
23
27
 
24
- def eval_proc
25
- lambda do |file, remote_name|
26
- remote_path = nil
27
- unless eval @config['upload']['command']
28
- raise "Upload failed: Bad Eval in config file"
29
- end
30
- # if the eval defines remote_path we will copy that to the clipboard
31
- # otherwise we compute it ouselves
32
- remote_path || "#{@config['upload']['url']}#{remote_name}"
33
- end
34
- end
35
-
36
- def scp_proc
37
- require 'net/scp'
38
- require 'etc'
39
- settings = @config['upload']
40
- lambda do |file, remote_name|
41
- Net::SCP.upload!(settings['host'],
42
- settings['user'] || Etc.getlogin,
43
- file,
44
- settings['path']+remote_name,
45
- :password => settings['password'])
46
-
47
- "#{@config['upload']['url']}#{remote_name}"
48
- end
49
- end
50
-
51
28
  def pbcopy(str)
52
29
  system "ruby -e \"print '#{str}'\" | pbcopy"
53
30
  # I prefer the following method but it was being intermitant about actually
@@ -62,7 +39,8 @@ class FileUploader
62
39
  def process_upload(file)
63
40
  remote_name = Digest::MD5.hexdigest(file+Time.now.to_i.to_s) + File.extname(file)
64
41
  growl("Processing Upload", "#{File.dirname(File.expand_path(__FILE__))}/../../resources/action_run.png")
65
- remote_path = @upload_proc.call(file, remote_name)
42
+ @uploader.upload(file)
43
+ remote_path = @uploader.url
66
44
  puts "Uploaded '#{file}' to '#{remote_path}'"
67
45
  pbcopy remote_path
68
46
  growl("Upload Succeeded", "#{File.dirname(File.expand_path(__FILE__))}/../../resources/green_check.png")
@@ -0,0 +1,23 @@
1
+ class EvalUploader
2
+ attr_accessor :url
3
+
4
+ def initialize(config = {})
5
+ @config = config
6
+ end
7
+
8
+ def gen_remote_name(file)
9
+ Digest::MD5.hexdigest(file+Time.now.to_i.to_s) + File.extname(file)
10
+ end
11
+
12
+ def upload(file)
13
+ remote_path = nil
14
+ remote_name = gen_remote_name(file)
15
+ unless eval @config['upload']['command']
16
+ raise "Upload failed: Bad Eval in config file"
17
+ end
18
+ # if the eval defines remote_path we will copy that to the clipboard
19
+ # otherwise we compute it ouselves
20
+ @url = remote_path || "#{@config['upload']['url']}#{remote_name}"
21
+ @url
22
+ end
23
+ end
@@ -0,0 +1,126 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'cgi'
4
+ require 'mime/types'
5
+
6
+ # Adapted from http://codesnippets.joyent.com/posts/show/1156
7
+ class ImageshackUploader
8
+ attr_reader :url
9
+ USER_AGENT = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko) Safari/419.3"
10
+ BOUNDARY = '----------PuSHerInDaBUSH_$'
11
+
12
+ def initialize(config = {})
13
+ @config = config
14
+ @shack_id = config['upload']['shackid'] || "captured"
15
+ end
16
+
17
+ def upload(file_name)
18
+ unless file_name =~ /jpe?g|png|gif|bmp|tif|tiff|swf$/
19
+ raise(NonImageTypeError, 'Expected image file.')
20
+ end
21
+ @img = file_name
22
+ @posted_url, @hosturi, @res = "","",""
23
+ @header, @params = {}, {}
24
+ @header['Cookie'] = "myimages=#{@shack_id}"
25
+ @header['User-Agent'] = USER_AGENT
26
+ @params['uploadtype'] = 'on'
27
+ @params['brand'] = ''
28
+ @params['refer'] = ''
29
+ @params['MAX_FILE_SIZE'] = '13145728'
30
+ @params['optimage'] = '0'
31
+ @params['rembar'] = '1'
32
+ transfer
33
+ getdirect
34
+ @url = @posted_url.gsub("content.php?page=done&l=", "")
35
+ end
36
+
37
+ def prepare_multipart ( params )
38
+ fp = []
39
+ params.each do |k,v|
40
+ if v.respond_to?(:read)
41
+ fp.push(FileParam.new(k,v.path,v.read))
42
+ else fp.push(Param.new(k,v))
43
+ end
44
+ end
45
+ query = fp.collect {|p| "--" + BOUNDARY + "\r\n" + p.to_multipart }.join("") + "--" + BOUNDARY + "--"
46
+ return query
47
+ end
48
+
49
+ def prepFile(path_to_file)
50
+ file = File.new(path_to_file)
51
+ @header['Content-Type'] = "multipart/form-data, boundary=" + BOUNDARY + " "
52
+ @params['url'] = 'paste image url here'
53
+ @params['fileupload'] = file
54
+ $query = prepare_multipart(@params)
55
+ file.close
56
+ end
57
+
58
+ def locate(path)
59
+ path !~ /^http/ ? "local" : "remote"
60
+ end
61
+
62
+ def process_upload( query, headers={} )
63
+ Net::HTTP.start(@hosturi.host) do | http |
64
+ http.post(@hosturi.path, query, headers);
65
+ end
66
+ end
67
+
68
+ def transload(url)
69
+ @header['Content-Type'] = 'form-data'
70
+ @params['url'] = url
71
+ @params['fileupload'] = ''
72
+ postreq = Net::HTTP::Post.new(@hosturi.path, @header)
73
+ postreq.set_form_data(@params)
74
+ return Net::HTTP.new(@hosturi.host, @hosturi.port).start { |http| http.request(postreq) }
75
+ end
76
+
77
+ def transfer
78
+ case locate(@img)
79
+ when "local"
80
+ @hosturi = URI.parse('http://load.imageshack.us/index.php')
81
+ prepFile(@img)
82
+ @res = process_upload($query,@header)
83
+ when "remote"
84
+ @hosturi = URI.parse('http://imageshack.us/transload.php')
85
+ @res = transload(@img)
86
+ end
87
+ end
88
+
89
+ def getdirect
90
+ puts @res.header
91
+ puts @res.body
92
+ @posted_url = @res.header['location']
93
+ end
94
+
95
+ end
96
+
97
+ class Param
98
+ attr_accessor :k, :v
99
+
100
+ def initialize(k,v)
101
+ @k = k
102
+ @v = v
103
+ end
104
+
105
+ def to_multipart
106
+ return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"\r\n\r\n#{v}\r\n"
107
+ end
108
+ end
109
+
110
+ class FileParam
111
+ attr_accessor :k, :filename, :content
112
+
113
+ def initialize(k, filename, content)
114
+ @k = k
115
+ @filename = filename
116
+ @content = content
117
+ end
118
+
119
+ def to_multipart
120
+ return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"; filename=\"#{filename}\"\r\n" +
121
+ "Content-Type: #{MIME::Types.type_for(@filename)}\r\n\r\n" + content + "\r\n"
122
+ end
123
+ end
124
+
125
+
126
+
@@ -0,0 +1,30 @@
1
+ class ScpUploader
2
+ attr_accessor :url
3
+
4
+ def initialize(config = {})
5
+ @config = config
6
+ end
7
+
8
+ def gen_remote_name(file)
9
+ Digest::MD5.hexdigest(file+Time.now.to_i.to_s) + File.extname(file)
10
+ end
11
+
12
+ def upload(file)
13
+ puts "Uploading #{file}"
14
+ # TODO: This needs to be called from file upload
15
+ # and this calss needs to be completed
16
+ # maybe some tests
17
+ require 'net/scp'
18
+ require 'etc'
19
+ settings = @config['upload']
20
+ remote_name = gen_remote_name(file)
21
+ puts Net::SCP.upload!(settings['host'],
22
+ settings['user'] || Etc.getlogin,
23
+ file,
24
+ settings['path']+remote_name,
25
+ :password => settings['password'])
26
+
27
+ @url = "#{@config['upload']['url']}#{remote_name}"
28
+ @url
29
+ end
30
+ end
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ def red(s); colorize(s, "\e[0m\e[31m"); end
5
+ def green(s); colorize(s, "\e[0m\e[32m"); end
6
+ def dark_green(s); colorize(s, "\e[32m"); end
7
+ def yellow(s); colorize(s, "\e[0m\e[33m"); end
8
+ def blue(s); colorize(s, "\e[0m\e[34m"); end
9
+ def dark_blue(s); colorize(s, "\e[34m"); end
10
+ def pur(s); colorize(s, "\e[0m\e[35m"); end
11
+ def colorize(text, color_code) "#{color_code}#{text}\e[0m" end
12
+
13
+ def log(msg)
14
+ puts yellow " #{msg}"
15
+ end
16
+
17
+ options = {}
18
+ OptionParser.new do |opts|
19
+ # -h,--help Display this help
20
+ # -v,--version Display version number
21
+ # -n,--name Set the name of the application that sends the notification
22
+ # [Default: growlnotify]
23
+ # -s,--sticky Make the notification sticky
24
+ # -a,--appIcon Specify an application name to take the icon from
25
+ # -i,--icon Specify a file type or extension to look up for the
26
+ # notification icon
27
+ # -I,--iconpath Specify a file whose icon will be the notification icon
28
+ # --image Specify an image file to be used for the notification icon
29
+
30
+ opts.on('--image IMAGE', "Specify an image file to be used for the notification icon") do |img|
31
+ options[:image] = true
32
+ if !File.exists? img
33
+ log "GROWL ERROR: Image file does not exist"
34
+ exit 1
35
+ end
36
+ end
37
+
38
+ # -m,--message Sets the message to be used instead of using stdin
39
+ opts.on('-m', '--message MSG', "Specify an image file to be used for the notification icon") do |msg|
40
+ options[:message] = true
41
+ if !msg
42
+ log "GROWL ERROR: No message"
43
+ exit 1
44
+ else
45
+ log "growl: #{msg}"
46
+ end
47
+ end
48
+ # Passing - as the argument means read from stdin
49
+ # -p,--priority Specify an int or named key (default is 0)
50
+ # -d,--identifier Specify a notification identifier (used for coalescing)
51
+ # -H,--host Specify a hostname to which to send a remote notification.
52
+ # -P,--password Password used for remote notifications.
53
+ # -u,--udp Use UDP instead of DO to send a remote notification.
54
+ # --port Port number for UDP notifications.
55
+ # -A,--auth Specify digest algorithm for UDP authentication.
56
+ # Either MD5 [Default], SHA256 or NONE.
57
+ # -c,--crypt Encrypt UDP notifications.
58
+ # -w,--wait Wait until the notification has been dismissed.
59
+ # --progress Set a progress value for this notification.
60
+
61
+ # -t,--title Does nothing. Any text following will be treated as the
62
+ # title because that's the default argument behaviour
63
+ opts.on('-t', "Does nothing") do |msg|
64
+ options[:title] = true
65
+ if !msg
66
+ log "GROWL ERROR: No title"
67
+ exit 1
68
+ end
69
+ log "growl: #{msg}"
70
+ end
71
+
72
+ #puts " Grrrr! #{ARGV.inspect}"
73
+ end.parse!
74
+
@@ -1,7 +1,30 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe "Captured" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
3
+ describe "File Uploader" do
4
+ before(:all) do
5
+ # This is run once and only once, before all of the examples
6
+
7
+ #Make a backup of the clipboard
8
+ $pb_backup = `pbpaste`
9
+
10
+ system "mkdir -p #{File.dirname(__FILE__) + '/../tmp/watch_path'}"
11
+ @options = {:config_file => File.dirname(__FILE__) + '/fixtures/scp_config.yml',
12
+ :watch_path => File.dirname(__FILE__) + '/../tmp/watch_path',
13
+ :watch_pattern => Captured.guess_watch_path,
14
+ :growl_path => "/usr/local/bin/growlnotify" }
15
+ end
16
+
17
+ after(:all) do
18
+ # This is run once and only once, after all of the examples
19
+ # Restore the clipboard contents
20
+ FileUploader.new(@options).pbcopy $pb_backup
21
+ end
22
+
23
+
24
+ it "should copy text to the system clipboard" do
25
+ fu = FileUploader.new @options
26
+ str = "Testing captured is fun for you"
27
+ fu.pbcopy str
28
+ `pbpaste`.should == str
6
29
  end
7
30
  end
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "File Uploader" do
4
+ before(:all) do
5
+ # This is run once and only once, before all of the examples
6
+
7
+ #Make a backup of the clipboard
8
+ $pb_backup = `pbpaste`
9
+
10
+ system "mkdir -p #{File.dirname(__FILE__) + '/../tmp/watch_path'}"
11
+ @options = {:config_file => File.dirname(__FILE__) + '/fixtures/scp_config.yml',
12
+ :watch_path => File.dirname(__FILE__) + '/../tmp/watch_path',
13
+ :watch_pattern => Captured.guess_watch_path,
14
+ :growl_path => File.dirname(__FILE__) + '/bin/mockgrowlnotify'}
15
+ end
16
+
17
+ after(:all) do
18
+ # This is run once and only once, after all of the examples
19
+ # Restore the clipboard contents
20
+ FileUploader.new(@options).pbcopy $pb_backup
21
+ end
22
+
23
+
24
+ it "should copy text to the system clipboard" do
25
+ fu = FileUploader.new @options
26
+ str = "Testing captured is fun for you"
27
+ fu.pbcopy str
28
+ `pbpaste`.should == str
29
+ end
30
+ it "should call growl" do
31
+ fu = FileUploader.new @options
32
+ str = "Testing captured is fun for you"
33
+ fu.growl str
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ upload:
2
+ type: scp
3
+ user: user
4
+ host: example.com
5
+ path: example.com/captured/
6
+ url: "http://example.com/captured/"
7
+
@@ -1,3 +1,4 @@
1
+ require 'rubygems'
1
2
  require 'spec'
2
3
 
3
4
  $LOAD_PATH.unshift(File.dirname(__FILE__))
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/captured/uploaders/imageshack_uploader')
3
+
4
+ describe "SCP File Uploader" do
5
+ it "should upload to the server" do
6
+ config = {"upload"=>{"url"=>"http://fuzzymonk.com/captured/",
7
+ "type"=>"imageshack",
8
+ "shackid"=>"capturedspec"}}
9
+
10
+ @uploader = ImageshackUploader.new(config)
11
+ @uploader.upload(File.expand_path(File.dirname(__FILE__) + '/../../resources/captured.png'))
12
+ system "open #{@uploader.url}"
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/captured/uploaders/scp_uploader')
3
+
4
+ describe "SCP File Uploader" do
5
+ it "should upload to the server" do
6
+ # This spec requires a scp_spec section in the config file with the
7
+ # scp settings
8
+ config = YAML.load_file("#{ENV['HOME']}/.captured.yml")['scp_spec']
9
+ @uploader = ScpUploader.new(config)
10
+ @uploader.upload(File.expand_path(File.dirname(__FILE__) + '/../../resources/captured.png'))
11
+ system "open #{@uploader.url}"
12
+ end
13
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: captured
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Sexton
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-28 00:00:00 -04:00
12
+ date: 2009-11-02 00:00:00 -05:00
13
13
  default_executable: captured
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -22,7 +22,7 @@ dependencies:
22
22
  - !ruby/object:Gem::Version
23
23
  version: "0"
24
24
  version:
25
- description:
25
+ description: Because <shift>-<command>-4 is the single most useful shorcut in Macdom
26
26
  email: csexton@gmail.com
27
27
  executables:
28
28
  - captured
@@ -40,6 +40,9 @@ files:
40
40
  - lib/captured/file_tracker.rb
41
41
  - lib/captured/file_uploader.rb
42
42
  - lib/captured/fs_events.rb
43
+ - lib/captured/uploaders/eval_uploader.rb
44
+ - lib/captured/uploaders/imageshack_uploader.rb
45
+ - lib/captured/uploaders/scp_uploader.rb
43
46
  - resources/2uparrow.png
44
47
  - resources/action_run.png
45
48
  - resources/captured.png
@@ -47,8 +50,13 @@ files:
47
50
  - resources/red_star.png
48
51
  - resources/red_x.png
49
52
  - resources/ruby.png
53
+ - spec/bin/mockgrowlnotify
50
54
  - spec/captured_spec.rb
55
+ - spec/file_uploader_spec.rb
56
+ - spec/fixtures/scp_config.yml
51
57
  - spec/spec_helper.rb
58
+ - spec/uploader_specs/imageshack_uploader_spec.rb
59
+ - spec/uploader_specs/scp_uploader_spec.rb
52
60
  - LICENSE
53
61
  has_rdoc: true
54
62
  homepage: http://github.com/csexton/captured
@@ -80,4 +88,7 @@ specification_version: 3
80
88
  summary: Quick screenshot sharing for OS X
81
89
  test_files:
82
90
  - spec/captured_spec.rb
91
+ - spec/file_uploader_spec.rb
83
92
  - spec/spec_helper.rb
93
+ - spec/uploader_specs/imageshack_uploader_spec.rb
94
+ - spec/uploader_specs/scp_uploader_spec.rb