nyancat 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/nyancat +37 -1
- data/lib/nyancat.rb +109 -40
- metadata +5 -5
data/bin/nyancat
CHANGED
@@ -36,6 +36,8 @@ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
36
36
|
require 'nyancat'
|
37
37
|
require 'optparse'
|
38
38
|
|
39
|
+
port = 23
|
40
|
+
telnet = false
|
39
41
|
options = {}
|
40
42
|
OptionParser.new do |opts|
|
41
43
|
opts.banner = "Usage: nyancat [options]"
|
@@ -46,6 +48,40 @@ OptionParser.new do |opts|
|
|
46
48
|
opts.on("-f", "--flavour FLAVOUR", "Available flavours: #{NyanCat.flavours.join(', ')}") do |f|
|
47
49
|
options[:flavour] = f
|
48
50
|
end
|
51
|
+
opts.on("-n", "--notime", "Don't show the time nyaned") do |n|
|
52
|
+
options[:hide_time] = n
|
53
|
+
end
|
54
|
+
opts.on("-l", "--listen [PORT]", "Run telnet server on PORT (default 21)") do |p|
|
55
|
+
telnet = true
|
56
|
+
port = p || 23
|
57
|
+
end
|
58
|
+
opts.on("-t", "--timeout SECONDS", "Timeout after SECONDS") do |t|
|
59
|
+
options[:timeout] = t.to_i
|
60
|
+
end
|
49
61
|
end.parse!
|
50
62
|
|
51
|
-
|
63
|
+
if telnet
|
64
|
+
# Start a new server listening on specified port
|
65
|
+
server = NyanCat::NyanServer.new(port, "::", options)
|
66
|
+
server.audit = true
|
67
|
+
server.start
|
68
|
+
server.join
|
69
|
+
else
|
70
|
+
stdout = IO.new STDOUT.fileno
|
71
|
+
|
72
|
+
# Get TTY size
|
73
|
+
options[:width], options[:height] = `stty size`.split.map { |x| x.to_i }.reverse
|
74
|
+
|
75
|
+
begin
|
76
|
+
n = NyanCat::NyanCat.new(stdout, options)
|
77
|
+
n.run
|
78
|
+
rescue SignalException => e
|
79
|
+
# Do nothing, exit gracefully
|
80
|
+
rescue Exception => e
|
81
|
+
puts "Oops, something went wrong..."
|
82
|
+
raise e
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
|
data/lib/nyancat.rb
CHANGED
@@ -31,6 +31,8 @@
|
|
31
31
|
# WITH THE SOFTWARE.
|
32
32
|
|
33
33
|
require 'yaml'
|
34
|
+
require 'gserver'
|
35
|
+
require 'timeout'
|
34
36
|
|
35
37
|
module NyanCat
|
36
38
|
OUTPUT_CHAR = " "
|
@@ -39,58 +41,125 @@ module NyanCat
|
|
39
41
|
return Dir.entries(File.expand_path("../nyancat/", __FILE__)).select { |entry| !(entry =='.' || entry == '..') }
|
40
42
|
end
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
44
|
+
class NyanCat
|
45
|
+
def initialize(io, options)
|
46
|
+
@running = false
|
47
|
+
@io = io
|
48
|
+
@term_width = options[:width] || 80
|
49
|
+
@term_height = options[:height] || 24
|
50
|
+
@mute = options[:mute] || false
|
51
|
+
@hide_time = options[:hide_time] || false
|
45
52
|
|
46
|
-
|
47
|
-
|
48
|
-
|
53
|
+
flavour = options[:flavour] || 'original'
|
54
|
+
frames = YAML.load_file(File.expand_path("../nyancat/#{flavour}/frames.yml", __FILE__))
|
55
|
+
palette = YAML.load_file(File.expand_path("../nyancat/#{flavour}/palette.yml", __FILE__))
|
49
56
|
|
50
|
-
|
51
|
-
term_width, term_height = `stty size`.split.map { |x| x.to_i }.reverse
|
57
|
+
@audio = File.expand_path("../nyancat/#{flavour}/audio.mp3", __FILE__)
|
52
58
|
|
53
|
-
|
54
|
-
|
59
|
+
# Calculate the width in terms of the output char
|
60
|
+
term_width = @term_width / OUTPUT_CHAR.length
|
61
|
+
term_height = @term_height
|
55
62
|
|
56
|
-
|
57
|
-
|
63
|
+
min_row = 0
|
64
|
+
max_row = frames[0].length
|
58
65
|
|
59
|
-
|
60
|
-
|
66
|
+
min_col = 0
|
67
|
+
max_col = frames[0][0].length
|
61
68
|
|
62
|
-
|
63
|
-
|
69
|
+
min_row = (max_row - term_height) / 2 if max_row > term_height
|
70
|
+
max_row = min_row + term_height if max_row > term_height
|
64
71
|
|
65
|
-
|
66
|
-
|
72
|
+
min_col = (max_col - term_width) / 2 if max_col > term_width
|
73
|
+
max_col = min_col + term_width if max_col > term_width
|
67
74
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
75
|
+
# Calculate the final animation width
|
76
|
+
@anim_width = (max_col - min_col) * OUTPUT_CHAR.length
|
77
|
+
|
78
|
+
# Precompute frames
|
79
|
+
@frames = frames.map do |frame|
|
80
|
+
frame[min_row...max_row].map do |line|
|
81
|
+
line.chars.to_a[min_col...max_col].map do |c|
|
82
|
+
"\033[48;5;%dm%s" % [palette[c], OUTPUT_CHAR]
|
83
|
+
end.join + "\033[m\n"
|
84
|
+
end
|
85
|
+
end
|
74
86
|
end
|
75
87
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
88
|
+
def run()
|
89
|
+
@running = true
|
90
|
+
|
91
|
+
begin
|
92
|
+
# Initialise term
|
93
|
+
@io.printf("\033[H\033[2J\033[?25l")
|
94
|
+
|
95
|
+
# Get start time
|
96
|
+
start_time = Time.now()
|
97
|
+
|
98
|
+
# Play audio
|
99
|
+
audio_t = Thread.new { IO.popen("mpg123 -loop 0 -q #{@audio} > /dev/null 2>&1") } unless @mute || nil
|
100
|
+
|
101
|
+
while @running
|
102
|
+
@frames.each do |frame|
|
103
|
+
# Print the next frame
|
104
|
+
@io.puts frame
|
105
|
+
|
106
|
+
# Print the time so far
|
107
|
+
unless @hide_time
|
108
|
+
time = "You have nyaned for %0.0f seconds!" % [Time.now() - start_time]
|
109
|
+
time = time.center(@anim_width)
|
110
|
+
@io.printf("\033[1;37;17m%s", time)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Reset the frame and sleep
|
114
|
+
@io.printf("\033[H")
|
115
|
+
sleep(0.09)
|
116
|
+
end
|
85
117
|
end
|
118
|
+
|
119
|
+
ensure
|
120
|
+
# Ensure the audio thread is killed, if it exists
|
121
|
+
audio_t.kill unless audio_t.nil?
|
122
|
+
stop
|
123
|
+
reset
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def stop()
|
128
|
+
@running = false
|
129
|
+
end
|
130
|
+
|
131
|
+
def reset()
|
132
|
+
begin
|
133
|
+
@io.puts("\033[0m\033c")
|
134
|
+
rescue Errno::EPIPE => e
|
135
|
+
# We failed to reset the TERM, IO stream is gone
|
86
136
|
end
|
87
|
-
rescue SignalException => e
|
88
|
-
printf("\033c\033c")
|
89
|
-
printf("YOU NYANED FOR %4.2f SECONDS\n", Time.now - start_time)
|
90
|
-
rescue Exception => e
|
91
|
-
printf("\033c")
|
92
|
-
puts "Oops, something went wrong..."
|
93
|
-
raise e
|
94
137
|
end
|
95
138
|
end
|
139
|
+
|
140
|
+
class NyanServer < GServer
|
141
|
+
def initialize(port, address, options = {})
|
142
|
+
@options = options
|
143
|
+
@options[:mute] = true
|
144
|
+
@timeout = @options[:timeout]
|
145
|
+
super(port, address)
|
146
|
+
end
|
147
|
+
|
148
|
+
def serve(io)
|
149
|
+
n = NyanCat.new(io, @options)
|
150
|
+
begin
|
151
|
+
# run the animation thread
|
152
|
+
t = Thread.new(n) { |nyan| nyan.run() }
|
153
|
+
|
154
|
+
# block until any input is received or timeout is reached, then die
|
155
|
+
Timeout::timeout(@timeout) { io.readline() }
|
156
|
+
rescue Exception => e
|
157
|
+
log("Client error: #{e}")
|
158
|
+
ensure
|
159
|
+
n.stop
|
160
|
+
t.join
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
96
165
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nyancat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
4
5
|
prerelease:
|
5
|
-
version: 0.1.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ben Arblaster
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-02-01 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A Ruby port of Kevin Lange's nyancat
|
15
15
|
email: ben@andatche.com
|
@@ -30,20 +30,20 @@ rdoc_options: []
|
|
30
30
|
require_paths:
|
31
31
|
- lib
|
32
32
|
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
33
34
|
requirements:
|
34
35
|
- - ! '>='
|
35
36
|
- !ruby/object:Gem::Version
|
36
37
|
version: '0'
|
37
|
-
none: false
|
38
38
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
39
40
|
requirements:
|
40
41
|
- - ! '>='
|
41
42
|
- !ruby/object:Gem::Version
|
42
43
|
version: '0'
|
43
|
-
none: false
|
44
44
|
requirements: []
|
45
45
|
rubyforge_project:
|
46
|
-
rubygems_version: 1.8.
|
46
|
+
rubygems_version: 1.8.25
|
47
47
|
signing_key:
|
48
48
|
specification_version: 3
|
49
49
|
summary: nyancat on your terminal
|