twitterpunch 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 96c566d4bdc10313e9efc77b92c9cfa407048617
4
- data.tar.gz: 59b7a93bd2cdda89c79cc1b99f2811a77b1230e4
3
+ metadata.gz: c881f24bd1e7cc981175e5f5fb52f80a7725e12f
4
+ data.tar.gz: 7516403fe3be89a85cf8ac0a11427857a28119a7
5
5
  SHA512:
6
- metadata.gz: 17cfa29c54696a7dcdecb8ee77c03b3cdbd2c2c0d30479b77abce4722a2f519159939e3d37037da74ea6dda61f235c18fb33e4a0e7261bfbf11278c733e8cf29
7
- data.tar.gz: fc1a39f9a4a93b7896510d48242f3ad968a7ccf8721ee3d966195c0286ab470c706b87fa7b84ffc266d01114d71a7ba5e53feef3bc838e07cb67b58f9ef04e71
6
+ metadata.gz: 2e2a4303a64a59f3cee1c582b74706fdbff6f7095ea60b3b4adcbc2c3c85c404f384f07d1b94e7c9abaed2c6ee340f2dcd1f8292ccbc67602b7f19e58110ebe1
7
+ data.tar.gz: 6c147d09131b4393231a97d531fe029fa3101299aff4e0dc154c3223c49b9407f684020559bd1102d1f0ebbb48f7faa8a111661da831ad1045d96197b7c1b420
data/README.md CHANGED
@@ -17,20 +17,20 @@ Configure the program via the `~/.twitterpunch.yaml` YAML file. This file should
17
17
  look similar to the example below.
18
18
 
19
19
  ---
20
- :twitter:
20
+ :twitter: # twitter configuration
21
21
  :consumer_key: <consumer key>
22
22
  :consumer_secret: <consumer secret>
23
23
  :access_token: <access token>
24
24
  :access_token_secret: <access secret>
25
- :messages:
26
- - Hello there
25
+ :messages: # list of messages to attach
26
+ - Hello there # to outgoing tweets
27
27
  - I'm a posting fool
28
28
  - minimally viable product
29
- :hashtag: BestHalloweenPartyEver
30
- :handle: FassFord
31
- :photodir: ~/Pictures/twitterpunch/
32
- :logfile: /Users/ben/.twitterpunch.log
33
- :sendsound: /System/Library/PrivateFrameworks/ToneLibrary.framework/Versions/A/Resources/AlertTones/tweet_sent.caf
29
+ :hashtag: Twitterpunch # The hashtag to post and listen to
30
+ :photodir: ~/Pictures/twitterpunch/ # Where to save downloaded images
31
+ :logfile: ~/.twitterpunch.log # Where to save logs
32
+ :viewer: # Use the built-in slideshow viewer
33
+ :count: 5 # How many images to have onscreen at once
34
34
 
35
35
  A skeleton configuration file, with access tokens from Twitter, can be generated
36
36
  by running the program with the `--genconfig` flag.
@@ -71,14 +71,18 @@ multiple files at once.
71
71
 
72
72
  ### Viewing the Twitter stream
73
73
 
74
- Currently Twitterpunch doesn't display photos directly. It simply downloads them
75
- and stuffs them into the configured `:photodir`. Twitterpunch will run on OS X or
76
- Windows equally well. Simply configure it on the computer that will act as the
77
- Twitter display and then run in streaming mode. Tweets that come from any other
78
- user will be spoken aloud.
74
+ Twitterpunch will run on OS X or Windows equally well. Simply configure it on the
75
+ computer that will act as the Twitter display and then run in streaming mode.
76
+ All images tweeted to the configured hashtag will be displayed in the slideshow
77
+ and tweets that come from any other user will also be spoken aloud.
79
78
 
80
79
  [ben@ganymede] ~ $ twitterpunch --stream
81
80
 
81
+ If you don't want to use the built-in slideshow viewer, you can disable it by
82
+ removing the `:viewer` key from your `~/.twitterpunch.yaml` config file. Twitterpunch
83
+ will then simply download the tweeted images and save them into the `:photodir`
84
+ directory. You can then use anything you like to view them.
85
+
82
86
  There are currently two decent viewing options I am aware of.
83
87
 
84
88
  * Windows background image:
@@ -98,7 +102,7 @@ Limitations
98
102
  ===========
99
103
 
100
104
  * It currently requires manual setup for Folder Actions.
101
- * It currently requires an external viewer, such as a screensaver.
105
+ * Rubygame is kind of a pain to set up.
102
106
 
103
107
 
104
108
  Contact
data/bin/twitterpunch CHANGED
@@ -66,11 +66,14 @@ when :stream
66
66
  require 'twitterpunch/streamer'
67
67
  require 'twitterpunch/viewer'
68
68
 
69
- statefile = File.expand_path('~/.twitterpunch.state')
70
- config[:state] = YAML.load_file(statefile) rescue {}
69
+ statefile = File.expand_path('~/.twitterpunch.state')
70
+ viewer = Twitterpunch::Viewer.new(config)
71
+
72
+ config[:state] = YAML.load_file(statefile) rescue {}
73
+ config[:display] = viewer
71
74
 
72
75
  Twitterpunch::Streamer.new(config).thread
73
- Twitterpunch::Viewer.new(config)
76
+ viewer.run
74
77
 
75
78
  File.open(statefile, 'w') {|f| f.write(config[:state].to_yaml) }
76
79
 
@@ -85,7 +88,8 @@ when :view
85
88
  statefile = File.expand_path('~/.twitterpunch.state')
86
89
  config[:state] = YAML.load_file(statefile) rescue {}
87
90
 
88
- client = Twitterpunch::Viewer.new(config)
91
+ viewer = Twitterpunch::Viewer.new(config)
92
+ viewer.run
89
93
 
90
94
  when :configure
91
95
  require 'twitterpunch/configuration'
data/lib/twitterpunch.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Twitterpunch
2
- VERSION = '0.0.3'
2
+ VERSION = '0.0.4'
3
3
  end
@@ -59,10 +59,9 @@ module Twitterpunch
59
59
  :viewer => {
60
60
  :count => 5,
61
61
  },
62
- :hashtag => "BestHalloweenPartyEver",
63
- :handle => "fassford",
62
+ :hashtag => "Twitterpunch",
64
63
  :photodir => "~/Pictures/twitterpunch/",
65
- :logfile => '/var/log/twitterpunch',
64
+ :logfile => '~/.twitterpunch.log',
66
65
  }
67
66
  end
68
67
  end
@@ -7,7 +7,7 @@ module Twitterpunch
7
7
  class Logger
8
8
  def initialize(config)
9
9
  @options = config
10
- @logger = ::Logger.new(config[:logfile])
10
+ @logger = ::Logger.new(File.expand_path(config[:logfile]))
11
11
 
12
12
  @logger.level = config[:debug] ? ::Logger::DEBUG : ::Logger::INFO
13
13
  end
@@ -6,34 +6,55 @@ module Twitterpunch
6
6
  include Rubygame
7
7
  include Sprites::Sprite
8
8
 
9
- def initialize(dimensions, image, text)
9
+ def initialize(dimensions, image, text, pop=false)
10
10
  # Invoking the base class constructor is important and yet easy to forget:
11
11
  super()
12
12
 
13
13
  @dimensions = dimensions
14
+ @popped = pop
15
+ @text = text
16
+ @original = Surface.load(image)
14
17
 
15
- @rate = rand(35..150)
16
- @zoom = rand(50..100) / 100.0
17
-
18
- # @image and @rect are expected by the Rubygame sprite code
19
- @image = Surface.load(image).zoom(@zoom)
18
+ if pop
19
+ @image = @original
20
+ @start = Time.now
21
+ @stale = 10
22
+ else
23
+ @rate = rand(35..150)
24
+ @zoom = rand(50..100) / 100.0
25
+ @image = @original.zoom(@zoom)
26
+ end
20
27
 
21
28
  max_width = dimensions[0] * 0.75
22
29
  if @image.width > max_width
23
- @image = @image.zoom(max_width/@image.width)
30
+ factor = max_width/@image.width
31
+ @original = @original.zoom(factor)
32
+ @image = @image.zoom(factor)
33
+ end
34
+
35
+ if pop
36
+ @left = (dimensions[0] - @image.width) / 2
37
+ @top = (dimensions[1] - @image.height) / 2
38
+ else
39
+ @left = (dimensions[0] - @image.width ) * rand
40
+ @top = 0 - @image.height
24
41
  end
25
42
 
26
- @top = 0 - @image.height
27
- @left = (dimensions[0] - @image.width ) * rand
28
43
  @rect = @image.make_rect
29
44
 
30
- if text
31
- @text = $font.render_utf8(text, true, Color[:black], Color[:gray])
32
- @text.alpha = 150
45
+ render_text
46
+ end
47
+
48
+ def render_text
49
+ if @text
50
+ text = $font.render_utf8(@text, true, Color[:black], Color[:gray])
51
+
52
+ # for some reason, windows doesn't deal with this properly
53
+ text.alpha = 150 unless RUBY_PLATFORM =~ /mingw|cygwin/
33
54
 
34
55
  # Determine the dimensions in pixels of the area used to render the text. The
35
56
  # "topleft" of the returned rectangle is at [ 0, 0]
36
- rt = @text.make_rect
57
+ rt = text.make_rect
37
58
 
38
59
  # Re-use the "topleft" of the rectangle to indicate where the text should
39
60
  # appear on screen ( lower left corner )
@@ -41,16 +62,34 @@ module Twitterpunch
41
62
  rt.topleft = [ 0, @image.height - rt.height]
42
63
 
43
64
  # Copy the pixels of the rendered text to the image
44
- @text.blit(@image, rt)
65
+ text.blit(@image, rt)
45
66
  end
46
67
  end
47
68
 
48
- # Animate this object. "seconds_passed" contains the number of ( real-world)
69
+ # Animate this object. "seconds_passed" contains the number of real-world
49
70
  # seconds that have passed since the last time this object was updated and is
50
- # therefore useful for working out how far the object should move ( which
71
+ # therefore useful for working out how far the object should move (which
51
72
  # should be independent of the frame rate)
52
73
  def update(seconds_passed)
53
- @top += seconds_passed * @rate
74
+ if @popped
75
+ elapsed = (Time.now - @start).to_f
76
+
77
+ if elapsed < 1
78
+ scale = 1 + damped_sin(elapsed, 4, 0.05)
79
+
80
+ @image = @original.zoom(scale)
81
+ @top *= scale
82
+ @left *= scale
83
+
84
+ # We changed image size, so rebuild the rect and draw new text
85
+ @rect = @image.make_rect
86
+ render_text
87
+ elsif elapsed > @stale
88
+ @image.alpha -= 5
89
+ end
90
+ else
91
+ @top += seconds_passed * @rate
92
+ end
54
93
  @rect.topleft = [ @left, @top ]
55
94
  end
56
95
 
@@ -59,7 +98,19 @@ module Twitterpunch
59
98
  end
60
99
 
61
100
  def visible
62
- @top < @dimensions[1]
101
+ if @popped
102
+ @image.alpha > 0
103
+ else
104
+ @top < @dimensions[1]
105
+ end
106
+ end
107
+
108
+ def damped_sin(input, cycles = 4, scale = 1)
109
+ Math.sin(input * cycles * Math::PI) * (1 - input) * scale
110
+ end
111
+
112
+ def popped?
113
+ return @popped
63
114
  end
64
115
  end
65
116
  end
@@ -12,6 +12,8 @@ module Twitterpunch
12
12
  @client = Twitter::Streaming::Client.new(config[:twitter])
13
13
  @logger = Twitterpunch::Logger.new(config)
14
14
  @output = File.expand_path(config[:photodir])
15
+ @handle = Twitter::REST::Client.new(config[:twitter]).current_user.screen_name
16
+ @viewer = config[:display]
15
17
 
16
18
  FileUtils.mkdir_p(@output) unless File.directory?(@output)
17
19
  end
@@ -31,18 +33,6 @@ module Twitterpunch
31
33
 
32
34
  content = tweet.text.gsub(/ http\S*/,'').gsub(/#\S*/,'')
33
35
 
34
-
35
- unless tweet.user.screen_name == @config[:handle]
36
- message = "#{tweet.user.name} says #{content}"
37
-
38
- case RUBY_PLATFORM
39
- when /mingw|cygwin/
40
- system('cscript', "#{@config[:resources]}/say.vbs", message)
41
- when /darwin/
42
- system('say', message)
43
- end
44
- end
45
-
46
36
  if tweet.media?
47
37
  uri = tweet.media.first.media_uri
48
38
 
@@ -56,16 +46,33 @@ module Twitterpunch
56
46
  file.write(response.body)
57
47
  end
58
48
 
59
- unless tweet.user.screen_name == @config[:handle]
49
+ unless tweet.user.screen_name == @handle
60
50
  @config[:state][image] = content
61
51
  end
62
52
 
63
- # OS X screensaver doesn't reload images dynamically. This kinda sucks.
64
- if RUBY_PLATFORM =~ /darwin/ and not @config.has_key? :viewer
65
- system('osascript', '-e', 'tell application "System Events" to stop current screen saver')
66
- system('osascript', '-e', 'tell application "System Events" to start current screen saver')
53
+ if @viewer
54
+ @viewer.pop(image, content)
55
+ else
56
+ # OS X screensaver doesn't reload images dynamically. This kinda sucks.
57
+ if RUBY_PLATFORM =~ /darwin/ and system('pgrep ScreenSaverEngine >/dev/null')
58
+ system('osascript', '-e', 'tell application "System Events" to stop current screen saver')
59
+ system('osascript', '-e', 'tell application "System Events" to start current screen saver')
60
+ end
67
61
  end
62
+
68
63
  end
64
+
65
+ unless tweet.user.screen_name == @handle
66
+ message = "#{tweet.user.name} says #{content}"
67
+
68
+ case RUBY_PLATFORM
69
+ when /mingw|cygwin/
70
+ system('cscript', "#{@config[:resources]}/say.vbs", message)
71
+ when /darwin/
72
+ system('say', message)
73
+ end
74
+ end
75
+
69
76
  end
70
77
  end
71
78
  rescue Interrupt => e
@@ -9,18 +9,19 @@ module Twitterpunch
9
9
 
10
10
  def initialize(config)
11
11
  @config = config
12
- @state = YAML.load_file(File.expand_path('~/.twitterpunch.state')) rescue {}
13
12
  srand
13
+ end
14
14
 
15
+ def run
15
16
  if @config.has_key? :viewer
16
- run
17
+ display
17
18
  else
18
19
  puts 'Press enter to exit'
19
20
  STDIN.gets
20
21
  end
21
22
  end
22
23
 
23
- def run
24
+ def display
24
25
  onscreen = @config[:viewer][:count] || 5
25
26
 
26
27
  # Set up the TrueType Font module
@@ -30,9 +31,9 @@ module Twitterpunch
30
31
 
31
32
  #@screen = Screen.open [ 640, 480]
32
33
  default_depth = 0
33
- maximum_resolution = Screen.get_resolution
34
+ @maximum_resolution = Screen.get_resolution
34
35
 
35
- screen = Screen.open(maximum_resolution, default_depth, [ HWSURFACE, DOUBLEBUF, FULLSCREEN])
36
+ screen = Screen.open(@maximum_resolution, default_depth, [ HWSURFACE, DOUBLEBUF, FULLSCREEN])
36
37
 
37
38
  screen.show_cursor = false
38
39
 
@@ -45,15 +46,15 @@ module Twitterpunch
45
46
 
46
47
  # Create a new group of sprites so that all sprites in the group may be updated
47
48
  # or drawn with a single method invocation.
48
- sprites = Sprites::Group.new
49
- Sprites::UpdateGroup.extend_object(sprites)
49
+ @sprites = Sprites::Group.new
50
+ Sprites::UpdateGroup.extend_object(@sprites)
50
51
  onscreen.times do
51
- sprites << Twitterpunch::Sprite.new(maximum_resolution, *next_image)
52
+ @sprites << Twitterpunch::Sprite.new(@maximum_resolution, *next_image)
52
53
  end
53
54
 
54
55
  #@background = Surface.load("background.png").zoom_to(maximum_resolution[0], maximum_resolution[1])
55
56
  # Create a background image and copy it to the screen. With no image, it's just black.
56
- background = Surface.new(maximum_resolution)
57
+ background = Surface.new(@maximum_resolution)
57
58
  background.blit(screen, [ 0, 0])
58
59
 
59
60
  event_queue = EventQueue.new
@@ -71,26 +72,37 @@ module Twitterpunch
71
72
  end
72
73
 
73
74
  # remove all sprites who've gone out of sight
74
- sprites.reject { |sprite| sprite.visible }.each do |sprite|
75
+ @sprites.reject { |sprite| sprite.visible }.each do |sprite|
76
+ sprite.undraw(screen, background)
75
77
  sprite.kill
76
- sprites << Twitterpunch::Sprite.new(maximum_resolution, *next_image)
78
+ next if sprite.popped?
79
+
80
+ @sprites << Twitterpunch::Sprite.new(@maximum_resolution, *next_image)
77
81
  end
78
82
 
79
83
  # "undraw" all of the sprites by drawing the background image at their
80
84
  # current location ( before their location has been changed by the animation)
81
- sprites.undraw(screen, background)
85
+ @sprites.undraw(screen, background)
82
86
 
83
87
  # Give all of the sprites an opportunity to move themselves to a new location
84
- sprites.update(seconds_passed)
88
+ @sprites.update(seconds_passed)
85
89
 
86
90
  # Draw all of the sprites
87
- sprites.draw(screen)
91
+ @sprites.draw(screen)
92
+
93
+ # Then redraw the popped sprite to ensure it's on top
94
+ @sprites.select { |sprite| sprite.popped? }.each { |popped| popped.draw(screen) }
88
95
 
89
96
  screen.flip
90
97
  end
91
98
 
92
99
  end
93
100
 
101
+ def pop(image, text)
102
+ path = File.expand_path("#{@config[:photodir]}/#{image}")
103
+ @sprites << Twitterpunch::Sprite.new(@maximum_resolution, path, text, true)
104
+ end
105
+
94
106
  def next_image
95
107
  image = Dir.glob(File.expand_path("#{@config[:photodir]}/*")).sample
96
108
  text = @config[:state][File.basename(image)]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twitterpunch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Ford
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-30 00:00:00.000000000 Z
11
+ date: 2014-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: twitter
@@ -74,15 +74,19 @@ description: "Twitterpunch\n===============\n\nTwitterpunch is designed to work
74
74
  them to a specified directory. If\nthe tweet came from another user, Twitterpunch
75
75
  will speak it aloud.\n\nConfiguration\n===========\n\nConfigure the program via
76
76
  the `~/.twitterpunch.yaml` YAML file. This file should\nlook similar to the example
77
- below.\n\n ---\n :twitter:\n :consumer_key: <consumer key>\n :consumer_secret:
78
- <consumer secret>\n :access_token: <access token>\n :access_token_secret:
79
- <access secret>\n :messages:\n - Hello there\n - I'm a posting fool\n -
80
- minimally viable product\n :hashtag: BestHalloweenPartyEver\n :handle: FassFord\n
81
- \ :photodir: ~/Pictures/twitterpunch/\n :logfile: /Users/ben/.twitterpunch.log\n
82
- \ :sendsound: /System/Library/PrivateFrameworks/ToneLibrary.framework/Versions/A/Resources/AlertTones/tweet_sent.caf\n\nA
83
- skeleton configuration file, with access tokens from Twitter, can be generated\nby
84
- running the program with the `--genconfig` flag.\n\nUsage \n==========\n\n### Using
85
- OS X PhotoBooth\n\n1. Start PhotoBooth at least once to generate its library.\n1.
77
+ below.\n\n ---\n :twitter: # twitter configuration\n
78
+ \ :consumer_key: <consumer key>\n :consumer_secret: <consumer secret>\n
79
+ \ :access_token: <access token>\n :access_token_secret: <access secret>\n
80
+ \ :messages: # list of messages to attach\n -
81
+ Hello there # to outgoing tweets\n - I'm a posting
82
+ fool\n - minimally viable product\n :hashtag: Twitterpunch #
83
+ The hashtag to post and listen to\n :photodir: ~/Pictures/twitterpunch/ #
84
+ Where to save downloaded images\n :logfile: ~/.twitterpunch.log # Where
85
+ to save logs\n :viewer: # Use the built-in slideshow
86
+ viewer\n :count: 5 # How many images to have onscreen
87
+ at once\n\nA skeleton configuration file, with access tokens from Twitter, can be
88
+ generated\nby running the program with the `--genconfig` flag.\n\nUsage \n==========\n\n###
89
+ Using OS X PhotoBooth\n\n1. Start PhotoBooth at least once to generate its library.\n1.
86
90
  Install the Twitterpunch Folder Action\n * `twitterpunch --install`\n * It
87
91
  may claim that it could not be attached, fear not.\n1. Profit!\n * _and by that,
88
92
  I mean take some shots with PhotoBooth!_\n\n#### Troubleshooting.\n\n1. Make sure
@@ -97,24 +101,27 @@ description: "Twitterpunch\n===============\n\nTwitterpunch is designed to work
97
101
  the program you are using for your photo shoot to call Twitterpunch\neach time it
98
102
  snaps a photo. Pass the name of the new photo as a command line\nargument. Alternatively,
99
103
  you could batch them, as Twitterpunch can accept\nmultiple files at once.\n\n [ben@ganymede]
100
- ~ $ twitterpunch photo.jpg\n\n### Viewing the Twitter stream\n\nCurrently Twitterpunch
101
- doesn't display photos directly. It simply downloads them\nand stuffs them into
102
- the configured `:photodir`. Twitterpunch will run on OS X or\nWindows equally well.
103
- Simply configure it on the computer that will act as the \nTwitter display and then
104
- run in streaming mode. Tweets that come from any other\nuser will be spoken aloud.\n\n
105
- \ [ben@ganymede] ~ $ twitterpunch --stream\n\nThere are currently two decent viewing
106
- options I am aware of.\n\n* Windows background image:\n * Configure the Windows
107
- background to randomly cycle through photos in a directory.\n * Hide desktop
108
- icons.\n * Hide the taskbar.\n * Disable screensaver and power savings.\n
109
- \ * Drawbacks: You're using Windows and you have to install Ruby & RubyGems manually.\n*
110
- OS X screensaver:\n * Choose one of the sexy screensavers and configure it to
111
- show photos from the `:photodir`\n * Set screensaver to a super short timeout.\n
112
- \ * Disable power savings.\n * Drawbacks: The screensaver doesn't reload dynamically,
113
- so I have to kick it\n and you'll see it reloading each time a new tweet comes
114
- in.\n\nLimitations\n===========\n\n* It currently requires manual setup for Folder
115
- Actions.\n* It currently requires an external viewer, such as a screensaver.\n\n\nContact\n=======\n\n*
116
- Author: Ben Ford\n* Email: binford2k@gmail.com\n* Twitter: @binford2k\n* IRC (Freenode):
117
- binford2k\n"
104
+ ~ $ twitterpunch photo.jpg\n\n### Viewing the Twitter stream\n\nTwitterpunch will
105
+ run on OS X or Windows equally well. Simply configure it on the\ncomputer that will
106
+ act as the Twitter display and then run in streaming mode.\nAll images tweeted to
107
+ the configured hashtag will be displayed in the slideshow\nand tweets that come
108
+ from any other user will also be spoken aloud.\n\n [ben@ganymede] ~ $ twitterpunch
109
+ --stream\n\nIf you don't want to use the built-in slideshow viewer, you can disable
110
+ it by\nremoving the `:viewer` key from your `~/.twitterpunch.yaml` config file.
111
+ Twitterpunch\nwill then simply download the tweeted images and save them into the
112
+ `:photodir`\ndirectory. You can then use anything you like to view them.\n\nThere
113
+ are currently two decent viewing options I am aware of.\n\n* Windows background
114
+ image:\n * Configure the Windows background to randomly cycle through photos
115
+ in a directory.\n * Hide desktop icons.\n * Hide the taskbar.\n * Disable
116
+ screensaver and power savings.\n * Drawbacks: You're using Windows and you have
117
+ to install Ruby & RubyGems manually.\n* OS X screensaver:\n * Choose one of the
118
+ sexy screensavers and configure it to show photos from the `:photodir`\n * Set
119
+ screensaver to a super short timeout.\n * Disable power savings.\n * Drawbacks:
120
+ The screensaver doesn't reload dynamically, so I have to kick it\n and you'll
121
+ see it reloading each time a new tweet comes in.\n\nLimitations\n===========\n\n*
122
+ It currently requires manual setup for Folder Actions.\n* Rubygame is kind of a
123
+ pain to set up.\n\n\nContact\n=======\n\n* Author: Ben Ford\n* Email: binford2k@gmail.com\n*
124
+ Twitter: @binford2k\n* IRC (Freenode): binford2k\n"
118
125
  email: binford2k@gmail.com
119
126
  executables:
120
127
  - twitterpunch