twitch_chatter 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7d4ba180e523e3c21f4124b3b12c166b6e21b7af9f8c6a882ee5a01bb22b543
4
- data.tar.gz: 9a92e1418e6f7b95b13ae87fd283365c16e0ec2688ec795457679c512c25efb8
3
+ metadata.gz: 65e839a944e5c1d2d0bf8049e954c12435872fb290c0027f6b42764375f8a61a
4
+ data.tar.gz: 0baa96f98a7b0161e44da032bb4c9387faf6c36aacda7be36924cc35f974035d
5
5
  SHA512:
6
- metadata.gz: 236cea705bb4b56208403dd37dbad1ddf5dc10200a91a9ebdc52a4cbcca9b8424ef853ddef0ef0d32fc3a841b0b1963d4ea1682ab9a84b91298625c33a87d26c
7
- data.tar.gz: 8cfe361fb854df8eb88c6ca3abee5b09b81836c1e42ad9462a0fbc4e2874323fbdbbea92f874056d22bc85eca319bbd8955d78a8fe84a33544debc4d44866150
6
+ metadata.gz: cd559c343272abf40568722b859ecc73806dcb0627bf05e53f3280fe3590c09df9a4e146300353f619a54936c227dca5c5dab9729f6f66f2e70250f1b40524dc
7
+ data.tar.gz: 622feea1abcd924c2ff8d2fd6310685d5b38f947b2d0e806e46e2e3c0f93ae3fdba52a4b1fcdf48006763b1d0ea472d78becf5969f6928bc6b7f1bcc7dcc36f4
@@ -0,0 +1,162 @@
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
+ def initialize(**options)
25
+ @nick = options[:nick] || DEFAULT_OPTIONS[:nick]
26
+ @websocket_url = Async::HTTP::Endpoint.parse(options[:websocket_url] || DEFAULT_OPTIONS[:websocket_url])
27
+ end
28
+
29
+ # @yield
30
+ # @yieldparam
31
+ def ready(&block)
32
+ @ready_handle = block
33
+ end
34
+
35
+ # @return [Boolean]
36
+ def ready?
37
+ @ws != nil
38
+ end
39
+
40
+ # @return [Async::Task]
41
+ def start
42
+ Async do
43
+ Async::WebSocket::Client.connect(@websocket_url) do |ws|
44
+ @ws = ws
45
+ ws.write("NICK #{@nick}")
46
+ dispatch_ready
47
+
48
+ while (ws_message = ws.read)
49
+ data = ws_message.to_str
50
+ if data.start_with?("PING")
51
+ ws.write("PONG :tmi.twitch.tv")
52
+ next
53
+ end
54
+
55
+ next unless data.include?("PRIVMSG")
56
+
57
+ dispatch(Message.new(data, connection: self))
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ # @return [Array<Symbol>]
64
+ def channels
65
+ streams.keys
66
+ end
67
+
68
+ # @yield
69
+ # @yieldparam streamer [Symbol]
70
+ # @yieldreturn [nil]
71
+ def joined(&block)
72
+ @join_handle = block
73
+ end
74
+
75
+ # @yield
76
+ # @yieldparam streamer [Symbol]
77
+ # @yieldreturn [nil]
78
+ def left(&block)
79
+ @leave_handle = block
80
+ end
81
+
82
+ # @param streamer [Symbol, String]
83
+ # @yield
84
+ # @yieldparam message [Twitch::Message]
85
+ # @yieldreturn [nil]
86
+ # @example
87
+ # bot.join(:twitchgaming) do |message|
88
+ # puts "##{message.channel} #{message.sender}: #{message}"
89
+ # end
90
+ def join(streamer, &block)
91
+ streamer = streamer.to_sym
92
+ unless ready?
93
+ yield_join(streamer, &block)
94
+ return
95
+ end
96
+
97
+ streams[streamer] = [] unless streams.key?(streamer)
98
+ streams[streamer] << block if block_given?
99
+ @ws.write("JOIN ##{streamer}")
100
+ @join_handle&.call(streamer)
101
+ end
102
+
103
+ # @param streamer [Symbol, String]
104
+ # @example
105
+ # bot.leave(:twitchgaming)
106
+ def leave(streamer)
107
+ streamer = streamer.to_sym
108
+ streams[streamer] = []
109
+ @ws.write("PART ##{streamer}")
110
+ @leave_handle&.call(streamer)
111
+ end
112
+
113
+ # @yield
114
+ # @yieldparam message [Twitch::Message]
115
+ # @yieldreturn [nil]
116
+ # @example
117
+ # bot.message do |message|
118
+ # puts "##{message.channel} #{message.sender}: #{message}"
119
+ # end
120
+ def message(&block)
121
+ @message_handle = block
122
+ end
123
+
124
+ alias_method :part, :leave
125
+ alias_method :on_leave, :leave
126
+ alias_method :on_join, :joined
127
+ alias_method :on_message, :message
128
+
129
+ private
130
+
131
+ def dispatch(message)
132
+ @message_handle&.call(message)
133
+ streams[message.channel.to_sym].each do |block|
134
+ block.call(message)
135
+ end
136
+ end
137
+
138
+ def dispatch_ready
139
+ join_all
140
+ @ready_handle&.call
141
+ end
142
+
143
+ def streams
144
+ @streams ||= {}
145
+ end
146
+
147
+ def pending
148
+ @pending ||= {}
149
+ end
150
+
151
+ def yield_join(streamer, &block)
152
+ pending[streamer] = [] if streamer
153
+ pending[streamer] << block
154
+ end
155
+
156
+ def join_all
157
+ pending.each do |streamer, blocks|
158
+ blocks.each { |block| join(streamer, &block) }
159
+ end
160
+ end
161
+ end
162
+ 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, String, 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,72 @@
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(":justinfan!justinfan@justinfan.tmi.twitch.tv PRIVMSG #twitchgaming :Hello world!\r\n")
14
+ # message.sender.name # => :justinfan
15
+ # message.channel.name # => :twitchgaming
16
+ # message.content # => "Hello world!"
17
+ # message.raw # => ":justinfan!justinfan@justinfan.tmi.twitch.tv PRIVMSG #justinfan :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(":justinfan!justinfan@justinfan.tmi.twitch.tv PRIVMSG #twitchgaming :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
+ @connection = connection
32
+ @channel = Channel.new(split[2][1..-1], connection: connection)
33
+ @sender = Channel.new(split[0].split("!")[0][1..-1])
34
+ @raw = raw
35
+ end
36
+
37
+ alias_method :text, :content
38
+ alias_method :streamer, :channel
39
+
40
+ USERNAME = /[a-zA-Z0-9_]{4,25}/
41
+ # @return [Array<Twitch::Channel>] List of usernames mentioned in the message
42
+ def mentions
43
+ return @mentions if @mentions
44
+
45
+ @mentions = []
46
+ @content.split(" ").each do |word|
47
+ match = word.match(/@#{USERNAME}/)
48
+ next unless match
49
+
50
+ @mentions << Channel.new(match[0][1..-1], connection: @connection)
51
+ end
52
+
53
+ @mentions
54
+ end
55
+
56
+ LINK = %r{(https?://[^\s]+)}
57
+ # @return [Array<String>] List of links mentioned in the message
58
+ def links
59
+ return @links if @links
60
+
61
+ @links = []
62
+ @content.split(" ").each do |word|
63
+ match = word.match(LINK)
64
+ next unless match
65
+
66
+ @links << match[0]
67
+ end
68
+
69
+ @links
70
+ end
71
+ end
72
+ 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
@@ -3,7 +3,6 @@
3
3
  require "async"
4
4
  require "async/http/endpoint"
5
5
  require "async/websocket/client"
6
- require_relative "twitch_chatter/concerns"
7
6
  require_relative "twitch_chatter/models"
8
7
  require_relative "twitch_chatter/bot"
9
8
 
metadata CHANGED
@@ -1,15 +1,29 @@
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.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dylan Hackworth
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-21 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2024-05-26 00:00:00.000000000 Z
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,12 +31,16 @@ extensions: []
17
31
  extra_rdoc_files: []
18
32
  files:
19
33
  - lib/twitch_chatter.rb
20
- homepage: https://github.com/dylhack/twitch-chat-gem
34
+ - lib/twitch_chatter/bot.rb
35
+ - lib/twitch_chatter/models.rb
36
+ - lib/twitch_chatter/models/channel.rb
37
+ - lib/twitch_chatter/models/message.rb
38
+ homepage: https://github.com/dylhack/twitch_chatter
21
39
  licenses:
22
40
  - MIT
23
41
  metadata:
24
- source_code_uri: https://github.com/dylhack/twitch-chat-gem
25
- post_install_message:
42
+ source_code_uri: https://github.com/dylhack/twitch_chatter
43
+ post_install_message:
26
44
  rdoc_options: []
27
45
  require_paths:
28
46
  - lib
@@ -30,7 +48,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
30
48
  requirements:
31
49
  - - ">="
32
50
  - !ruby/object:Gem::Version
33
- version: 3.1.0
51
+ version: 3.1.1
34
52
  required_rubygems_version: !ruby/object:Gem::Requirement
35
53
  requirements:
36
54
  - - ">="
@@ -38,7 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
56
  version: '0'
39
57
  requirements: []
40
58
  rubygems_version: 3.5.9
41
- signing_key:
59
+ signing_key:
42
60
  specification_version: 4
43
61
  summary: Read-only Twitch chat client.
44
62
  test_files: []