mirror of
https://github.com/dalbodeule/chibot-chzzk-bot.git
synced 2025-08-08 05:11:12 +00:00
[refactor] user and live stream handling logic
Replaced ChzzkUserCache with event-based user fetching for cleaner architecture. Integrated new ChzzkUserFindEvent and ChzzkUserReceiveEvent to handle user data retrieval. Removed old utility methods and streamlined live stream status checks with updated APIs.
This commit is contained in:
@@ -1,12 +1,9 @@
|
||||
package space.mori.chzzk_bot.chatbot.chzzk
|
||||
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.future.await
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.OkHttpClient
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
@@ -21,12 +18,12 @@ import space.mori.chzzk_bot.common.services.TimerConfigService
|
||||
import space.mori.chzzk_bot.common.services.UserService
|
||||
import space.mori.chzzk_bot.common.utils.*
|
||||
import xyz.r2turntrue.chzzk4j.ChzzkClient
|
||||
import xyz.r2turntrue.chzzk4j.auth.ChzzkSimpleUserLoginAdapter
|
||||
import xyz.r2turntrue.chzzk4j.session.ChzzkSessionBuilder
|
||||
import xyz.r2turntrue.chzzk4j.session.ChzzkSessionSubscriptionType
|
||||
import xyz.r2turntrue.chzzk4j.session.ChzzkUserSession
|
||||
import xyz.r2turntrue.chzzk4j.session.event.SessionChatMessageEvent
|
||||
import xyz.r2turntrue.chzzk4j.types.channel.ChzzkChannel
|
||||
import xyz.r2turntrue.chzzk4j.types.channel.live.ChzzkLiveStatus
|
||||
import java.lang.Exception
|
||||
import java.net.SocketTimeoutException
|
||||
import java.time.LocalDateTime
|
||||
@@ -53,8 +50,8 @@ object ChzzkHandler {
|
||||
}
|
||||
|
||||
handlers.forEach { handler ->
|
||||
val streamInfo = getStreamInfo(handler.channel.channelId)
|
||||
if (streamInfo.content?.status == "OPEN") handler.isActive(true, streamInfo)
|
||||
val streamInfo = Connector.getLive(handler.channel.channelId)
|
||||
if (streamInfo?.isOnline == true) handler.isActive(true, streamInfo)
|
||||
}
|
||||
|
||||
dispatcher.subscribe(UserRegisterEvent::class) {
|
||||
@@ -113,15 +110,15 @@ object ChzzkHandler {
|
||||
handlers.forEach {
|
||||
if (!running) return@forEach
|
||||
try {
|
||||
val streamInfo = getStreamInfo(it.channel.channelId)
|
||||
if (streamInfo.content?.status == "OPEN" && !it.isActive) {
|
||||
val streamInfo = Connector.getLive(it.channel.channelId)
|
||||
if (streamInfo?.isOnline == true && !it.isActive) {
|
||||
try {
|
||||
it.isActive(true, streamInfo)
|
||||
} catch(e: Exception) {
|
||||
logger.info("Exception: ${e.stackTraceToString()}")
|
||||
}
|
||||
}
|
||||
if (streamInfo.content?.status == "CLOSE" && it.isActive) it.isActive(false, streamInfo)
|
||||
if (streamInfo?.isOnline == false && it.isActive) it.isActive(false, streamInfo)
|
||||
} catch (e: SocketTimeoutException) {
|
||||
logger.info("Thread 1 Timeout: ${it.channel.channelName} / ${e.stackTraceToString()}")
|
||||
} catch (e: Exception) {
|
||||
@@ -141,19 +138,19 @@ object ChzzkHandler {
|
||||
handlers.forEach {
|
||||
if (!running) return@forEach
|
||||
try {
|
||||
val streamInfo = getStreamInfo(it.channel.channelId)
|
||||
if (streamInfo.content?.status == "OPEN" && !it.isActive) {
|
||||
val streamInfo = Connector.getLive(it.channel.channelId)
|
||||
if (streamInfo?.isOnline == true && !it.isActive) {
|
||||
try {
|
||||
it.isActive(true, streamInfo)
|
||||
} catch(e: Exception) {
|
||||
logger.info("Exception: ${e.stackTraceToString()}")
|
||||
}
|
||||
}
|
||||
if (streamInfo.content?.status == "CLOSE" && it.isActive) it.isActive(false, streamInfo)
|
||||
if (streamInfo?.isOnline == false && it.isActive) it.isActive(false, streamInfo)
|
||||
} catch (e: SocketTimeoutException) {
|
||||
logger.info("Thread 2 Timeout: ${it.channel.channelName} / ${e.stackTraceToString()}")
|
||||
logger.info("Thread 1 Timeout: ${it.channel.channelName} / ${e.stackTraceToString()}")
|
||||
} catch (e: Exception) {
|
||||
logger.info("Thread 2 Exception: ${it.channel.channelName} / ${e.stackTraceToString()}")
|
||||
logger.info("Thread 1 Exception: ${it.channel.channelName} / ${e.stackTraceToString()}")
|
||||
} finally {
|
||||
Thread.sleep(5000)
|
||||
}
|
||||
@@ -204,8 +201,8 @@ class UserHandler(
|
||||
var streamStartTime: LocalDateTime?,
|
||||
) {
|
||||
var messageHandler: MessageHandler
|
||||
lateinit var client: ChzzkClient
|
||||
lateinit var listener: ChzzkUserSession
|
||||
var client: ChzzkClient
|
||||
var listener: ChzzkUserSession
|
||||
|
||||
private val dispatcher: CoroutinesEventBus by inject(CoroutinesEventBus::class.java)
|
||||
private var _isActive: Boolean
|
||||
@@ -252,7 +249,7 @@ class UserHandler(
|
||||
internal val isActive: Boolean
|
||||
get() = _isActive
|
||||
|
||||
internal fun isActive(value: Boolean, status: IData<IStreamInfo?>) {
|
||||
internal fun isActive(value: Boolean, status: ChzzkLiveStatus) {
|
||||
if(value) {
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
logger.info("${user.username} is live.")
|
||||
@@ -262,7 +259,7 @@ class UserHandler(
|
||||
logger.info("ChzzkChat connecting... ${channel.channelName} - ${channel.channelId}")
|
||||
listener.subscribeAsync(ChzzkSessionSubscriptionType.CHAT)
|
||||
|
||||
streamStartTime = status.content?.openDate?.let { convertChzzkDateToLocalDateTime(it) }
|
||||
streamStartTime = LocalDateTime.now()
|
||||
|
||||
if(!_isActive) {
|
||||
_isActive = true
|
||||
|
@@ -1,28 +1,56 @@
|
||||
package space.mori.chzzk_bot.chatbot.chzzk
|
||||
|
||||
import io.github.cdimascio.dotenv.dotenv
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
import org.slf4j.LoggerFactory
|
||||
import space.mori.chzzk_bot.common.events.ChzzkUserFindEvent
|
||||
import space.mori.chzzk_bot.common.events.ChzzkUserReceiveEvent
|
||||
import space.mori.chzzk_bot.common.events.CoroutinesEventBus
|
||||
import xyz.r2turntrue.chzzk4j.ChzzkClient
|
||||
import xyz.r2turntrue.chzzk4j.ChzzkClientBuilder
|
||||
import xyz.r2turntrue.chzzk4j.auth.ChzzkOauthLoginAdapter
|
||||
import xyz.r2turntrue.chzzk4j.auth.ChzzkLegacyLoginAdapter
|
||||
import xyz.r2turntrue.chzzk4j.auth.ChzzkSimpleUserLoginAdapter
|
||||
import xyz.r2turntrue.chzzk4j.types.channel.ChzzkChannel
|
||||
import xyz.r2turntrue.chzzk4j.types.channel.live.ChzzkLiveStatus
|
||||
import kotlin.getValue
|
||||
|
||||
val dotenv = dotenv {
|
||||
ignoreIfMissing = true
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
object Connector {
|
||||
val adapter = ChzzkLegacyLoginAdapter(dotenv["NID_AUT"], dotenv["NID_SES"])
|
||||
val client: ChzzkClient = ChzzkClientBuilder(dotenv["NAVER_CLIENT_ID"], dotenv["NAVER_CLIENT_SECRET"])
|
||||
.withLoginAdapter(adapter)
|
||||
.build()
|
||||
private val logger = LoggerFactory.getLogger(this::class.java)
|
||||
private val dispatcher: CoroutinesEventBus by inject(CoroutinesEventBus::class.java)
|
||||
|
||||
fun getChannel(channelId: String): ChzzkChannel? = client.fetchChannel(channelId)
|
||||
fun getLive(channelId: String): ChzzkLiveStatus? = client.fetchLiveStatus(channelId)
|
||||
|
||||
init {
|
||||
logger.info("chzzk logged: ${client.isLoggedIn}")
|
||||
|
||||
client.loginAsync().join()
|
||||
|
||||
dispatcher.subscribe(ChzzkUserFindEvent::class) { event ->
|
||||
GlobalScope.launch {
|
||||
val user = getChannel(event.uid)
|
||||
|
||||
dispatcher.post(ChzzkUserReceiveEvent(
|
||||
find = user != null,
|
||||
uid = user?.channelId,
|
||||
nickname = user?.channelName,
|
||||
isStreamOn = user?.isBroadcasting,
|
||||
avatarUrl = user?.channelImageUrl
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getClient(accessToken: String, refreshToken: String): ChzzkClient {
|
||||
@@ -33,4 +61,6 @@ object Connector {
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -12,11 +12,11 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEve
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder
|
||||
import org.slf4j.LoggerFactory
|
||||
import space.mori.chzzk_bot.common.utils.IData
|
||||
import space.mori.chzzk_bot.common.utils.IStreamInfo
|
||||
import space.mori.chzzk_bot.chatbot.discord.commands.*
|
||||
import space.mori.chzzk_bot.common.models.User
|
||||
import xyz.r2turntrue.chzzk4j.types.channel.live.ChzzkLiveStatus
|
||||
import java.time.Instant
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
val dotenv = dotenv {
|
||||
ignoreIfMissing = true
|
||||
@@ -33,20 +33,19 @@ class Discord: ListenerAdapter() {
|
||||
return bot.getGuildById(guildId)?.getTextChannelById(channelId)
|
||||
}
|
||||
|
||||
fun sendDiscord(user: User, status: IData<IStreamInfo?>) {
|
||||
if(status.content == null) return
|
||||
fun sendDiscord(user: User, status: ChzzkLiveStatus) {
|
||||
if(user.liveAlertMessage != null && user.liveAlertGuild != null && user.liveAlertChannel != null) {
|
||||
val channel = getChannel(user.liveAlertGuild ?: 0, user.liveAlertChannel ?: 0)
|
||||
?: throw RuntimeException("${user.liveAlertChannel} is not valid.")
|
||||
|
||||
val embed = EmbedBuilder()
|
||||
embed.setTitle(status.content!!.liveTitle, "https://chzzk.naver.com/live/${user.token}")
|
||||
embed.setTitle(status.title, "https://chzzk.naver.com/live/${user.token}")
|
||||
embed.setDescription("${user.username} 님이 방송을 시작했습니다.")
|
||||
embed.setTimestamp(Instant.now())
|
||||
embed.setAuthor(user.username, "https://chzzk.naver.com/live/${user.token}", status.content!!.channel.channelImageUrl)
|
||||
embed.addField("카테고리", status.content!!.liveCategoryValue, true)
|
||||
embed.addField("태그", status.content!!.tags.joinToString(", "), true)
|
||||
embed.setImage(status.content!!.liveImageUrl.replace("{type}", "1080"))
|
||||
embed.setAuthor(user.username, "https://chzzk.naver.com/live/${user.token}")
|
||||
embed.addField("카테고리", status.categoryType.getOrNull() ?: "Unknown", true)
|
||||
embed.addField("태그", status.tags.joinToString { "," }, true)
|
||||
// embed.setImage(status.)
|
||||
|
||||
channel.sendMessage(
|
||||
MessageCreateBuilder()
|
||||
|
Reference in New Issue
Block a user