Warning
|
Pre-release state. Certain parts of the API will probably change or may be removed going forward. |
A Kotlin library, providing integration of Twitch IRC capabilities within JVM based applications (mainly intended for use with Spring Boot) by leveraging Spring’s WebSocket Support.
The project artifacts are currently only available through GitHub Packages.
To use them within your own project, see the corresponding documentation Installing a Gradle package.
To use this library add the following dependency to the gradle build file:
dependencies {
implementation "io.github.sykq:twitch-chat-client-core:0.0.1"
}
dependencies {
implementation("io.github.sykq:twitch-chat-client-core:0.0.1")
}
When using maven, add the following to the dependencies
sections of your pom.xml
:
<dependency>
<groupId>io.github.sykq</groupId>
<artifactId>twitch-chat-client-core</artifactId>
<version>0.0.1</version>
</dependency>
To use this library in a Spring Boot application, add the following Spring Boot Starter to the dependency section of your gradle build file:
dependencies {
implementation "io.github.sykq:twitch-chat-client-spring-boot-starter:0.0.1"
}
dependencies {
implementation("io.github.sykq:twitch-chat-client-spring-boot-starter:0.0.1")
}
When using maven, add the following to the dependencies
sections of your pom.xml
:
<dependency>
<groupId>io.github.sykq</groupId>
<artifactId>twitch-chat-client-spring-boot-starter</artifactId>
<version>0.0.1</version>
</dependency>
Tip
|
This project’s API uses Kotlin’s function literals with receiver feature in several places. Make sure you’re familiar with it to effectively use this library. |
The io.github.sykq.tcc.TmiClient
class is part of the core library and facilitates the connection with the Twitch Messaging Interface.
To create a new TmiClient instance use the tmiClient()
factory method within the io.github.sykq.tcc
package:
import io.github.sykq.tcc.tmiClient
fun main() {
val tmiClient = tmiClient {
// configure your instance
username = "myTwitchChatBot"
passwordProperty = "TMI_CLIENT_PASSWORD" (1)
// define the channels to join
channels += "myChannel"
channels += "someOtherChannel"
onConnect {
join("yetAnotherChannel") (2)
textMessage("connected") (3)
}
}
tmiClient.block {
// specify what should happen upon receiving a message
if (it.text == "!hello") { (4)
textMessage("Hi ${it.user}")
}
}
}
-
the passwordProperty can be set to the name of an environment variable of system property whose value will be used as the password for connecting to the TMI
-
optionally join another channel upon connecting
-
set an optional
onConnect
action, which will send the text "connected" to all joined channels -
the incoming
TmiMessage
is the lambda parameter (it
), theTmiSession
is the function receiver (this
)
To connect to the Twitch Messaging Interface (TMI) through the TmiClient
you need to provide your Twitch username (login name) in lowercase as the username
and an associated OAuth token as the password
.
Such a token can be generated with the help of the Twitch Chat Password Generator.
Tip
|
Instead of directly setting the password through the By default, the environment variable/system property with key TMI_CLIENT_PASSWORD is used to retrieve the password. The same functionality is present for the These properties are only read if no password or username are explicitly set within the TmiClient’s configurer during initialization. |
See Connecting to Twitch IRC in the official docs for details on how to use your Twitch account to connect to the TMI.
Adding the spring-boot-starter listed in Spring Boot to your Spring Boot project will pull in a AutoConfiguration which adds a BotRegistry
-Bean to the ApplicationContext and provide the additional BotBase
, Bot
and PublishingBot
interfaces which serve as an additional layer above the TmiClient, allowing for implementations to hold bot-specific state.
The TMI-Server will send a PING
message once about every five minutes.
To ensure that the connection is not terminated, the TmiClient will automatically reply to all such messages with a PONG
.
The TmiClient’s messageSink
allows for writing of text messages to joined channels, which aren’t created as a response to an incoming message, but rather come from an independent source (e.g. some user interaction).
Therefore, it should be possible to implement an interactive chat client on top of a TmiClient.
The following example sends two messages to a channel through the sink and then simply prints these messages out to the console (they will be consumed as messages coming in from the channel which has been used by the sink to send the messages to):
import reactor.core.publisher.Sinks
fun main() {
val sink = Sinks.many().unicast().onBackpressureBuffer<String>() (1)
sink.tryEmitNext("hello")
sink.tryEmitNext("hello again")
val tmiClient = tmiClient {
// configure your instance
username = "myUsername"
passwordProperty = TmiClient.TMI_CLIENT_PASSWORD_KEY
// define the channels to join
channels += "myChannel"
messageSink = sink
}
tmiClient.block { message ->
println(message.text)
}
}
-
onBackpressureBuffer()
replays all emissions pushed to this sink while no subscriber is registered, to the first (and only, sinceunicast()
is used) subscriber. This allows us in this demo to push to the sink before the TmiClient establishes a connection to the TMI.
The io.github.sykq.tcc.TmiSession
class is a wrapper over Spring’s WebSocketSession
and provides methods specifically tailored for interacting with the TMI as well as the list of currently joined channels as the member variable joinedChannels
.
This class (and its subclass ConfigurableTmiSession
) is part of the signature of most of TmiClient
's onConnect()
and onMessage()
variants.
Tip
|
An instance of It offers methods to activate membership state event data, tags and commands capabilities. E.g. to enrich incoming messages with tags, use the following instruction in an import io.github.sykq.tcc.tmiClient
fun main() {
val tmiClient = tmiClient {
// configure your instance
// ... (omitted for brevity)
onConnect {
tagCapabilities() (1)
}
}
// ...
}
|
Instances are implicitly provided by a TmiClient when using one of the according methods to establish a connection, e.g. connect()
, connectAndTransform()
or block()
.
-
join()
can be used to join one or more additional channels (as in additional to the channels specified within a TmiClient’s Configurer when creating a new TmiClient. -
leave()
can be used to leave one or more channels. -
textMessage()
can be used to send a text message to one or more channels. The following invocation will send Hello to all joined channels:tmiSession.textMessage("Hello")
The following will send a textMessage to all joined channels whose name starts with the letter a (this is just an artificial example which should demonstrate the possibility to reference the
joinedChannels
list):textMessage("Hello", *joinedChannels.filter { it.startsWith("a") }.toTypedArray())
-
clearChat()
sends the command/clear
to a given channel. Such command sending methods are available for several other command. See the TmiSession class and its KDoc comments for the full list.
The io.github.sykq.tcc.TmiMessage
class represents an incoming message originating from one of the channels within the TMI.
It consists of:
-
timestamp
= the timestamp of arrival at the client. -
channel
= the name of the originating channel of a message. -
user
= the authoring user of a message. -
text
= the text of a message. -
type
= one of the supportedTmiMessageType
s -
tags
= the list of tags associated with a message. NOTE: Will only be supplied if tag capabilities are activated.
Instances are implicitly provided by a TmiClient each time onMessage()
is invoked and one of the according methods to establish a connection, e.g. connect()
, connectAndTransform()
or block()
is used.
The io.github.sykq.tcc.action.OnCommandAction
represents an action in response to an incoming message, which will only be executed if the message is equal to a specified command.
The following examples will send the message Hello, user!
in response to an incoming message with text !greet (where user is the author of the message):
val onGreetCommand = OnCommandAction("!greet") { (tmiMessage, command) -> (1)
textMessage("Hello, ${tmiMessage.user}!")
}
tmiClient.block {
onGreetCommand(this, it) (2)
// potentially other actions
// ...
}
-
the callback is of type
TmiSession.(CommandMessageContext) → Unit
. The example shows a destructuredCommandMessageContext
. -
invoke the
onGreetCommand
as part of a tmiClient’s onMessage actions.this
corresponds to the function receiverTmiSession
, andit
is the incomingTmiMessage
(lambda parameter).
Tip
|
The |
The io.github.sykq.tcc.action.OnCheerAction
represents an action in response to an incoming message, which will only be executed if the message consists of a cheer (Bits donation) which fulfills a given condition linked to the amount of cheered Bits.
The following examples will send the message Thank you user for n bits!
in response to an incoming cheer, if the Bit amount was greater than 100 Bits (where user is the author of the message and n is the amount of Bits donated):
val onBigCheer = OnCheerAction(CheerAmountCondition.greaterThan(100)) { tmiMessage, cheerAmount -> (1)
textMessage("Thank you ${tmiMessage.user} for $cheerAmount bits!")
}
tmiClient.block {
onBigCheer(this, it) (2)
// potentially other actions
// ...
}
-
the callback is of type
TmiSession.(TmiMessage, Int) → Unit
, where the Int parameter is the amount cheered. -
invoke
onBigCheer
as part of a tmiClient’s onMessage actions.this
corresponds to the function receiverTmiSession
, andit
is the incomingTmiMessage
(lambda parameter).
Tip
|
The |
The io.github.sykq.tcc.action.OnUserNoticeAction
represents an action response to an incoming message of type USERNOTICE, which will only be executed if the message is a USERNOTICE
.
Requires Twitch IRC: Tags-Capabilities as well as Twitch IRC: Commands-Capabilities to be active on a session (see TmiSession.tagCapabilities() and ConfigurableTmiSession.commandCapabilities()).
val onSubOrResub = OnUserNoticeAction(UserNoticeType.SUB, UserNoticeType.RESUB) { (1)
changeSomeInternalState(it) (2)
}
tmiClient.block {
onSubOrResubAction(this, it) (3)
// potentially other actions
// ...
}
-
perform the specified action if the USERNOTICE is of sub-type sub or resub. The sub-type is extracted from the tag with key
msg-id
. -
it
is the incoming message,this
the active TmiSession -
invoke
onSubOrResub
as part of a tmiClient’s onMessage actions.this
corresponds to the function receiverTmiSession
, andit
is the incomingTmiMessage
(lambda parameter).
Tip
|
The |
TODO, but see TmiProperties for now.
A sample project consisting of a Spring Boot web service application which uses the features of this library can be found at https://github.com/sykq/twitch-chat-bot-service
Important
|
Builds with JDK 16+ won’t succeed since kapt uses some internal API which is no longer accessible in those builds. |