ssc.nob 0.1.0-java → 0.1.1-java
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/CHANGELOG.md +30 -2
- data/Gemfile +1 -19
- data/Gemfile.lock +49 -0
- data/README.md +56 -8
- data/Rakefile +52 -25
- data/bin/ssc.nob +3 -14
- data/lib/ssc.nob.rb +743 -156
- data/lib/ssc.nob/config.rb +94 -59
- data/lib/ssc.nob/error.rb +5 -17
- data/lib/ssc.nob/ssc_bot.rb +67 -88
- data/lib/ssc.nob/ssc_chat_log.rb +34 -46
- data/lib/ssc.nob/ssc_chat_log/message.rb +15 -27
- data/lib/ssc.nob/ssc_chat_log/message_parser.rb +39 -51
- data/lib/ssc.nob/userface.rb +33 -45
- data/lib/ssc.nob/util.rb +14 -26
- data/lib/ssc.nob/version.rb +4 -16
- data/ssc.nob.gemspec +24 -43
- metadata +45 -15
data/lib/ssc.nob/config.rb
CHANGED
@@ -1,87 +1,107 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
# encoding: UTF-8
|
3
2
|
# frozen_string_literal: true
|
4
3
|
|
5
4
|
#--
|
6
5
|
# This file is part of SSC.Nob.
|
7
|
-
# Copyright (c) 2020 Jonathan Bradley Whited
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# it under the terms of the GNU General Public License as published by
|
11
|
-
# the Free Software Foundation, either version 3 of the License, or
|
12
|
-
# (at your option) any later version.
|
13
|
-
#
|
14
|
-
# SSC.Nob is distributed in the hope that it will be useful,
|
15
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
-
# GNU General Public License for more details.
|
18
|
-
#
|
19
|
-
# You should have received a copy of the GNU General Public License
|
20
|
-
# along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
|
6
|
+
# Copyright (c) 2020-2021 Jonathan Bradley Whited
|
7
|
+
#
|
8
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
21
9
|
#++
|
22
10
|
|
23
11
|
|
12
|
+
require 'java'
|
24
13
|
require 'psych'
|
25
14
|
|
26
15
|
require 'ssc.nob/error'
|
27
16
|
require 'ssc.nob/userface'
|
28
17
|
require 'ssc.nob/util'
|
29
18
|
|
19
|
+
java_import 'java.awt.event.KeyEvent'
|
20
|
+
|
30
21
|
|
31
22
|
module SSCNob
|
32
23
|
###
|
33
|
-
# @author Jonathan Bradley Whited
|
24
|
+
# @author Jonathan Bradley Whited
|
34
25
|
# @since 0.1.0
|
35
26
|
###
|
36
27
|
class Config
|
37
28
|
include Uface
|
38
|
-
|
29
|
+
|
39
30
|
attr_reader :file
|
31
|
+
attr_accessor :msg_key
|
40
32
|
attr_accessor :ssc_dir
|
41
33
|
attr_accessor :username
|
42
|
-
|
34
|
+
|
43
35
|
def initialize(file='ssc.nob.yml')
|
44
36
|
super()
|
45
|
-
|
37
|
+
|
46
38
|
@file = File.expand_path(file)
|
39
|
+
@msg_key = nil
|
47
40
|
@ssc_dir = nil
|
48
41
|
@username = nil
|
49
42
|
end
|
50
|
-
|
51
|
-
def
|
43
|
+
|
44
|
+
def build_msg_key
|
45
|
+
# Can be a single space ' '.
|
46
|
+
return @msg_key if @msg_key.nil? || @msg_key.length == 1
|
47
|
+
|
48
|
+
fuzzy_key = Util.strip(@msg_key).downcase
|
49
|
+
|
50
|
+
if fuzzy_key.empty?
|
51
|
+
@msg_key = nil
|
52
|
+
|
53
|
+
return @msg_key
|
54
|
+
end
|
55
|
+
|
56
|
+
KeyEvent.constants.each do |c|
|
57
|
+
name = c.to_s.downcase
|
58
|
+
|
59
|
+
if name.start_with?('vk_') && name.include?(fuzzy_key)
|
60
|
+
return KeyEvent.const_get(c)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
raise UserError,"that's an invalid msg key{#{@msg_key}}, user."
|
65
|
+
end
|
66
|
+
|
67
|
+
def build_ssc_log_dir
|
52
68
|
return File.join(@ssc_dir,'logs')
|
53
69
|
end
|
54
|
-
|
55
|
-
def
|
70
|
+
|
71
|
+
def check_msg_key
|
72
|
+
build_msg_key
|
73
|
+
end
|
74
|
+
|
75
|
+
def check_ssc_dir
|
56
76
|
@ssc_dir = Util.strip(@ssc_dir)
|
57
|
-
|
58
|
-
if @ssc_dir.nil?
|
77
|
+
|
78
|
+
if @ssc_dir.nil? || @ssc_dir.empty?
|
59
79
|
raise UserError,"that's a blank folder name, user."
|
60
80
|
end
|
61
|
-
|
81
|
+
|
62
82
|
@ssc_dir = File.expand_path(@ssc_dir)
|
63
|
-
|
83
|
+
|
64
84
|
if !Dir.exist?(@ssc_dir)
|
65
85
|
raise UserError,"that folder{#{@ssc_dir}} doesn't exist, user."
|
66
86
|
end
|
67
87
|
if !File.directory?(@ssc_dir)
|
68
88
|
raise UserError,"that's a file{#{@ssc_dir}}, not a folder, user."
|
69
89
|
end
|
70
|
-
|
71
|
-
ssc_log_dir = build_ssc_log_dir
|
72
|
-
|
90
|
+
|
91
|
+
ssc_log_dir = build_ssc_log_dir
|
92
|
+
|
73
93
|
if !Dir.exist?(ssc_log_dir) || !File.directory?(ssc_log_dir)
|
74
94
|
raise UserError,"why's there no 'logs' folder{#{ssc_log_dir}}, user?"
|
75
95
|
end
|
76
96
|
end
|
77
|
-
|
78
|
-
def check_username
|
97
|
+
|
98
|
+
def check_username
|
79
99
|
raise UserError,"that's a blank username, user." if Util.blank?(@username)
|
80
100
|
end
|
81
|
-
|
101
|
+
|
82
102
|
def load_file!(mode: 'rt:BOM|UTF-8',**kargs)
|
83
103
|
data = File.read(@file,mode: mode,**kargs)
|
84
|
-
|
104
|
+
|
85
105
|
yaml = Psych.safe_load(data,
|
86
106
|
aliases: false,
|
87
107
|
filename: @file,
|
@@ -89,63 +109,78 @@ module SSCNob
|
|
89
109
|
symbolize_names: true,
|
90
110
|
**kargs,
|
91
111
|
)
|
92
|
-
|
112
|
+
|
113
|
+
@msg_key = yaml[:msg_key]
|
93
114
|
@ssc_dir = Util.strip(yaml[:ssc_dir])
|
94
|
-
@ssc_dir = File.expand_path(@ssc_dir) if !@ssc_dir.nil?
|
115
|
+
@ssc_dir = File.expand_path(@ssc_dir) if !@ssc_dir.nil? && !@ssc_dir.empty?
|
95
116
|
@username = yaml[:username]
|
96
117
|
end
|
97
|
-
|
118
|
+
|
98
119
|
def save_file(mode: 'wt',**kargs)
|
99
120
|
File.open(@file,mode: mode,**kargs) do |fout|
|
100
|
-
fout.write(to_s
|
121
|
+
fout.write(to_s)
|
101
122
|
end
|
102
123
|
end
|
103
|
-
|
104
|
-
def user_init!
|
124
|
+
|
125
|
+
def user_init!
|
105
126
|
if File.exist?(@file)
|
106
|
-
load_file!
|
127
|
+
load_file!
|
107
128
|
end
|
108
|
-
|
109
|
-
if valid?
|
110
|
-
uface.type(
|
129
|
+
|
130
|
+
if valid?
|
131
|
+
uface.type('Welcome back, ')
|
111
132
|
puts "#{uface.user(@username)}."
|
112
133
|
uface.type("Here's a hot cup of coffee: ")
|
113
134
|
puts uface.coffee
|
114
135
|
else
|
115
136
|
uface.types('Welcome, new user.')
|
116
137
|
puts
|
117
|
-
|
138
|
+
|
118
139
|
@username = uface.ask("What's your #{uface.user('username')}? ")
|
119
|
-
check_username
|
120
|
-
|
140
|
+
check_username
|
141
|
+
|
121
142
|
@ssc_dir = uface.ask("Where's your #{uface.ssc} folder? ")
|
122
|
-
check_ssc_dir
|
123
|
-
|
143
|
+
check_ssc_dir
|
144
|
+
|
145
|
+
puts(<<~MSGKEY)
|
146
|
+
What's your #{uface.color('Message Key').aqua.bold}?
|
147
|
+
- Can input a key code, like 'VK_TAB' or 'TAB'
|
148
|
+
- Can input a letter, like 'm'
|
149
|
+
- Can input nothing
|
150
|
+
MSGKEY
|
151
|
+
@msg_key = uface.ask('> ')
|
152
|
+
check_msg_key
|
153
|
+
|
124
154
|
puts
|
125
155
|
puts uface.gt(@file)
|
126
156
|
if uface.agree('Save this configuration (y/n)? ')
|
127
|
-
save_file
|
157
|
+
save_file
|
128
158
|
end
|
129
159
|
end
|
130
160
|
end
|
131
|
-
|
132
|
-
def valid?
|
161
|
+
|
162
|
+
def valid?
|
133
163
|
begin
|
134
|
-
|
135
|
-
|
136
|
-
|
164
|
+
check_msg_key
|
165
|
+
check_ssc_dir
|
166
|
+
check_username
|
167
|
+
rescue UserError => e
|
168
|
+
puts e.to_s.capitalize
|
169
|
+
puts
|
170
|
+
|
137
171
|
return false
|
138
172
|
end
|
139
|
-
|
173
|
+
|
140
174
|
return true
|
141
175
|
end
|
142
|
-
|
143
|
-
def to_s
|
176
|
+
|
177
|
+
def to_s
|
144
178
|
yaml = {
|
179
|
+
'msg_key' => @msg_key,
|
145
180
|
'username' => @username,
|
146
181
|
'ssc_dir' => @ssc_dir,
|
147
182
|
}
|
148
|
-
|
183
|
+
|
149
184
|
return Psych.dump(yaml,header: true)
|
150
185
|
end
|
151
186
|
end
|
data/lib/ssc.nob/error.rb
CHANGED
@@ -1,32 +1,20 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
# encoding: UTF-8
|
3
2
|
# frozen_string_literal: true
|
4
3
|
|
5
4
|
#--
|
6
5
|
# This file is part of SSC.Nob.
|
7
|
-
# Copyright (c) 2020 Jonathan Bradley Whited
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# it under the terms of the GNU General Public License as published by
|
11
|
-
# the Free Software Foundation, either version 3 of the License, or
|
12
|
-
# (at your option) any later version.
|
13
|
-
#
|
14
|
-
# SSC.Nob is distributed in the hope that it will be useful,
|
15
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
-
# GNU General Public License for more details.
|
18
|
-
#
|
19
|
-
# You should have received a copy of the GNU General Public License
|
20
|
-
# along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
|
6
|
+
# Copyright (c) 2020-2021 Jonathan Bradley Whited
|
7
|
+
#
|
8
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
21
9
|
#++
|
22
10
|
|
23
11
|
|
24
12
|
module SSCNob
|
25
13
|
###
|
26
|
-
# @author Jonathan Bradley Whited
|
14
|
+
# @author Jonathan Bradley Whited
|
27
15
|
# @since 0.1.0
|
28
16
|
###
|
29
17
|
class Error < ::StandardError; end
|
30
|
-
|
18
|
+
|
31
19
|
class UserError < Error; end
|
32
20
|
end
|
data/lib/ssc.nob/ssc_bot.rb
CHANGED
@@ -1,23 +1,11 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
# encoding: UTF-8
|
3
2
|
# frozen_string_literal: true
|
4
3
|
|
5
4
|
#--
|
6
5
|
# This file is part of SSC.Nob.
|
7
|
-
# Copyright (c) 2020 Jonathan Bradley Whited
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# it under the terms of the GNU General Public License as published by
|
11
|
-
# the Free Software Foundation, either version 3 of the License, or
|
12
|
-
# (at your option) any later version.
|
13
|
-
#
|
14
|
-
# SSC.Nob is distributed in the hope that it will be useful,
|
15
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
-
# GNU General Public License for more details.
|
18
|
-
#
|
19
|
-
# You should have received a copy of the GNU General Public License
|
20
|
-
# along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
|
6
|
+
# Copyright (c) 2020-2021 Jonathan Bradley Whited
|
7
|
+
#
|
8
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
21
9
|
#++
|
22
10
|
|
23
11
|
|
@@ -36,129 +24,118 @@ java_import 'java.awt.event.KeyEvent'
|
|
36
24
|
|
37
25
|
module SSCNob
|
38
26
|
###
|
39
|
-
# @author Jonathan Bradley Whited
|
27
|
+
# @author Jonathan Bradley Whited
|
40
28
|
# @since 0.1.0
|
41
29
|
###
|
42
30
|
class SSCBot
|
43
31
|
MESSAGE_FLOOD_COUNT = 8
|
44
|
-
MESSAGE_FLOOD_TIME =
|
45
|
-
|
32
|
+
MESSAGE_FLOOD_TIME = 6
|
33
|
+
|
46
34
|
attr_accessor :auto_delay_time
|
47
35
|
attr_reader :char_codes
|
48
36
|
attr_reader :clipboard
|
49
37
|
attr_reader :last_message_time
|
50
38
|
attr_reader :message_count
|
51
|
-
attr_accessor :message_key
|
52
39
|
attr_reader :robot
|
53
|
-
|
54
|
-
|
55
|
-
def initialize(auto_delay_time: 0.2,message_key: KeyEvent::VK_TAB)
|
40
|
+
|
41
|
+
def initialize(auto_delay_time: 0.1)
|
56
42
|
super()
|
57
|
-
|
43
|
+
|
58
44
|
@auto_delay_time = auto_delay_time
|
59
45
|
@char_codes = {}
|
60
|
-
@clipboard = Toolkit.getDefaultToolkit
|
61
|
-
@last_message_time = Time.now
|
46
|
+
@clipboard = Toolkit.getDefaultToolkit.getSystemClipboard
|
47
|
+
@last_message_time = Time.now
|
62
48
|
@message_count = 0
|
63
|
-
@
|
64
|
-
|
65
|
-
|
49
|
+
@robot = Robot.new
|
50
|
+
|
66
51
|
@robot.setAutoDelay(0) # Don't use Java's, too slow
|
67
|
-
|
68
|
-
build_char_codes
|
52
|
+
|
53
|
+
build_char_codes
|
69
54
|
end
|
70
|
-
|
71
|
-
def auto_delay
|
55
|
+
|
56
|
+
def auto_delay
|
72
57
|
sleep(@auto_delay_time)
|
73
|
-
|
58
|
+
|
74
59
|
return self
|
75
60
|
end
|
76
|
-
|
61
|
+
|
77
62
|
def chat_message(channel,msg)
|
78
63
|
return pub_message(";#{channel};#{msg}")
|
79
64
|
end
|
80
|
-
|
65
|
+
|
81
66
|
def copy(str)
|
82
|
-
@clipboard.setContents(StringSelection.new(str),nil)
|
83
|
-
|
67
|
+
@clipboard.setContents(StringSelection.new(str),nil)
|
68
|
+
|
84
69
|
return self
|
85
70
|
end
|
86
|
-
|
87
|
-
def enter
|
71
|
+
|
72
|
+
def enter
|
88
73
|
return type_key(KeyEvent::VK_ENTER)
|
89
74
|
end
|
90
|
-
|
75
|
+
|
91
76
|
def paste(str=nil)
|
92
|
-
copy(str) unless str.nil?
|
93
|
-
|
77
|
+
copy(str) unless str.nil?
|
78
|
+
|
94
79
|
# FIXME: change to VK_META for macOS
|
95
80
|
roll_keys(KeyEvent::VK_CONTROL,KeyEvent::VK_V)
|
96
|
-
|
81
|
+
|
97
82
|
return self
|
98
83
|
end
|
99
|
-
|
100
|
-
def prevent_flooding
|
84
|
+
|
85
|
+
def prevent_flooding
|
101
86
|
@message_count += 1
|
102
|
-
|
87
|
+
|
103
88
|
if @message_count >= MESSAGE_FLOOD_COUNT
|
104
|
-
time_diff = Time.now
|
105
|
-
|
106
|
-
if time_diff
|
107
|
-
|
108
|
-
|
109
|
-
|
89
|
+
time_diff = Time.now - @last_message_time
|
90
|
+
time_diff = (MESSAGE_FLOOD_TIME - time_diff).round
|
91
|
+
time_diff = 1 if time_diff < 1 # Always sleep for at least 1 sec
|
92
|
+
|
93
|
+
sleep(time_diff)
|
94
|
+
|
110
95
|
@message_count = 0
|
111
96
|
end
|
112
|
-
|
113
|
-
@last_message_time = Time.now
|
114
|
-
|
115
|
-
return self
|
116
|
-
end
|
117
|
-
|
118
|
-
def pub_message(msg)
|
119
|
-
type_key(@message_key).paste(msg).enter()
|
120
|
-
|
121
|
-
sleep(1.2)
|
122
|
-
|
97
|
+
|
98
|
+
@last_message_time = Time.now
|
99
|
+
|
123
100
|
return self
|
124
101
|
end
|
125
|
-
|
102
|
+
|
126
103
|
def roll_keys(*key_codes)
|
127
|
-
key_codes.each
|
104
|
+
key_codes.each do |key_code|
|
128
105
|
@robot.keyPress(key_code)
|
129
|
-
auto_delay
|
106
|
+
auto_delay
|
130
107
|
end
|
131
|
-
|
108
|
+
|
132
109
|
(key_codes.length - 1).downto(0) do |i|
|
133
110
|
@robot.keyRelease(key_codes[i])
|
134
|
-
auto_delay
|
111
|
+
auto_delay
|
135
112
|
end
|
136
|
-
|
113
|
+
|
137
114
|
return self
|
138
115
|
end
|
139
|
-
|
116
|
+
|
140
117
|
def type(str)
|
141
|
-
str.each_char
|
118
|
+
str.each_char do |c|
|
142
119
|
key_codes = @char_codes[c]
|
143
|
-
|
144
|
-
next if key_codes.nil?
|
145
|
-
|
120
|
+
|
121
|
+
next if key_codes.nil?
|
122
|
+
|
146
123
|
roll_keys(*key_codes)
|
147
124
|
end
|
148
|
-
|
125
|
+
|
149
126
|
return self
|
150
127
|
end
|
151
|
-
|
128
|
+
|
152
129
|
def type_key(key_code)
|
153
130
|
@robot.keyPress(key_code)
|
154
|
-
auto_delay
|
131
|
+
auto_delay
|
155
132
|
@robot.keyRelease(key_code)
|
156
|
-
auto_delay
|
157
|
-
|
133
|
+
auto_delay
|
134
|
+
|
158
135
|
return self
|
159
136
|
end
|
160
|
-
|
161
|
-
def build_char_codes
|
137
|
+
|
138
|
+
def build_char_codes
|
162
139
|
@char_codes.store("\b",[KeyEvent::VK_BACK_SPACE])
|
163
140
|
@char_codes.store("\f",[KeyEvent::VK_PAGE_DOWN])
|
164
141
|
@char_codes.store("\n",[KeyEvent::VK_ENTER])
|
@@ -167,15 +144,15 @@ module SSCNob
|
|
167
144
|
@char_codes.store(' ',[KeyEvent::VK_SPACE])
|
168
145
|
@char_codes.store('!',[KeyEvent::VK_SHIFT,KeyEvent::VK_EXCLAMATION_MARK])
|
169
146
|
@char_codes.store('"',[KeyEvent::VK_SHIFT,KeyEvent::VK_QUOTEDBL])
|
170
|
-
@char_codes.store('#',[KeyEvent::VK_SHIFT,KeyEvent::
|
171
|
-
@char_codes.store('$',[KeyEvent::VK_SHIFT,KeyEvent::
|
147
|
+
@char_codes.store('#',[KeyEvent::VK_SHIFT,KeyEvent::VK_NUMBER_SIGN])
|
148
|
+
@char_codes.store('$',[KeyEvent::VK_SHIFT,KeyEvent::VK_DOLLAR])
|
172
149
|
@char_codes.store('%',[KeyEvent::VK_SHIFT,KeyEvent::VK_5])
|
173
|
-
@char_codes.store('&',[KeyEvent::VK_SHIFT,KeyEvent::
|
150
|
+
@char_codes.store('&',[KeyEvent::VK_SHIFT,KeyEvent::VK_AMPERSAND])
|
174
151
|
@char_codes.store('\'',[KeyEvent::VK_QUOTE])
|
175
|
-
@char_codes.store('(',[KeyEvent::VK_SHIFT,KeyEvent::
|
176
|
-
@char_codes.store(')',[KeyEvent::VK_SHIFT,KeyEvent::
|
177
|
-
@char_codes.store('*',[KeyEvent::VK_SHIFT,KeyEvent::
|
178
|
-
@char_codes.store('+',[KeyEvent::VK_SHIFT,KeyEvent::
|
152
|
+
@char_codes.store('(',[KeyEvent::VK_SHIFT,KeyEvent::VK_LEFT_PARENTHESIS])
|
153
|
+
@char_codes.store(')',[KeyEvent::VK_SHIFT,KeyEvent::VK_RIGHT_PARENTHESIS])
|
154
|
+
@char_codes.store('*',[KeyEvent::VK_SHIFT,KeyEvent::VK_ASTERISK])
|
155
|
+
@char_codes.store('+',[KeyEvent::VK_SHIFT,KeyEvent::VK_PLUS])
|
179
156
|
@char_codes.store(',',[KeyEvent::VK_COMMA])
|
180
157
|
@char_codes.store('-',[KeyEvent::VK_MINUS])
|
181
158
|
@char_codes.store('.',[KeyEvent::VK_PERIOD])
|
@@ -259,6 +236,8 @@ module SSCNob
|
|
259
236
|
@char_codes.store('|',[KeyEvent::VK_SHIFT,KeyEvent::VK_BACK_SLASH])
|
260
237
|
@char_codes.store('}',[KeyEvent::VK_SHIFT,KeyEvent::VK_BRACERIGHT])
|
261
238
|
@char_codes.store('~',[KeyEvent::VK_SHIFT,KeyEvent::VK_BACK_QUOTE])
|
239
|
+
@char_codes.store('¡',[KeyEvent::VK_SHIFT,KeyEvent::VK_INVERTED_EXCLAMATION_MARK])
|
240
|
+
@char_codes.store('€',[KeyEvent::VK_SHIFT,KeyEvent::VK_EURO_SIGN])
|
262
241
|
end
|
263
242
|
end
|
264
243
|
end
|