nyancat 0.1.0 → 0.2.0
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/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
|