From 101db7d20c1c183a428b406c5ec3edd2cc1dddd1 Mon Sep 17 00:00:00 2001 From: dalbodeule <11470513+dalbodeule@users.noreply.github.com> Date: Tue, 13 May 2025 21:31:17 +0900 Subject: [PATCH] [refactor] chzzk4j update to 0.1.1 --- build.gradle.kts | 2 +- chatbot/build.gradle.kts | 4 +- .../chzzk_bot/chatbot/chzzk/ChzzkHandler.kt | 73 +++++----- .../mori/chzzk_bot/chatbot/chzzk/Connector.kt | 24 +++- .../chzzk_bot/chatbot/chzzk/MessageHandler.kt | 129 +++++++++--------- .../chatbot/utils/accessTokenRefresh.kt | 55 ++++++++ common/build.gradle.kts | 2 +- webserver/build.gradle.kts | 2 +- 8 files changed, 184 insertions(+), 107 deletions(-) create mode 100644 chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/utils/accessTokenRefresh.kt diff --git a/build.gradle.kts b/build.gradle.kts index b8d5a3e..5e238b5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,7 +28,7 @@ repositories { dependencies { // https://mvnrepository.com/artifact/ch.qos.logback/logback-classic - implementation("ch.qos.logback:logback-classic:1.5.12") + implementation("ch.qos.logback:logback-classic:1.5.13") // https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") diff --git a/chatbot/build.gradle.kts b/chatbot/build.gradle.kts index 5114398..fcab2d3 100644 --- a/chatbot/build.gradle.kts +++ b/chatbot/build.gradle.kts @@ -16,10 +16,10 @@ dependencies { } // https://mvnrepository.com/artifact/io.github.R2turnTrue/chzzk4j - implementation("io.github.R2turnTrue:chzzk4j:0.0.12") + implementation("io.github.R2turnTrue:chzzk4j:0.1.1") // https://mvnrepository.com/artifact/ch.qos.logback/logback-classic - implementation("ch.qos.logback:logback-classic:1.5.12") + implementation("ch.qos.logback:logback-classic:1.5.13") // https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") diff --git a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/ChzzkHandler.kt b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/ChzzkHandler.kt index d412c6b..b3d5547 100644 --- a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/ChzzkHandler.kt +++ b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/ChzzkHandler.kt @@ -1,25 +1,31 @@ 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 -import space.mori.chzzk_bot.chatbot.chzzk.Connector.chzzk +import space.mori.chzzk_bot.chatbot.chzzk.Connector.client as ChzzkClient import space.mori.chzzk_bot.chatbot.chzzk.Connector.getChannel import space.mori.chzzk_bot.chatbot.discord.Discord +import space.mori.chzzk_bot.chatbot.utils.refreshAccessToken import space.mori.chzzk_bot.common.events.* import space.mori.chzzk_bot.common.models.User import space.mori.chzzk_bot.common.services.LiveStatusService 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.chat.ChatEventListener -import xyz.r2turntrue.chzzk4j.chat.ChatMessage -import xyz.r2turntrue.chzzk4j.chat.ChzzkChat +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 java.lang.Exception import java.net.SocketTimeoutException @@ -37,18 +43,17 @@ object ChzzkHandler { } fun enable() { - botUid = chzzk.loggedUser.userId UserService.getAllUsers().map { if(!it.isDisabled) try { - chzzk.getChannel(it.token)?.let { token -> addUser(token, it) } + Connector.getChannel(it.token)?.let { token -> addUser(token, it) } } catch(e: Exception) { logger.info("Exception: ${it.token}(${it.username}) not found. ${e.stackTraceToString()}") } } handlers.forEach { handler -> - val streamInfo = getStreamInfo(handler.listener.channelId) + val streamInfo = getStreamInfo(handler.channel.channelId) if (streamInfo.content?.status == "OPEN") handler.isActive(true, streamInfo) } @@ -199,7 +204,8 @@ class UserHandler( var streamStartTime: LocalDateTime?, ) { var messageHandler: MessageHandler - var listener: ChzzkChat + lateinit var client: ChzzkClient + lateinit var listener: ChzzkUserSession private val dispatcher: CoroutinesEventBus by inject(CoroutinesEventBus::class.java) private var _isActive: Boolean @@ -209,35 +215,30 @@ class UserHandler( } init { - listener = chzzk.chat(channel.channelId) - .withAutoReconnect(true) - .withChatListener(object : ChatEventListener { - override fun onConnect(chat: ChzzkChat, isReconnecting: Boolean) { - logger.info("${channel.channelName} - ${channel.channelId} / reconnected: $isReconnecting") - } + val user = UserService.getUser(channel.channelId) - override fun onError(ex: Exception) { - logger.info("ChzzkChat error. ${channel.channelName} - ${channel.channelId}") - logger.info(ex.stackTraceToString()) - } + if(user?.accessToken == null || user.refreshToken == null) { + throw RuntimeException("AccessToken or RefreshToken is not valid.") + } - override fun onChat(msg: ChatMessage) { - if(!_isActive) return - messageHandler.handle(msg, user) - } + val tokens = ChzzkClient.refreshAccessToken(user.refreshToken!!) - override fun onConnectionClosed(code: Int, reason: String?, remote: Boolean, tryingToReconnect: Boolean) { - logger.info("ChzzkChat closed. ${channel.channelName} - ${channel.channelId}") - logger.info("Reason: $reason / $tryingToReconnect") - } - }) - .build() + client = Connector.getClient(tokens.first, tokens.second) + listener = ChzzkSessionBuilder(client).buildUserSession() + + UserService.setTokens(user, tokens.first, tokens.second) + + listener.createAndConnectAsync().join() + + listener.on(SessionChatMessageEvent::class.java) { + messageHandler.handle(it.message, user) + } messageHandler = MessageHandler(this@UserHandler) } - internal fun disable() { - listener.closeAsync() + listener.disconnectAsync().join() + _isActive = false } internal fun reloadCommand() { @@ -259,7 +260,7 @@ class UserHandler( reloadUser(UserService.getUser(user.id.value)!!) logger.info("ChzzkChat connecting... ${channel.channelName} - ${channel.channelId}") - listener.connectAsync().await() + listener.subscribeAsync(ChzzkSessionSubscriptionType.CHAT) streamStartTime = status.content?.openDate?.let { convertChzzkDateToLocalDateTime(it) } @@ -285,7 +286,7 @@ class UserHandler( delay(5000L) try { if(!user.isDisableStartupMsg) - listener.sendChat("${user.username} 님! 오늘도 열심히 방송하세요!") + sendChat("${user.username} 님! 오늘도 열심히 방송하세요!") Discord.sendDiscord(user, status) } catch(e: Exception) { logger.info("Stream on logic has some error: ${e.stackTraceToString()}") @@ -295,7 +296,7 @@ class UserHandler( } else { logger.info("${user.username} is offline.") streamStartTime = null - listener.closeAsync() + listener.disconnectAsync().join() _isActive = false CoroutineScope(Dispatchers.Default).launch { @@ -319,4 +320,8 @@ class UserHandler( } } } -} \ No newline at end of file + + internal fun sendChat(msg: String) { + client.sendChatToLoggedInChannel(msg) + } +} diff --git a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/Connector.kt b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/Connector.kt index 7309c11..9e60cbc 100644 --- a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/Connector.kt +++ b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/Connector.kt @@ -2,8 +2,10 @@ package space.mori.chzzk_bot.chatbot.chzzk import io.github.cdimascio.dotenv.dotenv import org.slf4j.LoggerFactory -import xyz.r2turntrue.chzzk4j.Chzzk -import xyz.r2turntrue.chzzk4j.ChzzkBuilder +import xyz.r2turntrue.chzzk4j.ChzzkClient +import xyz.r2turntrue.chzzk4j.ChzzkClientBuilder +import xyz.r2turntrue.chzzk4j.auth.ChzzkOauthLoginAdapter +import xyz.r2turntrue.chzzk4j.auth.ChzzkSimpleUserLoginAdapter import xyz.r2turntrue.chzzk4j.types.channel.ChzzkChannel val dotenv = dotenv { @@ -11,14 +13,24 @@ val dotenv = dotenv { } object Connector { - val chzzk: Chzzk = ChzzkBuilder() - .withAuthorization(dotenv["NID_AUT"], dotenv["NID_SES"]) + val client: ChzzkClient = ChzzkClientBuilder(dotenv["NAVER_CLIENT_ID"], dotenv["NAVER_CLIENT_SECRET"]) .build() private val logger = LoggerFactory.getLogger(this::class.java) - fun getChannel(channelId: String): ChzzkChannel? = chzzk.getChannel(channelId) + fun getChannel(channelId: String): ChzzkChannel? = client.fetchChannel(channelId) init { - logger.info("chzzk logged: ${chzzk.isLoggedIn} / ${chzzk.loggedUser?.nickname ?: "----"}") + logger.info("chzzk logged: ${client.isLoggedIn}") + + client.loginAsync().join() + } + + fun getClient(accessToken: String, refreshToken: String): ChzzkClient { + val adapter = ChzzkSimpleUserLoginAdapter(accessToken, refreshToken) + val client = ChzzkClientBuilder(dotenv["NAVER_CLIENT_ID"], dotenv["NAVER_CLIENT_SECRET"]) + .withLoginAdapter(adapter) + .build() + + return client } } \ No newline at end of file diff --git a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/MessageHandler.kt b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/MessageHandler.kt index e4300b7..f0a72de 100644 --- a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/MessageHandler.kt +++ b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/chzzk/MessageHandler.kt @@ -13,15 +13,16 @@ import space.mori.chzzk_bot.common.utils.getUptime import space.mori.chzzk_bot.common.utils.getYoutubeVideo import xyz.r2turntrue.chzzk4j.chat.ChatMessage import xyz.r2turntrue.chzzk4j.chat.ChzzkChat +import xyz.r2turntrue.chzzk4j.session.ChzzkUserSession +import xyz.r2turntrue.chzzk4j.session.message.SessionChatMessage import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit - class MessageHandler( private val handler: UserHandler ) { - private val commands = mutableMapOf Unit>() + private val commands = mutableMapOf Unit>() private val counterPattern = Regex("]+)>") private val personalCounterPattern = Regex("]+)>") @@ -71,85 +72,90 @@ class MessageHandler( this.commands.put(it.command.lowercase()) { msg, user -> logger.debug("${channel.channelName} - ${it.command} - ${it.content}/${it.failContent}") - val result = replaceCounters(Pair(it.content, it.failContent), user, msg, listener, msg.profile?.nickname ?: "") - listener.sendChat(result) + val result = replaceCounters( + Pair(it.content, it.failContent), + user, + msg, + msg.profile?.nickname ?: "" + ) + handler.sendChat(result) } } } - private fun commandListCommand(msg: ChatMessage, user: User) { - listener.sendChat("리스트는 여기입니다. https://nabot.mori.space/commands/${user.token}") + private fun commandListCommand(msg: SessionChatMessage, user: User) { + handler.sendChat("리스트는 여기입니다. https://nabot.mori.space/commands/${user.token}") } - private fun manageAddCommand(msg: ChatMessage, user: User) { - if (msg.profile?.userRoleCode == "common_user") { - listener.sendChat("매니저만 명령어를 추가할 수 있습니다.") + private fun manageAddCommand(msg: SessionChatMessage, user: User) { + if (msg.profile.badges.size == 0) { + handler.sendChat("매니저만 명령어를 추가할 수 있습니다.") return } val parts = msg.content.split(" ", limit = 3) if (parts.size < 3) { - listener.sendChat("명령어 추가 형식은 '!명령어추가 명령어 내용'입니다.") + handler.sendChat("명령어 추가 형식은 '!명령어추가 명령어 내용'입니다.") return } if (commands.containsKey(parts[1])) { - listener.sendChat("${parts[1]} 명령어는 이미 있는 명령어입니다.") + handler.sendChat("${parts[1]} 명령어는 이미 있는 명령어입니다.") return } val command = parts[1] val content = parts[2] CommandService.saveCommand(user, command, content, "") - listener.sendChat("명령어 '$command' 추가되었습니다.") + handler.sendChat("명령어 '$command' 추가되었습니다.") } - private fun manageUpdateCommand(msg: ChatMessage, user: User) { - if (msg.profile?.userRoleCode == "common_user") { - listener.sendChat("매니저만 명령어를 추가할 수 있습니다.") + private fun manageUpdateCommand(msg: SessionChatMessage, user: User) { + if (msg.profile.badges.size == 0) { + handler.sendChat("매니저만 명령어를 추가할 수 있습니다.") return } val parts = msg.content.split(" ", limit = 3) if (parts.size < 3) { - listener.sendChat("명령어 수정 형식은 '!명령어수정 명령어 내용'입니다.") + handler.sendChat("명령어 수정 형식은 '!명령어수정 명령어 내용'입니다.") return } if (!commands.containsKey(parts[1])) { - listener.sendChat("${parts[1]} 명령어는 없는 명령어입니다.") + handler.sendChat("${parts[1]} 명령어는 없는 명령어입니다.") return } val command = parts[1] val content = parts[2] CommandService.updateCommand(user, command, content, "") - listener.sendChat("명령어 '$command' 수정되었습니다.") + handler.sendChat("명령어 '$command' 수정되었습니다.") ChzzkHandler.reloadCommand(channel) } - private fun manageRemoveCommand(msg: ChatMessage, user: User) { - if (msg.profile?.userRoleCode == "common_user") { - listener.sendChat("매니저만 명령어를 삭제할 수 있습니다.") + private fun manageRemoveCommand(msg: SessionChatMessage, user: User) { + if (msg.profile.badges.size == 0) { + handler.sendChat("매니저만 명령어를 삭제할 수 있습니다.") return } val parts = msg.content.split(" ", limit = 2) if (parts.size < 2) { - listener.sendChat("명령어 삭제 형식은 '!명령어삭제 명령어'입니다.") + handler.sendChat("명령어 삭제 형식은 '!명령어삭제 명령어'입니다.") return } val command = parts[1] CommandService.removeCommand(user, command) - listener.sendChat("명령어 '$command' 삭제되었습니다.") + handler.sendChat("명령어 '$command' 삭제되었습니다.") ChzzkHandler.reloadCommand(channel) } - private fun timerCommand(msg: ChatMessage, user: User) { - if (msg.profile?.userRoleCode == "common_user") { - listener.sendChat("매니저만 이 명령어를 사용할 수 있습니다.") + private fun timerCommand(msg: SessionChatMessage, user: User) { + if (msg.profile.badges.size == 0) { + handler.sendChat("매니저만 이 명령어를 사용할 수 있습니다.") return } val parts = msg.content.split(" ", limit = 3) if (parts.size < 2) { - listener.sendChat("타이머 명령어 형식을 잘 찾아봐주세요!") + handler.sendChat("타이머 명령어 형식을 잘 찾아봐주세요!") return } @@ -178,13 +184,13 @@ class MessageHandler( when (parts[2]) { "업타임" -> { TimerConfigService.saveOrUpdateConfig(user, TimerType.UPTIME) - listener.sendChat("기본 타이머 설정이 업타임으로 바뀌었습니다.") + handler.sendChat("기본 타이머 설정이 업타임으로 바뀌었습니다.") } "삭제" -> { TimerConfigService.saveOrUpdateConfig(user, TimerType.REMOVE) - listener.sendChat("기본 타이머 설정이 삭제로 바뀌었습니다.") + handler.sendChat("기본 타이머 설정이 삭제로 바뀌었습니다.") } - else -> listener.sendChat("!타이머 설정 (업타임/삭제) 형식으로 써주세요!") + else -> handler.sendChat("!타이머 설정 (업타임/삭제) 형식으로 써주세요!") } } else -> { @@ -198,9 +204,9 @@ class MessageHandler( dispatcher.post(TimerEvent(user.token, TimerType.TIMER, timestamp.toString())) } } catch (e: NumberFormatException) { - listener.sendChat("!타이머/숫자 형식으로 적어주세요! 단위: 분") + handler.sendChat("!타이머/숫자 형식으로 적어주세요! 단위: 분") } catch (e: Exception) { - listener.sendChat("타이머 설정 중 오류가 발생했습니다.") + handler.sendChat("타이머 설정 중 오류가 발생했습니다.") logger.error("Error processing timer command: ${e.message}", e) } } @@ -208,21 +214,21 @@ class MessageHandler( } // songs - private fun songAddCommand(msg: ChatMessage, user: User) { + private fun songAddCommand(msg: SessionChatMessage, user: User) { if(SongConfigService.getConfig(user).disabled) { return } val parts = msg.content.split(" ", limit = 2) if (parts.size < 2) { - listener.sendChat("유튜브 URL을 입력해주세요!") + handler.sendChat("유튜브 URL을 입력해주세요!") return } val config = SongConfigService.getConfig(user) - if(config.streamerOnly && msg.profile?.userRoleCode == "common_user") { - listener.sendChat("매니저만 이 명령어를 사용할 수 있습니다.") + if(config.streamerOnly && msg.profile.badges.size == 0) { + handler.sendChat("매니저만 이 명령어를 사용할 수 있습니다.") return } @@ -230,34 +236,34 @@ class MessageHandler( val songs = SongListService.getSong(user) if(songs.size >= config.queueLimit) { - listener.sendChat("더이상 노래를 신청할 수 없습니다. 잠시 뒤 다시 시도해주세요!") + handler.sendChat("더이상 노래를 신청할 수 없습니다. 잠시 뒤 다시 시도해주세요!") return } - if(songs.filter { it.uid == msg.userId }.size >= config.personalLimit) { - listener.sendChat("더이상 노래를 신청할 수 없습니다. 잠시 뒤 다시 시도해주세요!") + if(songs.filter { it.uid == msg.senderChannelId }.size >= config.personalLimit) { + handler.sendChat("더이상 노래를 신청할 수 없습니다. 잠시 뒤 다시 시도해주세요!") return } try { val video = getYoutubeVideo(url) if (video == null) { - listener.sendChat("유튜브에서 찾을 수 없어요!") + handler.sendChat("유튜브에서 찾을 수 없어요!") return } if (songs.any { it.url == video.url }) { - listener.sendChat("같은 노래가 이미 신청되어 있습니다.") + handler.sendChat("같은 노래가 이미 신청되어 있습니다.") return } if (video.length > 600) { - listener.sendChat("10분이 넘는 노래는 신청할 수 없습니다.") + handler.sendChat("10분이 넘는 노래는 신청할 수 없습니다.") return } SongListService.saveSong( user, - msg.userId, + msg.senderChannelId, video.url, video.name, video.author, @@ -269,31 +275,31 @@ class MessageHandler( SongEvent( user.token, SongType.ADD, - msg.userId, + msg.senderChannelId, null, video, ) ) } - listener.sendChat("노래가 추가되었습니다. ${video.name} - ${video.author}") + handler.sendChat("노래가 추가되었습니다. ${video.name} - ${video.author}") } catch(e: Exception) { - listener.sendChat("유튜브 영상 주소로 다시 신청해주세요!") + handler.sendChat("유튜브 영상 주소로 다시 신청해주세요!") logger.info(e.stackTraceToString()) } } - private fun songListCommand(msg: ChatMessage, user: User) { + private fun songListCommand(msg: SessionChatMessage, user: User) { if(SongConfigService.getConfig(user).disabled) { return } - listener.sendChat("리스트는 여기입니다. https://nabot.mori.space/songs/${user.token}") + handler.sendChat("리스트는 여기입니다. https://nabot.mori.space/songs/${user.token}") } - private fun songStartCommand(msg: ChatMessage, user: User) { - if (msg.profile?.userRoleCode == "common_user") { - listener.sendChat("매니저만 이 명령어를 사용할 수 있습니다.") + private fun songStartCommand(msg: SessionChatMessage, user: User) { + if (msg.profile?.badges?.size == 0) { + handler.sendChat("매니저만 이 명령어를 사용할 수 있습니다.") return } @@ -306,28 +312,28 @@ class MessageHandler( } } } else { - listener.sendChat("나봇 홈페이지의 노래목록 페이지를 이용해주세요! 디스코드 연동을 하시면 DM으로 바로 전송됩니다.") + handler.sendChat("나봇 홈페이지의 노래목록 페이지를 이용해주세요! 디스코드 연동을 하시면 DM으로 바로 전송됩니다.") } } - internal fun handle(msg: ChatMessage, user: User) { - if(msg.userId == ChzzkHandler.botUid) return + internal fun handle(msg: SessionChatMessage, user: User) { + if(msg.senderChannelId == ChzzkHandler.botUid) return val commandKey = msg.content.split(' ')[0] commands[commandKey.lowercase()]?.let { it(msg, user) } } - private fun replaceCounters(chat: Pair, user: User, msg: ChatMessage, listener: ChzzkChat, userName: String): String { + private fun replaceCounters(chat: Pair, user: User, msg: SessionChatMessage, userName: String): String { var result = chat.first var isFail = false // Replace dailyCounterPattern result = dailyCounterPattern.replace(result) { matchResult -> val name = matchResult.groupValues[1] - val dailyCounter = CounterService.getDailyCounterValue(name, msg.userId, user) + val dailyCounter = CounterService.getDailyCounterValue(name, msg.senderChannelId, user) if (dailyCounter.second) { - CounterService.updateDailyCounterValue(name, msg.userId, 1, user).first.toString() + CounterService.updateDailyCounterValue(name, msg.senderChannelId, 1, user).first.toString() } else { isFail = true dailyCounter.first.toString() @@ -339,7 +345,7 @@ class MessageHandler( result = chat.second result = dailyCounterPattern.replace(result) { matchResult -> val name = matchResult.groupValues[1] - val dailyCounter = CounterService.getDailyCounterValue(name, msg.userId, user) + val dailyCounter = CounterService.getDailyCounterValue(name, msg.senderChannelId, user) dailyCounter.first.toString() } } @@ -347,7 +353,7 @@ class MessageHandler( // Replace followPattern result = followPattern.replace(result) { _ -> try { - val followingDate = getFollowDate(listener.chatId, msg.userId) + val followingDate = getFollowDate(channel.channelId, msg.senderChannelId) .content?.streamingProperty?.following?.followDate val period = followingDate?.let { @@ -383,7 +389,7 @@ class MessageHandler( // Replace personalCounterPattern result = personalCounterPattern.replace(result) { matchResult -> val name = matchResult.groupValues[1] - CounterService.updatePersonalCounterValue(name, msg.userId, 1, user).toString() + CounterService.updatePersonalCounterValue(name, msg.senderChannelId, 1, user).toString() } // Replace namePattern @@ -391,5 +397,4 @@ class MessageHandler( return result } - -} \ No newline at end of file +} diff --git a/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/utils/accessTokenRefresh.kt b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/utils/accessTokenRefresh.kt new file mode 100644 index 0000000..c8eb9ac --- /dev/null +++ b/chatbot/src/main/kotlin/space/mori/chzzk_bot/chatbot/utils/accessTokenRefresh.kt @@ -0,0 +1,55 @@ +package space.mori.chzzk_bot.chatbot.utils + +import com.google.gson.Gson +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import space.mori.chzzk_bot.common.utils.client +import xyz.r2turntrue.chzzk4j.ChzzkClient +import java.io.IOException + +val client = OkHttpClient.Builder() + .addNetworkInterceptor { chain -> + chain.proceed( + chain.request() + .newBuilder() + .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36") + .build() + ) + } + .build() +val gson = Gson() + +data class RefreshTokenResponse( + val accessToken: String, + val refreshToken: String, + val expiresIn: Int, + val tokenType: String = "Bearer", + val scope: String +) + +fun ChzzkClient.refreshAccessToken(refreshToken: String): Pair { + val url = "https://openapi.chzzk.naver.com/auth/v1/token" + val request = Request.Builder() + .url(url) + .header("Content-Type", "application/json") + .post(gson.toJson(mapOf( + "grantType" to "refresh_token", + "refreshToken" to refreshToken, + "clientId" to this.apiClientId, + "clientSecret" to this.apiSecret + )).toRequestBody()) + .build() + + client.newCall(request).execute().use { response -> + try { + if(!response.isSuccessful) throw IOException("Unexpected code ${response.code}") + val body = response.body?.string() + val data = gson.fromJson(body, RefreshTokenResponse::class.java) + + return Pair(data.accessToken, data.refreshToken) + } catch(e: Exception) { + throw e + } + } +} \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 3d9c74f..b8eca0d 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -23,7 +23,7 @@ dependencies { api("com.zaxxer:HikariCP:6.1.0") // https://mvnrepository.com/artifact/ch.qos.logback/logback-classic - implementation("ch.qos.logback:logback-classic:1.5.12") + implementation("ch.qos.logback:logback-classic:1.5.13") // https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client implementation("org.mariadb.jdbc:mariadb-java-client:3.5.0") diff --git a/webserver/build.gradle.kts b/webserver/build.gradle.kts index d73ec32..8867b5f 100644 --- a/webserver/build.gradle.kts +++ b/webserver/build.gradle.kts @@ -10,7 +10,7 @@ repositories { mavenCentral() } -val ktorVersion = "3.0.1" +val ktorVersion = "3.1.3" dependencies { implementation("io.ktor:ktor-server-core:$ktorVersion")