twitch_chatter 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7d4ba180e523e3c21f4124b3b12c166b6e21b7af9f8c6a882ee5a01bb22b543
4
- data.tar.gz: 9a92e1418e6f7b95b13ae87fd283365c16e0ec2688ec795457679c512c25efb8
3
+ metadata.gz: 0cd70432c7cb5123a7377b95203e38f2c97cdd04d185a59dfd59356e59b4658c
4
+ data.tar.gz: 2e46bc4c3fbfffe262716cef079b1e988a5624c31dc9a4fa623ea9021d753b1f
5
5
  SHA512:
6
- metadata.gz: 236cea705bb4b56208403dd37dbad1ddf5dc10200a91a9ebdc52a4cbcca9b8424ef853ddef0ef0d32fc3a841b0b1963d4ea1682ab9a84b91298625c33a87d26c
7
- data.tar.gz: 8cfe361fb854df8eb88c6ca3abee5b09b81836c1e42ad9462a0fbc4e2874323fbdbbea92f874056d22bc85eca319bbd8955d78a8fe84a33544debc4d44866150
6
+ metadata.gz: f9387375052d6c148931b7330f26701cefcb6dac48fab53a97ef8741db12833cb4d7a288f8dbc1d081cbf6cbcd802e4fdb7b8f82680cab40d2cc3566ea413645
7
+ data.tar.gz: 5b6dc9d6a7cb115effb39016c309bbe1dd310cf1875c634841602238de1a123a9d41bf87f589c18046f5555dfaa2535f962c5b93996171af83b8fd74158b62bf
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ # @example
5
+ # bot = Twitch::Bot.new
6
+ #
7
+ # bot.ready do
8
+ # puts "Ready!"
9
+ # end
10
+ #
11
+ # bot.join(:twitchgaming) do |message|
12
+ # puts "#{message.channel} #{message.user}: #{message.text}"
13
+ # end
14
+ #
15
+ # bot.start
16
+ class Bot
17
+ # Default options for Twitch websocket. Nicknames starting with "justinfan" are considered anonymous.
18
+ # @api private
19
+ DEFAULT_OPTIONS = {
20
+ nick: "justinfan0735",
21
+ websocket_url: "wss://irc-ws.chat.twitch.tv:443",
22
+ }.freeze
23
+
24
+ include Concerns::Channels
25
+
26
+ def initialize(**options)
27
+ @nick = options[:nick] || DEFAULT_OPTIONS[:nick]
28
+ @websocket_url = Async::HTTP::Endpoint.parse(options[:websocket_url] || DEFAULT_OPTIONS[:websocket_url])
29
+ end
30
+
31
+ # @yield
32
+ # @yieldparam
33
+ def ready(&block)
34
+ @ready_handle = block
35
+ end
36
+
37
+ # @return [Boolean]
38
+ def ready?
39
+ @ws != nil
40
+ end
41
+
42
+ # @return [Async::Task]
43
+ def start
44
+ Async do
45
+ Async::WebSocket::Client.connect(@websocket_url) do |ws|
46
+ @ws = ws
47
+ ws.write("NICK #{@nick}")
48
+ resume_pending
49
+ @ready_handle&.call
50
+
51
+ while (ws_message = ws.read)
52
+ data = ws_message.to_str
53
+ if data.start_with?("PING")
54
+ ws.write("PONG :tmi.twitch.tv")
55
+ next
56
+ end
57
+
58
+ next unless data.include?("PRIVMSG")
59
+
60
+ message = Message.new(data, connection: self)
61
+ @message_handle&.call(message)
62
+ streams[message.channel.to_sym].each do |block|
63
+ block.call(message)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ # Mixin modules
5
+ # @private
6
+ module Concerns
7
+ # Mixin for channel-related methods
8
+ # @private
9
+ module Channels
10
+ # @return [Array<Symbol>]
11
+ def channels
12
+ streams.keys
13
+ end
14
+
15
+ # @yield
16
+ # @yieldparam streamer [Symbol]
17
+ # @yieldreturn [nil]
18
+ def joined(&block)
19
+ @join_handle = block
20
+ end
21
+
22
+ # @yield
23
+ # @yieldparam streamer [Symbol]
24
+ # @yieldreturn [nil]
25
+ def left(&block)
26
+ @leave_handle = block
27
+ end
28
+
29
+ # @param streamer [Symbol, String]
30
+ # @yield
31
+ # @yieldparam message [Twitch::Message]
32
+ # @yieldreturn [nil]
33
+ # @example
34
+ # bot.join(:twitchgaming) do |message|
35
+ # puts "##{message.channel} #{message.sender}: #{message}"
36
+ # end
37
+ def join(streamer, &block)
38
+ streamer = streamer.to_sym
39
+ unless ready?
40
+ yield_join(streamer, &block)
41
+ return
42
+ end
43
+
44
+ streams[streamer] = [] unless streams.key?(streamer)
45
+ streams[streamer] << block if block_given?
46
+ @ws.write("JOIN ##{streamer}")
47
+ @join_handle&.call(streamer)
48
+ end
49
+
50
+ # @param streamer [Symbol, String]
51
+ # @example
52
+ # bot.leave(:twitchgaming)
53
+ def leave(streamer)
54
+ streamer = streamer.to_sym
55
+ streams[streamer] = []
56
+ @ws.write("PART ##{streamer}")
57
+ @leave_handle&.call(streamer)
58
+ end
59
+
60
+ # @yield
61
+ # @yieldparam message [Twitch::Message]
62
+ # @yieldreturn [nil]
63
+ # @example
64
+ # bot.message do |message|
65
+ # puts "##{message.channel} #{message.sender}: #{message}"
66
+ # end
67
+ def message(&block)
68
+ @message_handle = block
69
+ end
70
+
71
+ alias_method :part, :leave
72
+ alias_method :on_leave, :leave
73
+ alias_method :on_join, :joined
74
+ alias_method :on_message, :message
75
+
76
+ private
77
+
78
+ def streams
79
+ @streams ||= {}
80
+ end
81
+
82
+ def pending
83
+ @pending ||= {}
84
+ end
85
+
86
+ def yield_join(streamer, &block)
87
+ pending[streamer] = [] if streamer
88
+ pending[streamer] << block
89
+ end
90
+
91
+ def resume_pending
92
+ pending.each do |streamer, blocks|
93
+ blocks.each { |block| join(streamer, &block) }
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ require_relative "concerns/channels"
5
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ # @!attribute [r] name
5
+ # @return [Symbol] Name of the channel
6
+ # @example
7
+ # channel = Twitch::Channel.new("twitchgaming")
8
+ class Channel
9
+ attr_reader :name
10
+
11
+ # @param name [String, Symbol]
12
+ # @param connection [Bot, nil] For internal usage
13
+ def initialize(name, connection: nil)
14
+ @name = name.to_sym
15
+ @connection = connection
16
+ end
17
+
18
+ # @yield
19
+ # @yieldparam message [Twitch::Message]
20
+ # @return [nil]
21
+ def join(&block)
22
+ @connection.join(@name, &block)
23
+ end
24
+
25
+ # @return [nil]
26
+ def leave
27
+ @connection.leave(@name)
28
+ end
29
+
30
+ # @return [Symbol]
31
+ def to_sym
32
+ @name
33
+ end
34
+
35
+ # @return [String]
36
+ def to_s
37
+ @name.to_s
38
+ end
39
+
40
+ # @param other [Channel, Symbol]
41
+ # @return [Boolean]
42
+ def ==(other)
43
+ if other.is_a?(Channel)
44
+ return @name == other.name
45
+ end
46
+
47
+ @name == other.to_sym
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ # @!attribute [r] sender
5
+ # @return [Channel] Sender of the message
6
+ # @!attribute [r] channel
7
+ # @return [Channel] Channel the message was sent to
8
+ # @!attribute [r] content
9
+ # @return [String] Content of the message
10
+ # @!attribute [r] raw
11
+ # @return [String] Raw message from Twitch
12
+ # @example
13
+ # message = Twitch::Message.new(":ttlnow!ttlnow@ttlnow.tmi.twitch.tv PRIVMSG #ttlnow :Hello world!\r\n")
14
+ # message.sender.name # => :ttlnow
15
+ # message.channel.name # => :ttlnow
16
+ # message.content # => "Hello world!"
17
+ # message.raw # => ":ttlnow!ttlnow@ttlnow.tmi.twitch.tv PRIVMSG #ttlnow :Hello world!\r\n"
18
+ class Message < String
19
+ attr_reader :sender, :channel, :content, :raw
20
+
21
+ # @param raw [String] Raw IRC websocket message from Twitch
22
+ # @param connection [Bot, nil] For internal usage
23
+ # @example
24
+ # message = Twitch::Message.new(":ttlnow!ttlnow@ttlnow.tmi.twitch.tv PRIVMSG #ttlnow :Hello world!\r\n")
25
+ def initialize(raw, connection: nil)
26
+ split = raw.split(" ")
27
+ content = split[3..-1].join(" ")[1..-1]
28
+ super(content)
29
+
30
+ @content = content
31
+ @channel = Channel.new(split[2][1..-1], connection: connection)
32
+ @sender = Channel.new(split[0].split("!")[0][1..-1])
33
+ @raw = raw
34
+ end
35
+
36
+ alias_method :text, :content
37
+ alias_method :streamer, :channel
38
+ end
39
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Twitch
4
+ require_relative "models/channel"
5
+ require_relative "models/message"
6
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twitch_chatter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dylan Hackworth
@@ -9,7 +9,21 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2024-05-21 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: async-websocket
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.26.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.26.1
13
27
  description: A Ruby gem for Twitch's chat IRC websocket
14
28
  email: me@dylhack.dev
15
29
  executables: []
@@ -17,6 +31,12 @@ extensions: []
17
31
  extra_rdoc_files: []
18
32
  files:
19
33
  - lib/twitch_chatter.rb
34
+ - lib/twitch_chatter/bot.rb
35
+ - lib/twitch_chatter/concerns.rb
36
+ - lib/twitch_chatter/concerns/channels.rb
37
+ - lib/twitch_chatter/models.rb
38
+ - lib/twitch_chatter/models/channel.rb
39
+ - lib/twitch_chatter/models/message.rb
20
40
  homepage: https://github.com/dylhack/twitch-chat-gem
21
41
  licenses:
22
42
  - MIT
@@ -30,7 +50,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
30
50
  requirements:
31
51
  - - ">="
32
52
  - !ruby/object:Gem::Version
33
- version: 3.1.0
53
+ version: 3.1.1
34
54
  required_rubygems_version: !ruby/object:Gem::Requirement
35
55
  requirements:
36
56
  - - ">="