twitch-bot 2.1.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +47 -0
- data/CHANGELOG.md +8 -0
- data/README.md +2 -54
- data/Rakefile +1 -0
- data/lib/twitch/bot/adapter/irc.rb +5 -6
- data/lib/twitch/bot/adapter/terminal.rb +2 -10
- data/lib/twitch/bot/client.rb +23 -17
- data/lib/twitch/bot/config.rb +27 -0
- data/lib/twitch/bot/memory/hash.rb +26 -0
- data/lib/twitch/bot/version.rb +1 -1
- data/lib/twitch/bot.rb +2 -1
- data/spec/twitch/bot/client_spec.rb +25 -3
- data/spec/twitch/bot/config_spec.rb +28 -0
- data/spec/twitch/bot/memory/hash_spec.rb +13 -0
- metadata +9 -3
- data/lib/twitch/bot/connection.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38e0242c3bca6c9dbf21deab310f99435146e3e7be852ba50d26a489c81f2f24
|
4
|
+
data.tar.gz: 17963e5b6af86dcd2892d20a80661f2a44afc46692375b207c2f55600664e5b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d77d780322da5aeb3df98caa3991995be44e0b67c8510473fa66ccc533b8c3cfd0169dc1082726fcf4c7f26f324ac4086d3f6af300d933a47882263d5372203
|
7
|
+
data.tar.gz: 4c1e4e6cbbde65ce58dc0683e43f6de1ebdeaa62582375304b554beaad604b8f69f95a6bfa3821490e6cdb03f1eb02b2b3d37972ea0eee7a4189803aa0661156
|
@@ -0,0 +1,47 @@
|
|
1
|
+
name: Ruby Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
- push
|
5
|
+
- pull_request
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
test:
|
9
|
+
runs-on: ubuntu-latest
|
10
|
+
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v2
|
13
|
+
- name: Set up Ruby
|
14
|
+
uses: actions/setup-ruby@v1
|
15
|
+
with:
|
16
|
+
ruby-version: 2.6.x
|
17
|
+
- name: Bundle
|
18
|
+
run: |
|
19
|
+
gem install bundler
|
20
|
+
bundle install --jobs 4 --retry 3
|
21
|
+
- name: Build and test
|
22
|
+
run: |
|
23
|
+
bundle exec rake test
|
24
|
+
|
25
|
+
release:
|
26
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
27
|
+
needs: test
|
28
|
+
runs-on: ubuntu-latest
|
29
|
+
steps:
|
30
|
+
- uses: actions/checkout@v2
|
31
|
+
- name: Set up Ruby
|
32
|
+
uses: actions/setup-ruby@v1
|
33
|
+
with:
|
34
|
+
ruby-version: 2.6.x
|
35
|
+
- name: Bundle
|
36
|
+
run: |
|
37
|
+
gem install bundler
|
38
|
+
bundle install --jobs 4 --retry 3
|
39
|
+
- name: Publish to RubyGems
|
40
|
+
run: |
|
41
|
+
mkdir -p $HOME/.gem
|
42
|
+
touch $HOME/.gem/credentials
|
43
|
+
chmod 0600 $HOME/.gem/credentials
|
44
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
45
|
+
rake release
|
46
|
+
env:
|
47
|
+
GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog Twitch::Bot
|
2
2
|
|
3
|
+
## v3.1.0
|
4
|
+
|
5
|
+
* [NEW] Client provides a persistent memory in form of a key/value store.
|
6
|
+
|
7
|
+
## v3.0.0
|
8
|
+
|
9
|
+
* [BREAKING] Instead of choosing and creating the `Adapter` in the `Client`, we now inject a `Config` class into `Client` that carries our choice of Adapter. This change also makes the `Connection` class obsolete; its information went into `Config` as well.
|
10
|
+
|
3
11
|
## v2.1.1
|
4
12
|
|
5
13
|
* [FIXED] Fix a few bugs missed by not running tests. We need CI...
|
data/README.md
CHANGED
@@ -2,9 +2,7 @@
|
|
2
2
|
|
3
3
|
`twitch-bot` provides a Twitch chat client object that can be used for building Twitch chat bots.
|
4
4
|
|
5
|
-
This gem is based on
|
6
|
-
|
7
|
-
_As of April 2020, this gem is under heavy development. I've created it to develop my own Twitch chat bot and will add more functionality. Feel free to add issues with suggestions and feature requests!_
|
5
|
+
This gem is based on [`twitch-chat`](https://github.com/EnotPoloskun/twitch-chat).
|
8
6
|
|
9
7
|
## Installation
|
10
8
|
|
@@ -28,57 +26,7 @@ $ gem install twitch-bot
|
|
28
26
|
|
29
27
|
## Usage
|
30
28
|
|
31
|
-
|
32
|
-
require "twitch/bot"
|
33
|
-
|
34
|
-
class JoinHandler < Twitch::Bot::EventHandler
|
35
|
-
def call
|
36
|
-
client.send_message "Hi guys!"
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.handled_events
|
40
|
-
[:join]
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class SubscriptionHandler < Twitch::Bot::EventHandler
|
45
|
-
def call
|
46
|
-
client.send_message "Hi #{event.user}, thank you for your subscription"
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.handled_events
|
50
|
-
[:subscription]
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class TimeCommandHandler < Twitch::Bot::EventHandler
|
55
|
-
def call
|
56
|
-
if event.bot_command?("time")
|
57
|
-
client.send_message "Current time: #{Time.now.utc}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.handled_events
|
62
|
-
[:chat_message]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
connection = Twitch::Bot::Connection.new(
|
67
|
-
nickname: "test",
|
68
|
-
password: "secret",
|
69
|
-
)
|
70
|
-
|
71
|
-
client = Twitch::Bot::Client.new(
|
72
|
-
connection: connection,
|
73
|
-
channel: "test",
|
74
|
-
) do
|
75
|
-
register_handler(JoinHandler)
|
76
|
-
register_handler(SubscriptionHandler)
|
77
|
-
register_handler(TimeCommandHandler)
|
78
|
-
end
|
79
|
-
|
80
|
-
client.run
|
81
|
-
```
|
29
|
+
Refer to the [Teneggs](https://www.github.com/geewiz/teneggs) repository for an example bot implementation.
|
82
30
|
|
83
31
|
## Supported event types
|
84
32
|
|
data/Rakefile
CHANGED
@@ -52,10 +52,9 @@ module Twitch
|
|
52
52
|
attr_reader :socket, :client, :channel
|
53
53
|
|
54
54
|
def open_socket
|
55
|
-
connection = client.connection
|
56
55
|
@socket = ::TCPSocket.new(
|
57
|
-
|
58
|
-
|
56
|
+
client.config.setting("irc_hostname") || "irc.chat.twitch.tv",
|
57
|
+
client.config.setting("irc_port") || 6667,
|
59
58
|
)
|
60
59
|
|
61
60
|
Twitch::Bot::Logger.debug "Socket open"
|
@@ -95,9 +94,9 @@ module Twitch
|
|
95
94
|
end
|
96
95
|
|
97
96
|
def authenticate
|
98
|
-
|
99
|
-
send_data "PASS #{
|
100
|
-
send_data "NICK #{
|
97
|
+
config = client.config
|
98
|
+
send_data "PASS #{config.setting('irc_password')}"
|
99
|
+
send_data "NICK #{config.setting('irc_nickname')}"
|
101
100
|
end
|
102
101
|
|
103
102
|
def sanitize_data(data)
|
@@ -5,9 +5,7 @@ module Twitch
|
|
5
5
|
module Adapter
|
6
6
|
# This adapter connects the chat client to the terminal
|
7
7
|
class Terminal
|
8
|
-
def initialize(client:)
|
9
|
-
@client = client
|
10
|
-
end
|
8
|
+
def initialize(client:); end
|
11
9
|
|
12
10
|
def connect; end
|
13
11
|
|
@@ -22,7 +20,7 @@ module Twitch
|
|
22
20
|
end
|
23
21
|
|
24
22
|
def send_data(data)
|
25
|
-
puts
|
23
|
+
puts data
|
26
24
|
end
|
27
25
|
|
28
26
|
def join_channel(_channel); end
|
@@ -33,12 +31,6 @@ module Twitch
|
|
33
31
|
|
34
32
|
attr_reader :client
|
35
33
|
|
36
|
-
def sanitize_data(data)
|
37
|
-
data.gsub(/(PASS oauth:)(\w+)/) do
|
38
|
-
"#{Regexp.last_match(1)}#{'*' * Regexp.last_match(2).size}"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
34
|
def read_message_from_terminal
|
43
35
|
Twitch::Bot::Logger.debug "Waiting for input..."
|
44
36
|
input = gets
|
data/lib/twitch/bot/client.rb
CHANGED
@@ -19,23 +19,35 @@ module Twitch
|
|
19
19
|
USER_MESSAGES_COUNT = 20
|
20
20
|
TWITCH_PERIOD = 30.0
|
21
21
|
|
22
|
-
attr_reader :
|
22
|
+
attr_reader :channel, :config, :memory
|
23
23
|
|
24
24
|
def initialize(
|
25
|
-
|
25
|
+
channel: nil, config:, &block
|
26
26
|
)
|
27
|
-
@
|
27
|
+
@config = config
|
28
28
|
@channel = Twitch::Bot::Channel.new(channel) if channel
|
29
|
+
|
29
30
|
@messages_queue = []
|
30
31
|
@event_handlers = {}
|
31
32
|
@event_loop_running = false
|
32
33
|
|
33
|
-
|
34
|
+
setup_logging
|
35
|
+
|
36
|
+
memory_class = config.setting("memory") || "Twitch::Bot::Memory::Hash"
|
37
|
+
@memory = Object.const_get(memory_class).new
|
38
|
+
|
39
|
+
adapter_class = config.setting("adapter") || "Twitch::Bot::Adapter::Irc"
|
40
|
+
@adapter = Object.const_get(adapter_class).new(client: self)
|
34
41
|
|
35
42
|
execute_initialize_block block if block
|
36
43
|
register_default_handlers
|
37
44
|
end
|
38
45
|
|
46
|
+
#
|
47
|
+
# Register an event handler for specific event types
|
48
|
+
#
|
49
|
+
# @param [<EventHandler>] handler EventHandler class to register
|
50
|
+
#
|
39
51
|
def register_handler(handler)
|
40
52
|
handler.handled_events.each do |event_type|
|
41
53
|
(event_handlers[event_type] ||= []) << handler
|
@@ -95,15 +107,13 @@ module Twitch
|
|
95
107
|
private
|
96
108
|
|
97
109
|
attr_reader :adapter, :event_handlers, :event_loop_running,
|
98
|
-
:input_thread, :output_thread, :
|
110
|
+
:input_thread, :output_thread, :messages_queue
|
99
111
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
106
|
-
@adapter = adapter_class.new(client: self)
|
112
|
+
def setup_logging
|
113
|
+
Twitch::Bot::Logger.output =
|
114
|
+
config.setting(:log_file) || "twitchbot.log"
|
115
|
+
Twitch::Bot::Logger.level =
|
116
|
+
(config.setting(:log_level) || "info").to_sym
|
107
117
|
end
|
108
118
|
|
109
119
|
def startup
|
@@ -156,10 +166,6 @@ module Twitch
|
|
156
166
|
end
|
157
167
|
end
|
158
168
|
|
159
|
-
def development_mode?
|
160
|
-
ENV["BOT_MODE"] == "development"
|
161
|
-
end
|
162
|
-
|
163
169
|
def execute_initialize_block(block)
|
164
170
|
if block.arity == 1
|
165
171
|
block.call self
|
@@ -175,7 +181,7 @@ module Twitch
|
|
175
181
|
end
|
176
182
|
|
177
183
|
def max_messages_count
|
178
|
-
if channel.moderators.include?(
|
184
|
+
if channel.moderators.include?(config.setting("botname"))
|
179
185
|
MODERATOR_MESSAGES_COUNT
|
180
186
|
else
|
181
187
|
USER_MESSAGES_COUNT
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twitch
|
4
|
+
module Bot
|
5
|
+
# This class stores the connection details for the client.
|
6
|
+
class Config
|
7
|
+
def initialize(settings: {})
|
8
|
+
@settings = settings
|
9
|
+
end
|
10
|
+
|
11
|
+
def setting(name)
|
12
|
+
conf = settings
|
13
|
+
name_str = name.to_s
|
14
|
+
name_str.split("_").each do |key|
|
15
|
+
return nil if conf.nil?
|
16
|
+
|
17
|
+
conf = conf.fetch(key.to_sym, nil)
|
18
|
+
end
|
19
|
+
conf
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :settings
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twitch
|
4
|
+
module Bot
|
5
|
+
# Manage a key/value store for our bot
|
6
|
+
module Memory
|
7
|
+
class Hash
|
8
|
+
def initialize
|
9
|
+
@kvstore = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def store(key, value)
|
13
|
+
kvstore[key] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def retrieve(key)
|
17
|
+
kvstore[key]
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :kvstore
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/twitch/bot/version.rb
CHANGED
data/lib/twitch/bot.rb
CHANGED
@@ -4,6 +4,7 @@ require "bundler/setup"
|
|
4
4
|
Bundler.require(:default)
|
5
5
|
|
6
6
|
require_relative "bot/version"
|
7
|
+
require_relative "bot/config"
|
7
8
|
require_relative "bot/logger"
|
8
9
|
require_relative "bot/event"
|
9
10
|
require_relative "bot/event_handler"
|
@@ -11,8 +12,8 @@ require_relative "bot/default_handlers"
|
|
11
12
|
require_relative "bot/message"
|
12
13
|
require_relative "bot/irc_message"
|
13
14
|
require_relative "bot/message_parser"
|
15
|
+
require_relative "bot/memory/hash"
|
14
16
|
require_relative "bot/channel"
|
15
|
-
require_relative "bot/connection"
|
16
17
|
require_relative "bot/adapter/irc"
|
17
18
|
require_relative "bot/adapter/terminal"
|
18
19
|
require_relative "bot/client"
|
@@ -2,10 +2,16 @@
|
|
2
2
|
|
3
3
|
RSpec.describe Twitch::Bot::Client do
|
4
4
|
let!(:client) do
|
5
|
-
|
6
|
-
|
5
|
+
config = Twitch::Bot::Config.new(
|
6
|
+
settings: {
|
7
|
+
bot_user: "testuser",
|
8
|
+
adapter: "Twitch::Bot::Adapter::Terminal",
|
9
|
+
},
|
10
|
+
)
|
11
|
+
described_class.new(
|
12
|
+
config: config,
|
13
|
+
channel: "testchannel",
|
7
14
|
)
|
8
|
-
described_class.new(connection: connection)
|
9
15
|
end
|
10
16
|
|
11
17
|
describe "#trigger" do
|
@@ -49,4 +55,20 @@ RSpec.describe Twitch::Bot::Client do
|
|
49
55
|
expect(client).to have_received(:remove_moderator)
|
50
56
|
end
|
51
57
|
end
|
58
|
+
|
59
|
+
describe "#channel" do
|
60
|
+
it "returns the channel object" do
|
61
|
+
channel = client.channel
|
62
|
+
|
63
|
+
expect(channel.name).to eq "testchannel"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#memory" do
|
68
|
+
it "stores and retrieves data" do
|
69
|
+
client.memory.store("foo", "bar")
|
70
|
+
|
71
|
+
expect(client.memory.retrieve("foo")).to eq "bar"
|
72
|
+
end
|
73
|
+
end
|
52
74
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Twitch::Bot::Config do
|
4
|
+
describe "#setting" do
|
5
|
+
it "returns a first-level setting" do
|
6
|
+
config = described_class.new(
|
7
|
+
settings: {
|
8
|
+
test: "Test",
|
9
|
+
foo: "bar",
|
10
|
+
},
|
11
|
+
)
|
12
|
+
|
13
|
+
expect(config.setting("test")).to eq "Test"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "returns a second-level setting" do
|
17
|
+
config = described_class.new(
|
18
|
+
settings: {
|
19
|
+
test: {
|
20
|
+
foo: "bar",
|
21
|
+
},
|
22
|
+
},
|
23
|
+
)
|
24
|
+
|
25
|
+
expect(config.setting("test_foo")).to eq "bar"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Twitch::Bot::Memory::Hash do
|
4
|
+
describe "#store" do
|
5
|
+
it "persists a value for a key" do
|
6
|
+
mem = described_class.new
|
7
|
+
|
8
|
+
mem.store("foo", "bar")
|
9
|
+
|
10
|
+
expect(mem.retrieve("foo")).to eq "bar"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twitch-bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jochen Lillich
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-04-
|
11
|
+
date: 2020-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -174,6 +174,7 @@ extensions: []
|
|
174
174
|
extra_rdoc_files: []
|
175
175
|
files:
|
176
176
|
- ".editorconfig"
|
177
|
+
- ".github/workflows/main.yml"
|
177
178
|
- ".gitignore"
|
178
179
|
- ".rspec"
|
179
180
|
- ".rubocop.yml"
|
@@ -191,18 +192,21 @@ files:
|
|
191
192
|
- lib/twitch/bot/adapter/terminal.rb
|
192
193
|
- lib/twitch/bot/channel.rb
|
193
194
|
- lib/twitch/bot/client.rb
|
194
|
-
- lib/twitch/bot/
|
195
|
+
- lib/twitch/bot/config.rb
|
195
196
|
- lib/twitch/bot/default_handlers.rb
|
196
197
|
- lib/twitch/bot/event.rb
|
197
198
|
- lib/twitch/bot/event_handler.rb
|
198
199
|
- lib/twitch/bot/irc_message.rb
|
199
200
|
- lib/twitch/bot/logger.rb
|
201
|
+
- lib/twitch/bot/memory/hash.rb
|
200
202
|
- lib/twitch/bot/message.rb
|
201
203
|
- lib/twitch/bot/message/user_message.rb
|
202
204
|
- lib/twitch/bot/message_parser.rb
|
203
205
|
- lib/twitch/bot/version.rb
|
204
206
|
- spec/spec_helper.rb
|
205
207
|
- spec/twitch/bot/client_spec.rb
|
208
|
+
- spec/twitch/bot/config_spec.rb
|
209
|
+
- spec/twitch/bot/memory/hash_spec.rb
|
206
210
|
- spec/twitch/bot/message/user_message_spec.rb
|
207
211
|
- spec/twitch/bot/message_parser_spec.rb
|
208
212
|
- twitch-bot.gemspec
|
@@ -233,5 +237,7 @@ summary: twitch-bot is a Twitch chat client that uses Twitch IRC that can be use
|
|
233
237
|
test_files:
|
234
238
|
- spec/spec_helper.rb
|
235
239
|
- spec/twitch/bot/client_spec.rb
|
240
|
+
- spec/twitch/bot/config_spec.rb
|
241
|
+
- spec/twitch/bot/memory/hash_spec.rb
|
236
242
|
- spec/twitch/bot/message/user_message_spec.rb
|
237
243
|
- spec/twitch/bot/message_parser_spec.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Twitch
|
4
|
-
module Bot
|
5
|
-
# This class stores the connection details for the client.
|
6
|
-
class Connection
|
7
|
-
attr_reader :nickname, :password, :hostname, :port
|
8
|
-
|
9
|
-
def initialize(
|
10
|
-
nickname:, password:, hostname: "irc.chat.twitch.tv", port: "6667"
|
11
|
-
)
|
12
|
-
@nickname = nickname
|
13
|
-
@password = password
|
14
|
-
@hostname = hostname
|
15
|
-
@port = port
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|