twitchbot 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4eb24be58e5d670664da6a08c56cf3007ed3477b08c0d3e73bae57d7ee4bac29
4
+ data.tar.gz: 1ae2d56adbb8bdd41529888c3abb7d7b9f509147beddedc0fe385e54104c5b73
5
+ SHA512:
6
+ metadata.gz: a1354939320f1d974ab95107db9385e801aebf0f6b3c090d0f6a7d33f9db6c0a17bccd8e94179b6ecf8112d6f0a20623c7d3ce81a74f36c497c7170596dcdb64
7
+ data.tar.gz: ac3048f9253dcac655ec2a99787057a3ff9e3a8937af159576d11087d784b1a61d2d168fba7d701ff362630eea4294610056bf99e2eb1979bfe27263eceb9b71
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Charles Ray Shisler III
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # Twitchbot
2
+
3
+ A plugin-based framework for creating Twitch chat bots, written in Ruby and based on `EventMachine` and `Faye::WebSocket`.
4
+
5
+ Notes:
6
+ * Plugins are first class citizens
7
+ * Helper functions implemented to gate-keep commands
8
+ * Bot can currently only join one channel (it might stay that way)
9
+ * Read the source until I get all the documentation completed
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'twitchbot'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install twitchbot
26
+
27
+ ## Getting Started
28
+
29
+ Require Twitchbot
30
+
31
+ require 'twitchbot'
32
+
33
+ Create Plugins
34
+
35
+ # MessagePlugin, which listens for the registered command preceeded by the Bot command_prefix
36
+ class HiPlugin
37
+ include Twitchbot::MessagePlugin
38
+
39
+ register command: 'hi', method: :say_hi
40
+
41
+ def say_hi(message, arg)
42
+ message.respond 'Hello world!'
43
+ end
44
+ end
45
+
46
+ # TimedPlugin, which fires off the registered command periodically
47
+ class ShoutOutPlugin
48
+ include Twitchbot::TimedPlugin
49
+
50
+ register method: :social, interval: 15 # Time in seconds
51
+
52
+ def social(handler)
53
+ handler.send_channel('Hello! Check my social media out!')
54
+ end
55
+ end
56
+
57
+ # Plugin, which listens for registered commands according to the raw IRC command
58
+ class PutsPlugin
59
+ include Twitchbot::Plugin
60
+
61
+ register command: 'PRIVMSG', method: :put_string
62
+
63
+ def put_string(handler)
64
+ handler.messages.each do |message|
65
+ puts message
66
+ end
67
+ end
68
+ end
69
+
70
+ Create and start `Bot`
71
+
72
+ bot = Twitchbot::Bot.new do |bot|
73
+ bot.username = 'bot_name'
74
+ bot.password = 'oauth:password'
75
+ bot.channel = 'channel_name'
76
+ bot.plugins = [HiPlugin, ShoutOutPlugin, PutsPlugin]
77
+ bot.debug = true
78
+ # bot.command_prefix = '$' # Default is '!'
79
+ end
80
+
81
+ bot.start
82
+
83
+ ## Development
84
+
85
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
86
+
87
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
88
+
89
+ ## Contributing
90
+
91
+ Bug reports and pull requests are welcome on GitHub at https://github.com/craysiii/twitchbot.
92
+
93
+ ## License
94
+
95
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'twitchbot'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+
10
+ require 'pry'
11
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/twitchbot.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'twitchbot/version'
2
+ require 'twitchbot/bot'
3
+ require 'twitchbot/plugin'
4
+ require 'twitchbot/message_plugin'
5
+ require 'twitchbot/timed_plugin'
@@ -0,0 +1,74 @@
1
+ require 'eventmachine'
2
+ require 'faye/websocket'
3
+
4
+ require_relative 'event_handler'
5
+ require_relative 'channel'
6
+ require_relative 'plugin/debug_plugin'
7
+ require_relative 'plugin/auth_plugin'
8
+ require_relative 'plugin/ping_plugin'
9
+ require_relative 'plugin/channel_plugin'
10
+ require_relative 'plugin/message_queue_plugin'
11
+
12
+ module Twitchbot
13
+ # Main Bot class that we pass all bot account information to, as well as any
14
+ # plugins that should be used
15
+ class Bot
16
+ # @return [String] Username of the bot account
17
+ attr_accessor :username
18
+ # @return [String] Password of the bot account
19
+ attr_accessor :password
20
+ # @return [Channel] The channel that the bot is connected to
21
+ attr_accessor :channel
22
+ # @return [Array] The plugins that are in use by the bot
23
+ attr_accessor :plugins
24
+ # @return [Boolean] Whether the bot should display debug info to STDOUT
25
+ attr_accessor :debug
26
+ # @return [Array] The array of messages that are to be sent to the server
27
+ attr_accessor :message_queue
28
+ # @return [String] The prefix to use when defining and parsing commands e.g. +!+
29
+ attr_accessor :command_prefix
30
+
31
+ # The connection URL for Twitch
32
+ DEFAULT_URL = 'wss://irc-ws.chat.twitch.tv'.freeze
33
+ # The built-in plugins to be used
34
+ DEFAULT_PLUGINS = [AuthPlugin,
35
+ PingPlugin,
36
+ ChannelPlugin,
37
+ MessageQueuePlugin,
38
+ DebugPlugin].freeze
39
+ # The events that eventmachine dispatches to any plugins in use
40
+ DEFAULT_EVENTS = %i[error close open message].freeze
41
+
42
+ # Create a new Bot instance, passing a block to set the necessary
43
+ # attributes to have the bot function
44
+ def initialize
45
+ @username = ''
46
+ @password = ''
47
+ @channel = ''
48
+ @plugins = []
49
+ @message_queue = Queue.new
50
+ @command_prefix = '!'
51
+
52
+ yield self
53
+
54
+ @channel = Channel.new(@channel)
55
+ end
56
+
57
+ # Start the event loop, initiate the websocket client, and register the
58
+ # plugins with eventmachine
59
+ def start
60
+ EM.run do
61
+ connection = Faye::WebSocket::Client.new DEFAULT_URL
62
+ plugins = (@plugins << DEFAULT_PLUGINS).flatten!.reverse!.map! &:new
63
+ DEFAULT_EVENTS.each do |default_event|
64
+ connection.on(default_event) do |em_event|
65
+ handler = EventHandler.new em_event, connection, self
66
+ plugins.each do |plugin|
67
+ plugin.send(default_event, handler)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,22 @@
1
+ module Twitchbot
2
+ # Class responsible for keeping track of channel attributes such as channel
3
+ # state and users in the channel
4
+ #
5
+ # TODO: Implement channel states e.g. r9k, emote-only, sub-only, slow
6
+ # TODO: Capture channel id from tags
7
+ class Channel
8
+ # @return [String] Name of the channel we have joined
9
+ attr_reader :name
10
+ # @return [Hash] Mapping of user objects according to their username
11
+ attr_accessor :users
12
+
13
+ def initialize(name)
14
+ @name = name
15
+ @users = {}
16
+ end
17
+ end
18
+
19
+ def to_s
20
+ @name
21
+ end
22
+ end
@@ -0,0 +1,50 @@
1
+ require_relative 'message'
2
+
3
+ module Twitchbot
4
+ # Class responsible for handling the eventmachine event that is provided
5
+ # whenever an event is fired
6
+ class EventHandler
7
+ # @return [Bot] The bot that the channel is a member of
8
+ attr_reader :bot
9
+ # @return [Array] The different messages received
10
+ attr_reader :messages
11
+ # @return [Faye::WebSocket::Client] The WebSocket client instance
12
+ attr_reader :connection
13
+
14
+ def initialize(event, connection, bot)
15
+ @connection = connection
16
+ @bot = bot
17
+
18
+ if event.respond_to? :data
19
+ @chunks = event.data.split "\n"
20
+ @messages = []
21
+ @chunks.each do |chunk|
22
+ @messages << Message.new(self, chunk.chomp)
23
+ end
24
+ end
25
+ end
26
+
27
+ # Add a raw message to the message queue
28
+ def send_raw(message)
29
+ @bot.message_queue.push(message)
30
+ end
31
+
32
+ # Add a formatted channel message to the message queue
33
+ def send_channel(message)
34
+ @bot.message_queue.push("PRIVMSG ##{bot.channel.name} :#{message}")
35
+ end
36
+
37
+ # Add a whisper to the specified user to the message queue
38
+ def send_whisper(user, message)
39
+ @bot.message_queue.push("PRIVMSG jtv :/w #{user} :#{message}")
40
+ end
41
+
42
+ # Method that provides a shortcut to grab the first message in an event
43
+ # handler. We can typically use this after authenticating, but there is no
44
+ # guarantee that twitch will not send multiple 'messages' in a single
45
+ # +:message+ event
46
+ def message
47
+ @messages.first
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,78 @@
1
+ require_relative 'user'
2
+
3
+ module Twitchbot
4
+ # Class responsible for parsing messages created in [EventHandler]
5
+ #
6
+ # TODO: Clean this up because its ugly
7
+ # TODO: Parse message-id
8
+ class Message
9
+ # @return [Integer] Number of bits that have been included in a message
10
+ attr_reader :bits
11
+ # @return [User] User that the message was sent by
12
+ attr_reader :user
13
+ # @return [Channel] Channel that the message was sent to
14
+ attr_reader :channel
15
+ # @return [String] IRC command of the raw IRC message
16
+ attr_reader :command
17
+ # @return [String] Raw IRC message received
18
+ attr_reader :raw
19
+ # @return [String] Sender of the IRC message
20
+ attr_reader :sender
21
+ # @return [String] Target of the IRC message
22
+ attr_reader :target
23
+ # @return [String] Content of the IRC message
24
+ attr_reader :payload
25
+
26
+ def initialize(handler, raw_message)
27
+ @handler = handler
28
+ @raw = raw_message
29
+ msg = @raw.dup
30
+ @tags = msg.slice! /^\S+/ if tagged?
31
+
32
+ msg.lstrip!
33
+ /^(?<sender>:\S+) (?<command>\S+)( (?<target>\S+))?( (?<payload>.+))?$/ =~ msg
34
+ @sender = sender
35
+ @command = command
36
+ @target = target
37
+ @payload = payload
38
+
39
+ if message?
40
+ @payload.slice! 0, 1
41
+ @channel = @handler.bot.channel
42
+ /bits=(?<bits>\d+)/ =~ @tags
43
+ @bits = bits.nil? ? 0 : bits.to_i
44
+ /display-name=(?<display_name>\w+)/ =~ @tags
45
+ /user-id=(?<user_id>[a-zA-Z0-9\-]+)/ =~ @tags
46
+ /badges=(?<badges>[a-zA-Z\/,0-9\-]+)/ =~ @tags
47
+ badges = badges || ''
48
+ /:(?<user>\w+)/ =~ @sender
49
+ if @channel.users.key? user
50
+ @channel.users[user].update_attributes display_name, user_id, badges
51
+ else
52
+ @channel.users[user] = User.new user, display_name, user_id, badges
53
+ end
54
+ @user = @channel.users[user]
55
+ end
56
+ end
57
+
58
+ # Method to determine if the IRC message includes any tags from the +:twitch.tv/tags+ capability
59
+ def tagged?
60
+ @raw.start_with? '@'
61
+ end
62
+
63
+ # Method to determine if the IRC message is an actual message to the [Channel] by a [User]
64
+ def message?
65
+ @command.eql? 'PRIVMSG'.freeze
66
+ end
67
+
68
+ # Method to respond to the IRC message target with a private message
69
+ def respond(message)
70
+ @handler.bot.message_queue.push("PRIVMSG #{@target} :#{message}")
71
+ end
72
+
73
+ # Method to determine if the IRC message is a PING challenge
74
+ def ping?
75
+ @raw.start_with? 'PING'
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,47 @@
1
+ module Twitchbot
2
+ module MessagePlugin
3
+
4
+ COMMANDS = {}
5
+
6
+ # Method that can be overriden to react to the eventmachine +:open+ event
7
+ def open(handler) end
8
+
9
+ def message(handler)
10
+ handler.messages.each do |message|
11
+ if message.message?
12
+ prefix = handler.bot.command_prefix
13
+ _, _command, arguments = message.payload.partition(
14
+ /#{Regexp.escape prefix}\S+/
15
+ )
16
+ command = _command.delete prefix
17
+ commands = COMMANDS[self.class]
18
+ if !command.nil? && !commands[command].nil?
19
+ send(commands[command], message, arguments)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ # Method that can be overriden to react to the eventmachine +:error+ event
26
+ def error(handler) end
27
+
28
+ # Method that can be overriden to react to the eventmachine +:close+ event
29
+ def close(handler) end
30
+
31
+ # Define a class method called register on each class that includes this
32
+ # module, which allows the user to add methods to the +COMMANDS+ constant
33
+ #
34
+ # def self.register(command:, method:)
35
+ # COMMANDS[base] = {} if COMMANDS[base].nil?
36
+ # COMMANDS[base][params[:command]] = params[:method]
37
+ # end
38
+ def self.included(klass)
39
+ klass.instance_eval do
40
+ define_singleton_method 'register' do |params|
41
+ COMMANDS[klass] = {} if COMMANDS[klass].nil?
42
+ COMMANDS[klass][params[:command]] = params[:method]
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,55 @@
1
+ module Twitchbot
2
+ # Base Plugin module that listens for IRC commands and calls the associated
3
+ # method of the class that includes it
4
+ module Plugin
5
+
6
+ # The commands that are registered to this base module via classes that
7
+ # include it
8
+ #
9
+ # Example state during runtime:
10
+ # { AuthPlugin: { '376': :request_caps }, ChannelPlugin: { 'CAP': :join_channel, 'JOIN': :process_join, 'PART': :process_part } }
11
+ COMMANDS = {}
12
+
13
+ # Method that can be overriden to react to the eventmachine +:open+ event
14
+ def open(handler) end
15
+
16
+ # Method that reacts to the eventmachine +:message+ event and processes each
17
+ # message in the {EventHandler}, calling the appropriate method if available.
18
+ #
19
+ # It is not recommended to override this method unless you plan on handling
20
+ # all logic for reacting to methods yourself.
21
+ def message(handler)
22
+ handler.messages.each do |message|
23
+ command = message&.command
24
+ # Grab all registered methods of the including class
25
+ commands = COMMANDS[self.class]
26
+ if !command.nil? && !commands[command].nil?
27
+ # Call the including class method and pass the EventHandler to it
28
+ send(commands[command], handler)
29
+ end
30
+ end
31
+ end
32
+
33
+ # Method that can be overriden to react to the eventmachine +:error+ event
34
+ def error(handler) end
35
+
36
+ # Method that can be overriden to react to the eventmachine +:close+ event
37
+ def close(handler) end
38
+
39
+ # Define a class method called register on each class that includes this
40
+ # module, which allows the user to add methods to the +COMMANDS+ constant
41
+ #
42
+ # def self.register(command:, method:)
43
+ # COMMANDS[base] = {} if COMMANDS[base].nil?
44
+ # COMMANDS[base][params[:command]] = params[:method]
45
+ # end
46
+ def self.included(klass)
47
+ klass.instance_eval do
48
+ define_singleton_method 'register' do |params|
49
+ COMMANDS[klass] = {} if COMMANDS[klass].nil?
50
+ COMMANDS[klass][params[:command]] = params[:method]
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,37 @@
1
+ require_relative '../plugin'
2
+
3
+ module Twitchbot
4
+ # Plugin to handle authenticating the bot account and authorizing the use of
5
+ # all available Twitch IRCv3 capabilities
6
+ class AuthPlugin
7
+ include Twitchbot::Plugin
8
+
9
+ # The capabilities available to request
10
+ CAPABILITIES = %w(
11
+ twitch.tv/tags
12
+ twitch.tv/commands
13
+ twitch.tv/membership
14
+ ).freeze
15
+
16
+ # Send bot account credentials after the connection has opened
17
+ def open(handler)
18
+ handler.send_raw "PASS #{handler.bot.password}"
19
+ handler.send_raw "NICK #{handler.bot.username}"
20
+ end
21
+
22
+ register command: '376', method: :request_caps
23
+ # Listen for the last message of a successful authentication attempt and
24
+ # request capabilities
25
+ #
26
+ # > :tmi.twitch.tv 001 bot :Welcome, GLHF!
27
+ # > :tmi.twitch.tv 002 bot :Your host is tmi.twitch.tv
28
+ # > :tmi.twitch.tv 003 bot :This server is rather new
29
+ # > :tmi.twitch.tv 004 bot :-
30
+ # > :tmi.twitch.tv 375 bot :-
31
+ # > :tmi.twitch.tv 372 bot :You are in a maze of twisty passages, all alike.
32
+ # > :tmi.twitch.tv 376 bot :>
33
+ def request_caps(handler)
34
+ handler.send_raw "CAP REQ :#{CAPABILITIES.join ' '}"
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,51 @@
1
+ require_relative '../plugin'
2
+ require_relative '../user'
3
+
4
+ module Twitchbot
5
+ # Plugin to handle joining the specified channel, as well as maintaining a
6
+ # list of users who have joined or left the channel
7
+ #
8
+ # TODO: Handle 353 and 366 (NAMES list)
9
+ class ChannelPlugin
10
+ include Twitchbot::Plugin
11
+
12
+ register command: 'CAP', method: :join_channel
13
+ # Listen for the response from AuthPlugin#request_caps and request to join
14
+ # the channel
15
+ #
16
+ # > :tmi.twitch.tv CAP * ACK :twitch.tv/tags twitch.tv/commands twitch.tv/membership
17
+ def join_channel(handler)
18
+ handler.send_raw "JOIN ##{handler.bot.channel.name}"
19
+ end
20
+
21
+ register command: 'JOIN', method: :process_join
22
+ # Listen for any JOIN commands and add the user to the channel user list
23
+ #
24
+ # > :<user>!<user>@<user>.tmi.twitch.tv JOIN #<channel>
25
+ def process_join(handler)
26
+ channel = handler.bot.channel
27
+ handler.messages.each do |message|
28
+ /:(?<sender>\w+)/ =~ message.raw
29
+ unless channel.users.key? sender
30
+ channel.users[sender] = User.new sender
31
+ end
32
+ end
33
+ end
34
+
35
+ register command: 'PART', method: :process_part
36
+ # Listen for any PART commands and remove the user from the channel user
37
+ # list
38
+ #
39
+ # > :<user>!<user>@<user>.tmi.twitch.tv PART #<channel>
40
+ def process_part(handler)
41
+ channel = handler.bot.channel
42
+ handler.messages.each do |message|
43
+ /:(?<sender>\w+)/ =~ message.raw
44
+ if channel.users.key? sender
45
+ channel.users.delete sender
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,34 @@
1
+ require_relative '../plugin'
2
+
3
+ module Twitchbot
4
+ # Plugin to handle displaying debug information such as raw messages received
5
+ # as well as connection events e.g. open, close, error
6
+ class DebugPlugin
7
+ include Twitchbot::Plugin
8
+
9
+ # Display to the user that the connection has been opened
10
+ def open(handler)
11
+ puts '! Connection established' if handler.bot.debug
12
+ end
13
+
14
+ # Display to the user any raw messages that have been received from the
15
+ # server
16
+ def message(handler)
17
+ if handler.bot.debug
18
+ handler.messages.each do |line|
19
+ puts "> #{line.raw}"
20
+ end
21
+ end
22
+ end
23
+
24
+ # Display to the user that the connection has encountered an error
25
+ def error(handler)
26
+ puts '! Error occurred' if handler.bot.debug
27
+ end
28
+
29
+ # Display to the user that the connection has been closed
30
+ def close(handler)
31
+ puts '! Connection closed' if handler.bot.debug
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ require_relative '../timed_plugin'
2
+
3
+ module Twitchbot
4
+ # Plugin to handle sending messages to the server that have been queued from
5
+ # any plugins running.
6
+ #
7
+ # TODO: Implement different levels of rate limiting according to bot status e.g. :mod, :verified, :trusted
8
+ class MessageQueuePlugin
9
+ include Twitchbot::TimedPlugin
10
+
11
+ # The most privileged bot can only send 7200 messages every 30 seconds
12
+ register method: :send_message, interval: (30 / 7200)
13
+ # Pull a message from the message queue if any are available and send to the
14
+ # server
15
+ def send_message(handler)
16
+ queue = handler.bot.message_queue
17
+ unless queue.empty?
18
+ message = queue.pop
19
+ puts "< #{message}" if handler.bot.debug
20
+ handler.connection.send message
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ require_relative '../plugin'
2
+
3
+ module Twitchbot
4
+ # Plugin to handle any PING messages from the server and keep the connection
5
+ # alive
6
+ class PingPlugin
7
+ include Twitchbot::Plugin
8
+
9
+ # Listen for any PING messages and respond with PONG
10
+ #
11
+ # > PING :tmi.twitch.tv
12
+ def message(handler)
13
+ handler.send_raw('PONG :tmi.twitch.tv') if handler.message.ping?
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,47 @@
1
+ require 'eventmachine'
2
+
3
+ module Twitchbot
4
+ # Base Plugin module that registers methods that should be called periodically
5
+ module TimedPlugin
6
+
7
+ COMMANDS = {}
8
+
9
+ # Method that reacts to the eventmachine +:open+ event and creates a new
10
+ # eventmachine periodic timer for each plugin of this type
11
+ #
12
+ # It is not recommended to override this method unless you plan on handling
13
+ # all logic for managing timed plugins yourself
14
+ def open(handler)
15
+ COMMANDS[self.class].each do |command, interval|
16
+ EM::PeriodicTimer.new(interval) do
17
+ send(command, handler)
18
+ end
19
+ end
20
+ end
21
+
22
+ # Method that can be overriden to react to the eventmachine +:message+ event
23
+ def message(event) end
24
+
25
+ # Method that can be overriden to react to the eventmachine +:error+ event
26
+ def error(event) end
27
+
28
+ # Method that can be overriden to react to the eventmachine +:close+ event
29
+ def close(event) end
30
+
31
+ # Define a class method called register on each class that includes this
32
+ # module, which allows the user to add methods to the +COMMANDS+ constant
33
+ #
34
+ # def self.register(command:, method:)
35
+ # COMMANDS[base] = {} if COMMANDS[base].nil?
36
+ # COMMANDS[base][params[:command]] = params[:method]
37
+ # end
38
+ def self.included(klass)
39
+ klass.instance_eval do
40
+ define_singleton_method 'register' do |params|
41
+ COMMANDS[klass] = {} if COMMANDS[klass].nil?
42
+ COMMANDS[klass][params[:method]] = params[:interval]
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,80 @@
1
+ module Twitchbot
2
+ # Class responsible for keeping track of a user attributes such as their
3
+ # display name, id, any badges they have, and implementing helper functions
4
+ # to determine if different qualities of the user
5
+ class User
6
+ # @return [String] Server ID for the user
7
+ attr_reader :id
8
+ # @return [Hash] Collection of known badges for the user
9
+ attr_reader :badges
10
+
11
+ def initialize(name, display_name = nil, id = nil, badges = nil)
12
+ @name = name
13
+ @display_name = display_name
14
+ @id = id
15
+ @badges = badges.nil? ? nil : process_badges(badges)
16
+ end
17
+
18
+ # Method to update the main attributes of a user
19
+ def update_attributes(display_name, id, badges)
20
+ @display_name = display_name
21
+ @user_id = id
22
+ @badges = process_badges(badges)
23
+ end
24
+
25
+ # Method to grab the best representation of a user
26
+ def name
27
+ @display_name || @name
28
+ end
29
+
30
+ # Method to determine if the user is a moderator of the channel
31
+ def mod?
32
+ @badges.key? 'moderator'
33
+ end
34
+
35
+ # Method to determine if the user is a subscriber to the channel
36
+ def sub?
37
+ @badges.key? 'subscriber'
38
+ end
39
+
40
+ # Method to determine if the user has Twitch Prime
41
+ def prime?
42
+ @badges.key? 'premium'
43
+ end
44
+
45
+ # Method to determine if the user has ever donated to the channel
46
+ def donator?
47
+ @badges.key? 'bits'
48
+ end
49
+
50
+ # Method to determine if the user is a channel founder
51
+ def founder?
52
+ @badges.key? 'founder'
53
+ end
54
+
55
+ # Method to determine if the user is on the leaderboard for subscriber gifts
56
+ def sub_gift_leader?
57
+ @badges.key? 'sub-gift-leader'
58
+ end
59
+
60
+ # Method to determine if the user is on the leaderboard for bit gifts
61
+ def bits_leader?
62
+ @badges.key? 'bits-leader'
63
+ end
64
+
65
+ # Method to process the string representation of badges into a Hash so that
66
+ # we can query it for specific badges and levels of the badges
67
+ def process_badges(badges)
68
+ badge = {}
69
+ badges.split(',').each do |_badge|
70
+ type, value = _badge.split '/'
71
+ badge[type] = value.to_i
72
+ end
73
+ badge
74
+ end
75
+
76
+ def to_s
77
+ name
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ module Twitchbot
2
+ VERSION = '0.0.2'.freeze
3
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: twitchbot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Charles Ray Shisler III
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-11-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faye-websocket
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.10.7
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.10.7
83
+ description:
84
+ email:
85
+ - charles@cray.io
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - LICENSE.txt
91
+ - README.md
92
+ - bin/console
93
+ - bin/setup
94
+ - lib/twitchbot.rb
95
+ - lib/twitchbot/bot.rb
96
+ - lib/twitchbot/channel.rb
97
+ - lib/twitchbot/event_handler.rb
98
+ - lib/twitchbot/message.rb
99
+ - lib/twitchbot/message_plugin.rb
100
+ - lib/twitchbot/plugin.rb
101
+ - lib/twitchbot/plugin/auth_plugin.rb
102
+ - lib/twitchbot/plugin/channel_plugin.rb
103
+ - lib/twitchbot/plugin/debug_plugin.rb
104
+ - lib/twitchbot/plugin/message_queue_plugin.rb
105
+ - lib/twitchbot/plugin/ping_plugin.rb
106
+ - lib/twitchbot/timed_plugin.rb
107
+ - lib/twitchbot/user.rb
108
+ - lib/twitchbot/version.rb
109
+ homepage: https://github.com/craysiii/twitchbot
110
+ licenses:
111
+ - MIT
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubygems_version: 3.0.3
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: A framework for creating Twitch.tv chat bots
132
+ test_files: []