twitterpunch 0.0.5 → 0.0.6
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.
- checksums.yaml +4 -4
- data/bin/twitterpunch +32 -3
- data/lib/twitterpunch.rb +1 -1
- data/lib/twitterpunch/poster.rb +20 -14
- data/lib/twitterpunch/queue.rb +53 -0
- data/lib/twitterpunch/remote.rb +54 -0
- data/public/touch-icon-ipad-retina.png +0 -0
- data/public/touch-icon-iphone-retina.png +0 -0
- data/views/index.erb +147 -0
- metadata +18 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f713d6cb1c1e707769c09897f11913046bbffbd4
|
4
|
+
data.tar.gz: c37e34a59d06f4e0f6edfcfee3d23e0d87af4b77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 840fce97e3c6a0b6b55d34aea8080a2bc82873bcb528b6e108036544e6427b48b542eac7509b1cbce852fb0dd108c0dba010df85bb261da23efa3eed4642e7cd
|
7
|
+
data.tar.gz: 789cc9841fb3bf2b22f0184ff425fca27b8bf8b33aeaf76312efba604d07bbdecb041063ff1cc4cdf2f5508037c5676e4d1644cde99056ef6850a4c80942cd6e
|
data/bin/twitterpunch
CHANGED
@@ -4,10 +4,14 @@ require 'rubygems'
|
|
4
4
|
require 'twitter'
|
5
5
|
require 'optparse'
|
6
6
|
require "net/http"
|
7
|
+
require 'fileutils'
|
7
8
|
require 'yaml'
|
8
9
|
|
9
10
|
require 'twitterpunch'
|
10
11
|
|
12
|
+
FileUtils.mkdir_p File.expand_path('~/.twitterpunch')
|
13
|
+
FileUtils.touch(File.expand_path('~/.twitterpunch/queue.yaml'))
|
14
|
+
|
11
15
|
configfile = File.expand_path('~/.twitterpunch.yaml')
|
12
16
|
config = YAML.load_file(configfile) rescue {}
|
13
17
|
|
@@ -44,10 +48,18 @@ optparse = OptionParser.new { |opts|
|
|
44
48
|
config[:action] = :configure
|
45
49
|
end
|
46
50
|
|
47
|
-
opts.on("-i", "--
|
51
|
+
opts.on("-i", "--remote", "Start the Twitterpunch remote web service") do
|
52
|
+
config[:action] = :remote
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on("-r", "--install", "Install the Folder Action workflow (OS X only).") do
|
48
56
|
config[:action] = :install
|
49
57
|
end
|
50
58
|
|
59
|
+
opts.on("-t", "--test", "Load up Pry debugging console.") do
|
60
|
+
config[:action] = :test
|
61
|
+
end
|
62
|
+
|
51
63
|
opts.on("-v", "--version", "Display version information.") do
|
52
64
|
puts "Twitterpunch v#{Twitterpunch::VERSION}"
|
53
65
|
exit 0
|
@@ -62,8 +74,11 @@ optparse = OptionParser.new { |opts|
|
|
62
74
|
}
|
63
75
|
optparse.parse!
|
64
76
|
|
65
|
-
config[:action]
|
66
|
-
config[:resources]
|
77
|
+
config[:action] = :post if ARGV.size > 0 and config[:action].nil?
|
78
|
+
config[:resources] = File.expand_path("#{File.dirname(__FILE__)}/../resources")
|
79
|
+
config[:queue] = {}
|
80
|
+
config[:queue][:file] = File.expand_path('~/.twitterpunch/queue.yaml')
|
81
|
+
config[:queue][:ttl] = 30
|
67
82
|
|
68
83
|
case config[:action]
|
69
84
|
when :stream
|
@@ -103,6 +118,20 @@ when :configure
|
|
103
118
|
when :install
|
104
119
|
system('open', "#{config[:resources]}/Twitterpunch.workflow")
|
105
120
|
|
121
|
+
when :remote
|
122
|
+
require 'twitterpunch/remote'
|
123
|
+
options = {
|
124
|
+
:port => 8080,
|
125
|
+
:bind => '0.0.0.0',
|
126
|
+
:queue => Twitterpunch::Queue.new(config),
|
127
|
+
}
|
128
|
+
|
129
|
+
Twitterpunch::Remote.run! options
|
130
|
+
|
131
|
+
when :test
|
132
|
+
require 'pry'
|
133
|
+
binding.pry
|
134
|
+
|
106
135
|
else
|
107
136
|
puts "Run twitterpunch --help for usage."
|
108
137
|
exit 1
|
data/lib/twitterpunch.rb
CHANGED
data/lib/twitterpunch/poster.rb
CHANGED
@@ -1,34 +1,40 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'twitter'
|
3
|
+
require 'twitterpunch/queue'
|
3
4
|
|
4
5
|
module Twitterpunch
|
5
6
|
class Poster
|
6
7
|
def initialize(config)
|
7
8
|
@config = config
|
8
9
|
@client = Twitter::REST::Client.new(config[:twitter])
|
10
|
+
@sound = @config[:sendsound] || "#{@config[:resources]}/tweet_sent.wav"
|
11
|
+
@length = 113 - @config[:hashtag].length
|
12
|
+
@queue = Twitterpunch::Queue.new(config)
|
9
13
|
end
|
10
14
|
|
11
15
|
def post(files)
|
12
16
|
files.each do |img|
|
17
|
+
message = @queue.pop || @config[:messages].sample
|
18
|
+
message = "#{message[0..@length]} ##{@config[:hashtag]}"
|
13
19
|
|
14
|
-
message = "#{@config[:messages].sample} ##{@config[:hashtag]}"
|
15
20
|
@client.update_with_media(message, File.new(File.expand_path(img)))
|
21
|
+
chirp()
|
22
|
+
end
|
23
|
+
end
|
16
24
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
puts 'gem install win32-sound to enable sounds.'
|
26
|
-
end
|
27
|
-
when /darwin/
|
28
|
-
system("afplay #{soundfile}")
|
25
|
+
def chirp
|
26
|
+
case RUBY_PLATFORM
|
27
|
+
when /mingw|cygwin/
|
28
|
+
begin
|
29
|
+
require 'win32/sound'
|
30
|
+
Win32::Sound.play(@sound)
|
31
|
+
rescue LoadError
|
32
|
+
puts 'gem install win32-sound to enable sounds.'
|
29
33
|
end
|
30
|
-
|
34
|
+
when /darwin/
|
35
|
+
system("afplay #{@sound}")
|
31
36
|
end
|
32
37
|
end
|
38
|
+
|
33
39
|
end
|
34
40
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class Twitterpunch::Queue
|
2
|
+
def initialize(config)
|
3
|
+
@config = config
|
4
|
+
@file = config[:queue][:file]
|
5
|
+
@ttl = config[:queue][:ttl]
|
6
|
+
end
|
7
|
+
|
8
|
+
def pop
|
9
|
+
message = nil
|
10
|
+
File.open(@file, 'r+') do |file|
|
11
|
+
file.flock(File::LOCK_EX)
|
12
|
+
queue = load(file)
|
13
|
+
|
14
|
+
unless queue.empty?
|
15
|
+
if RUBY_VERSION < "1.9.3"
|
16
|
+
message = queue[queue.keys.sort.first]
|
17
|
+
else
|
18
|
+
message = queue.shift[1]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
save(file, queue)
|
23
|
+
end
|
24
|
+
message
|
25
|
+
end
|
26
|
+
|
27
|
+
def push(message)
|
28
|
+
return unless message.is_a? String
|
29
|
+
return if message.empty?
|
30
|
+
File.open(@file, 'r+') do |file|
|
31
|
+
file.flock(File::LOCK_EX)
|
32
|
+
|
33
|
+
queue = load(file)
|
34
|
+
queue[Time.now] = message
|
35
|
+
save(file, queue)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def load(file)
|
40
|
+
queue = YAML.load(file.read) rescue {}
|
41
|
+
queue ||= {}
|
42
|
+
|
43
|
+
# forcibly expire anything that's too old.
|
44
|
+
queue.select { |k,v| (Time.now - k) < @ttl }
|
45
|
+
end
|
46
|
+
|
47
|
+
def save(file, queue)
|
48
|
+
puts "Saving #{queue.inspect}"
|
49
|
+
file.rewind
|
50
|
+
file.truncate 0
|
51
|
+
file.write(queue.to_yaml)
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'webrick'
|
3
|
+
require 'tilt/erb'
|
4
|
+
require 'open3'
|
5
|
+
require 'twitterpunch/queue'
|
6
|
+
|
7
|
+
class Twitterpunch::Remote < Sinatra::Base
|
8
|
+
|
9
|
+
set :views, File.dirname(__FILE__) + '/../../views'
|
10
|
+
set :public_folder, File.dirname(__FILE__) + '/../../public'
|
11
|
+
set :erb, :trim => '-'
|
12
|
+
set :configfile, File.expand_path('~/.twitterpunch/queue.yaml')
|
13
|
+
|
14
|
+
configure :production, :development do
|
15
|
+
enable :logging
|
16
|
+
enable :sessions
|
17
|
+
system('osascript', '-e' 'tell application "Photo Booth" to activate')
|
18
|
+
end
|
19
|
+
|
20
|
+
get '/' do
|
21
|
+
erb :index
|
22
|
+
end
|
23
|
+
|
24
|
+
get '/photo' do
|
25
|
+
settings.queue.push(params[:message]) unless params.empty?
|
26
|
+
photo()
|
27
|
+
end
|
28
|
+
|
29
|
+
not_found do
|
30
|
+
status 404
|
31
|
+
end
|
32
|
+
|
33
|
+
helpers do
|
34
|
+
def photo
|
35
|
+
begin
|
36
|
+
stdout, status = Open3.capture2e('osascript', '-e', 'tell application "Photo Booth" to activate')
|
37
|
+
puts stdout
|
38
|
+
raise "Could not activate Photo Booth" unless status.success?
|
39
|
+
|
40
|
+
# This is kind of iffy, because it depends on having full control over the UI.
|
41
|
+
# This will only work when Photo Booth actually has the foreground.
|
42
|
+
stdout, status = Open3.capture2e('osascript', '-e', 'tell application "System Events" to keystroke return')
|
43
|
+
puts stdout
|
44
|
+
raise "Snapshot failed" unless status.success?
|
45
|
+
|
46
|
+
'ok'
|
47
|
+
rescue => e
|
48
|
+
status 500
|
49
|
+
e.message
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
Binary file
|
Binary file
|
data/views/index.erb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
4
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
|
5
|
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
6
|
+
<meta name="apple-mobile-web-app-title" content="Twitterpunch" />
|
7
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
8
|
+
<link rel="apple-touch-icon" sizes="120x120" href="touch-icon-iphone-retina.png">
|
9
|
+
<link rel="apple-touch-icon" sizes="152x152" href="touch-icon-ipad-retina.png">
|
10
|
+
<title>Twitterpunch Remote</title>
|
11
|
+
<style>
|
12
|
+
body {
|
13
|
+
display: flex;
|
14
|
+
flex-direction: column;
|
15
|
+
margin: 0;
|
16
|
+
padding: 0;
|
17
|
+
height: 100%;
|
18
|
+
width: 100%;
|
19
|
+
background-color: black;
|
20
|
+
}
|
21
|
+
#message {
|
22
|
+
flex: 1;
|
23
|
+
font-size: 16px;
|
24
|
+
}
|
25
|
+
input[type=button] {
|
26
|
+
flex: 4;
|
27
|
+
margin: 5px;
|
28
|
+
padding: 0;
|
29
|
+
font-size: 104pt;
|
30
|
+
font-weight: bolder;
|
31
|
+
background-color: #5e5959;
|
32
|
+
border: 6px solid #ccc;
|
33
|
+
border-radius: 32px;
|
34
|
+
white-space:normal;
|
35
|
+
-webkit-appearance: none;
|
36
|
+
}
|
37
|
+
input.active {
|
38
|
+
color: white;
|
39
|
+
font-size: 64pt;
|
40
|
+
background-color: #5e2524;
|
41
|
+
}
|
42
|
+
body.focused #message {
|
43
|
+
flex: 2;
|
44
|
+
}
|
45
|
+
body.focused input[type=button] {
|
46
|
+
flex: 3;
|
47
|
+
margin-bottom: 325px;
|
48
|
+
font-size: 64pt;
|
49
|
+
}
|
50
|
+
|
51
|
+
@media screen and (max-width: 370px) and (orientation:portrait) {
|
52
|
+
input[type=button] {
|
53
|
+
font-size: 64pt;
|
54
|
+
}
|
55
|
+
input.active {
|
56
|
+
font-size: 52pt;
|
57
|
+
}
|
58
|
+
body.focused #message {
|
59
|
+
flex: 6;
|
60
|
+
}
|
61
|
+
body.focused input[type=button] {
|
62
|
+
flex: 4;
|
63
|
+
margin-bottom: 250px;
|
64
|
+
font-size: 20pt;
|
65
|
+
border-radius: 6px;
|
66
|
+
padding: 0;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
@media screen and (max-width: 650px) and (orientation:landscape) {
|
70
|
+
input[type=button] {
|
71
|
+
font-size: 84pt;
|
72
|
+
}
|
73
|
+
input.active {
|
74
|
+
font-size: 56pt;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
</style>
|
78
|
+
<script type="text/javascript">
|
79
|
+
function get(url, callback) {
|
80
|
+
var xmlHttp = new XMLHttpRequest();
|
81
|
+
xmlHttp.onreadystatechange = function() {
|
82
|
+
if (xmlHttp.readyState == 4) {
|
83
|
+
if(xmlHttp.status == 200) {
|
84
|
+
if(typeof(callback) == 'function') {
|
85
|
+
callback(xmlHttp.responseText);
|
86
|
+
}
|
87
|
+
}
|
88
|
+
else {
|
89
|
+
console.log(xmlHttp.responseText);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
xmlHttp.open("GET", url, true);
|
94
|
+
xmlHttp.send(null);
|
95
|
+
}
|
96
|
+
function activate() {
|
97
|
+
var msg = document.getElementById("message");
|
98
|
+
var btn = document.getElementById("btn");
|
99
|
+
var txt = msg.value;
|
100
|
+
btn.className = "active";
|
101
|
+
btn.value = "Say Cheese!";
|
102
|
+
|
103
|
+
setTimeout(function(){
|
104
|
+
btn.className = "";
|
105
|
+
btn.value = "Push Me";
|
106
|
+
msg.value = "";
|
107
|
+
},3000);
|
108
|
+
|
109
|
+
if (txt == "") {
|
110
|
+
get('/photo');
|
111
|
+
}
|
112
|
+
else {
|
113
|
+
get('/photo?message='+txt);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
function shrink() {
|
117
|
+
var body = document.getElementsByTagName("body")[0];
|
118
|
+
body.className = "focused";
|
119
|
+
}
|
120
|
+
function expand() {
|
121
|
+
var body = document.getElementsByTagName("body")[0];
|
122
|
+
body.className = "";
|
123
|
+
}
|
124
|
+
</script>
|
125
|
+
</head>
|
126
|
+
<body>
|
127
|
+
<textarea id="message" class="item" placeholder="Enter a message if you like..." onclick="shrink()" onblur="expand()"></textarea>
|
128
|
+
<input type="button" id="btn" class="item" value="Push Me" onClick="activate()" />
|
129
|
+
</body>
|
130
|
+
<script>
|
131
|
+
// really truly disable the shit out of pinch-to-zoom
|
132
|
+
var lastTouchEnd = 0;
|
133
|
+
document.documentElement.addEventListener('touchend', function (event) {
|
134
|
+
var now = (new Date()).getTime();
|
135
|
+
if (now - lastTouchEnd <= 300) {
|
136
|
+
event.preventDefault();
|
137
|
+
}
|
138
|
+
lastTouchEnd = now;
|
139
|
+
}, false);
|
140
|
+
|
141
|
+
document.documentElement.addEventListener('touchstart', function (event) {
|
142
|
+
if (event.touches.length > 1) {
|
143
|
+
event.preventDefault();
|
144
|
+
}
|
145
|
+
}, false);
|
146
|
+
</script>
|
147
|
+
</html>
|
metadata
CHANGED
@@ -1,69 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twitterpunch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Ford
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-12-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: twitter
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: oauth
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: colorize
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rubygame
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
description: "Twitterpunch\n===============\n\nTwitterpunch is designed to work with
|
@@ -134,6 +134,8 @@ files:
|
|
134
134
|
- lib/twitterpunch/configuration.rb
|
135
135
|
- lib/twitterpunch/logger.rb
|
136
136
|
- lib/twitterpunch/poster.rb
|
137
|
+
- lib/twitterpunch/queue.rb
|
138
|
+
- lib/twitterpunch/remote.rb
|
137
139
|
- lib/twitterpunch/sprite.rb
|
138
140
|
- lib/twitterpunch/streamer.rb
|
139
141
|
- lib/twitterpunch/viewer.rb
|
@@ -144,6 +146,9 @@ files:
|
|
144
146
|
- resources/Twitterpunch.workflow/Contents/document.wflow
|
145
147
|
- resources/say.vbs
|
146
148
|
- resources/tweet_sent.wav
|
149
|
+
- views/index.erb
|
150
|
+
- public/touch-icon-ipad-retina.png
|
151
|
+
- public/touch-icon-iphone-retina.png
|
147
152
|
homepage: http://binford2k.com
|
148
153
|
licenses: []
|
149
154
|
metadata: {}
|
@@ -162,17 +167,17 @@ require_paths:
|
|
162
167
|
- lib
|
163
168
|
required_ruby_version: !ruby/object:Gem::Requirement
|
164
169
|
requirements:
|
165
|
-
- -
|
170
|
+
- - ">="
|
166
171
|
- !ruby/object:Gem::Version
|
167
172
|
version: '0'
|
168
173
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
174
|
requirements:
|
170
|
-
- -
|
175
|
+
- - ">="
|
171
176
|
- !ruby/object:Gem::Version
|
172
177
|
version: '0'
|
173
178
|
requirements: []
|
174
179
|
rubyforge_project:
|
175
|
-
rubygems_version: 2.0.14
|
180
|
+
rubygems_version: 2.0.14.1
|
176
181
|
signing_key:
|
177
182
|
specification_version: 4
|
178
183
|
summary: A simple tool to automate the posting and streaming of PhotoBooth shots over
|