diff --git a/Dockerfile b/Dockerfile index a7077d6..2d9f384 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM openjdk:21-bullseye RUN apt update -y && apt install ffmpeg -y -ADD tgbot-1.0-SNAPSHOT.jar /opt/kuku/tgbot-1.0-SNAPSHOT.jar +ADD tgbot.jar /opt/kuku/tgbot.jar ADD application.yml /opt/kuku/application.yml ADD docker-entrypoint.sh /opt/kuku/docker-entrypoint.sh WORKDIR /opt/kuku diff --git a/build.gradle.kts b/build.gradle.kts index 7b19dc3..ba08dbe 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,12 +1,11 @@ @file:Suppress("VulnerableLibrariesLocal") plugins { - val kotlinVersion = "2.0.0" + val kotlinVersion = "2.0.20" kotlin("jvm") version kotlinVersion kotlin("plugin.spring") version kotlinVersion - id("org.springframework.boot") version "3.3.1" - id("io.spring.dependency-management") version "1.1.5" - application + id("org.springframework.boot") version "3.3.3" + id("io.spring.dependency-management") version "1.1.6" } group = "me.kuku" @@ -23,11 +22,11 @@ dependencies { implementation("io.projectreactor.kotlin:reactor-kotlin-extensions") implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive") implementation("org.springframework.boot:spring-boot-starter-mail") - implementation("com.github.pengrad:java-telegram-bot-api:7.7.0") - implementation("me.kuku:utils:2.3.12.0") + implementation("com.github.pengrad:java-telegram-bot-api:7.9.0") + implementation("me.kuku:utils:2.3.12.1") implementation("me.kuku:ktor-spring-boot-starter:2.3.12.0") implementation("org.jsoup:jsoup:1.17.2") - val ociVersion = "3.44.1" + val ociVersion = "3.44.4" implementation("com.oracle.oci.sdk:oci-java-sdk-core:$ociVersion") implementation("com.oracle.oci.sdk:oci-java-sdk-identity:$ociVersion") implementation("com.oracle.oci.sdk:oci-java-sdk-common-httpclient-jersey3:$ociVersion") { @@ -62,6 +61,6 @@ tasks.test { useJUnitPlatform() } -application { - mainClass = "me.kuku.telegram.TelegramApplicationKt" -} \ No newline at end of file +tasks.bootJar { + archiveFileName.set("tgbot.jar") +} diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index c18ea17..69bcf84 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,7 +1,7 @@ #!/bin/bash -jar_name=tgbot-1.0-SNAPSHOT.jar -jar_new_name=tgbot-1.0-SNAPSHOT-new.jar +jar_name=tgbot.jar +jar_new_name=tgbot-new.jar rm -f update.pid java -Dspring.profiles.active=prod -Duser.timezone=Asia/Shanghai -jar $jar_name & diff --git a/run.sh b/run.sh index a824475..d05bf9f 100644 --- a/run.sh +++ b/run.sh @@ -4,8 +4,8 @@ JAVA_HOME=~/jdk/jdk-21+35 java=$JAVA_HOME/bin/java -jar_name=tgbot-1.0-SNAPSHOT.jar -jar_new_name=tgbot-1.0-SNAPSHOT-new.jar +jar_name=tgbot.jar +jar_new_name=tgbot-new.jar rm -f update.pid "${java}" -Dspring.profiles.active=prod -jar $jar_name & diff --git a/src/main/kotlin/me/kuku/telegram/entity/MiHoYoEntity.kt b/src/main/kotlin/me/kuku/telegram/entity/MiHoYoEntity.kt index d1c7df8..094919b 100644 --- a/src/main/kotlin/me/kuku/telegram/entity/MiHoYoEntity.kt +++ b/src/main/kotlin/me/kuku/telegram/entity/MiHoYoEntity.kt @@ -23,8 +23,8 @@ class MiHoYoEntity: BaseEntity() { var mysSign: Status = Status.OFF fun hubCookie(): String { - if (sToken.isEmpty()) error("未设置sToken,请使用账号密码重新登录") - return "stuid=$aid; stoken=$sToken; " + if (token.isEmpty()) error("未设置token,请使用app账号密码重新登录") + return "stuid=$aid; stoken=$token; mid=$mid; " } } diff --git a/src/main/kotlin/me/kuku/telegram/entity/NetEaseEntity.kt b/src/main/kotlin/me/kuku/telegram/entity/NetEaseEntity.kt index afafb51..8990a06 100644 --- a/src/main/kotlin/me/kuku/telegram/entity/NetEaseEntity.kt +++ b/src/main/kotlin/me/kuku/telegram/entity/NetEaseEntity.kt @@ -16,6 +16,7 @@ class NetEaseEntity: BaseEntity() { var sign: Status = Status.OFF var musicianSign: Status = Status.OFF var vipSign: Status = Status.OFF + var listen: Status = Status.OFF fun cookie() = "channel=netease; __remember_me=true; MUSIC_U=$musicU; __csrf=$csrf; " @@ -36,6 +37,8 @@ interface NetEaseRepository: CoroutineCrudRepository { suspend fun findByVipSign(status: Status): List + suspend fun findByListen(listen: Status): List + } @Service @@ -58,4 +61,6 @@ class NetEaseService( suspend fun findByVipSign(status: Status) = netEaseRepository.findByVipSign(status) + suspend fun findByListen(listen: Status) = netEaseRepository.findByListen(listen) + } diff --git a/src/main/kotlin/me/kuku/telegram/entity/NetEaseSmallEntity.kt b/src/main/kotlin/me/kuku/telegram/entity/NetEaseSmallEntity.kt new file mode 100644 index 0000000..11e6787 --- /dev/null +++ b/src/main/kotlin/me/kuku/telegram/entity/NetEaseSmallEntity.kt @@ -0,0 +1,36 @@ +package me.kuku.telegram.entity + +import kotlinx.coroutines.flow.toList +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.mapping.Document +import org.springframework.data.repository.kotlin.CoroutineCrudRepository +import org.springframework.stereotype.Service + +@Document("net_ease_small") +class NetEaseSmallEntity { + @Id + var id: String? = null + var username: String = "" + var password: String = "" + var musicU: String = "" + var csrf: String = "" + + fun cookie() = "channel=netease; __remember_me=true; MUSIC_U=$musicU; __csrf=$csrf; " +} + +interface NetEaseSmallRepository: CoroutineCrudRepository { + suspend fun findByUsername(username: String): NetEaseSmallEntity? +} + +@Service +class NetEaseSmallService( + private val netEaseSmallRepository: NetEaseSmallRepository +) { + suspend fun save(netEaseSmallEntity: NetEaseSmallEntity): NetEaseSmallEntity = netEaseSmallRepository.save(netEaseSmallEntity) + + suspend fun findByUsername(username: String): NetEaseSmallEntity? = netEaseSmallRepository.findByUsername(username) + + suspend fun findAll(): List = netEaseSmallRepository.findAll().toList() + + suspend fun delete(entity: NetEaseSmallEntity) = netEaseSmallRepository.delete(entity) +} \ No newline at end of file diff --git a/src/main/kotlin/me/kuku/telegram/extension/ExecExtension.kt b/src/main/kotlin/me/kuku/telegram/extension/ExecExtension.kt index dbb7509..ec9ccc9 100644 --- a/src/main/kotlin/me/kuku/telegram/extension/ExecExtension.kt +++ b/src/main/kotlin/me/kuku/telegram/extension/ExecExtension.kt @@ -164,7 +164,7 @@ class ExecExtension( val markup = InlineKeyboardMarkup(arrayOf(genShinSignButton), arrayOf(mysSign)) editMessageText(""" 米哈游 - 注意:签到大概率需要在/config配置rrcor的key + 注意:签到大概率需要在/config配置2captcha的key """.trimIndent(), markup) } callback("genShinSign") { diff --git a/src/main/kotlin/me/kuku/telegram/extension/LoginExtension.kt b/src/main/kotlin/me/kuku/telegram/extension/LoginExtension.kt index 48e6a20..c273abd 100644 --- a/src/main/kotlin/me/kuku/telegram/extension/LoginExtension.kt +++ b/src/main/kotlin/me/kuku/telegram/extension/LoginExtension.kt @@ -640,7 +640,7 @@ class LoginExtension( arrayOf(appQrcodeButton), arrayOf(cookieButton) ) - editMessageText("请选择什么值得买登录方式\n注意:因为什么值得买部分有极验验证码,所以你可能需要在/config中设配置rrocr密钥", markup) + editMessageText("请选择什么值得买登录方式\n注意:因为什么值得买部分有极验验证码,所以你可能需要在/config中设配置2captcha密钥", markup) } callback("smZdmLoginByPhoneCode") { editMessageText("请发送什么值得买的手机号码") diff --git a/src/main/kotlin/me/kuku/telegram/extension/ManagerExtension.kt b/src/main/kotlin/me/kuku/telegram/extension/ManagerExtension.kt index fd5ceda..d3f1a1e 100644 --- a/src/main/kotlin/me/kuku/telegram/extension/ManagerExtension.kt +++ b/src/main/kotlin/me/kuku/telegram/extension/ManagerExtension.kt @@ -227,7 +227,7 @@ class ManagerExtension( ) editMessageText(""" 米哈游签到管理 - 注意:签到大概率需要在/config配置rrcor的key + 注意:签到大概率需要在/config配置2captcha的key """.trimIndent(), inlineKeyboardMarkup, top = true) } } @@ -238,6 +238,7 @@ class ManagerExtension( callback("netEaseSignSwitch") { firstArg().also { it.sign = !it.sign } } callback("netEaseMusicianSignSwitch") { firstArg().also { it.musicianSign = !it.musicianSign } } callback("netEaseVipSignSwitch") { firstArg().also { it.vipSign = !it.vipSign } } + callback("netEaseListenSwitch") { firstArg().also { it.listen = !it.listen } } after { val netEaseEntity = firstArg() netEaseService.save(netEaseEntity) @@ -245,11 +246,13 @@ class ManagerExtension( .callbackData("netEaseSignSwitch") val musicianSignButton = InlineKeyboardButton("${netEaseEntity.musicianSign}音乐人自动签到") .callbackData("netEaseMusicianSignSwitch") - val vipSign = inlineKeyboardButton("vip自动签到", "netEaseVipSignSwitch") + val vipSign = inlineKeyboardButton("${netEaseEntity.vipSign}vip自动签到", "netEaseVipSignSwitch") + val listen = inlineKeyboardButton("${netEaseEntity.listen}刷歌曲播放", "netEaseListenSwitch") val inlineKeyboardMarkup = InlineKeyboardMarkup( arrayOf(signButton), arrayOf(musicianSignButton), - arrayOf(vipSign) + arrayOf(vipSign), + arrayOf(listen) ) editMessageText(""" 网易云签到管理 diff --git a/src/main/kotlin/me/kuku/telegram/extension/NetEaseSmallExtension.kt b/src/main/kotlin/me/kuku/telegram/extension/NetEaseSmallExtension.kt new file mode 100644 index 0000000..9dca164 --- /dev/null +++ b/src/main/kotlin/me/kuku/telegram/extension/NetEaseSmallExtension.kt @@ -0,0 +1,37 @@ +package me.kuku.telegram.extension + +import me.kuku.telegram.context.AbilitySubscriber +import me.kuku.telegram.context.nextMessage +import me.kuku.telegram.entity.NetEaseSmallEntity +import me.kuku.telegram.entity.NetEaseSmallService +import org.springframework.stereotype.Service + +@Service +class NetEaseSmallExtension( + private val netEaseSmallService: NetEaseSmallService +) { + + fun AbilitySubscriber.netEaseSmall() { + sub(name = "netEaseSmall") { + sendMessage(""" + 请发送网易云小号,格式为:用户名----密码,一行一个 + """.trimIndent()) + val text = nextMessage().text() + val firstArr = text.split("\n") + for (line in firstArr) { + val lineSplit = line.split("----") + val username = lineSplit[0] + var password = lineSplit[1] + password.indexOf('-').takeIf { it > 0 }?.let { + password = password.substring(0, it) + } + val netEaseSmallEntity = netEaseSmallService.findByUsername(username) ?: NetEaseSmallEntity() + netEaseSmallEntity.username = username + netEaseSmallEntity.password = password + netEaseSmallService.save(netEaseSmallEntity) + } + sendMessage("保存网易云小号成功") + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/me/kuku/telegram/extension/UpdateExtension.kt b/src/main/kotlin/me/kuku/telegram/extension/UpdateExtension.kt index c5b6a27..abc3860 100644 --- a/src/main/kotlin/me/kuku/telegram/extension/UpdateExtension.kt +++ b/src/main/kotlin/me/kuku/telegram/extension/UpdateExtension.kt @@ -44,12 +44,12 @@ class UpdateExtension { mutex.withLock { editMessageText("下载指定jar中") val suffix = query.data().split("|")[1] - val find = listFile("/tgbot/$suffix").find { it.name == "tgbot-1.0-SNAPSHOT.jar" } ?: error("未找到该目录下的文件") - val url = "https://pan.kuku.me/d/tgbot/$suffix/tgbot-1.0-SNAPSHOT.jar?sign=${find.sign}" + val find = listFile("/tgbot/$suffix").find { it.name == "tgbot.jar" } ?: error("未找到该目录下的文件") + val url = "https://pan.kuku.me/d/tgbot/$suffix/tgbot.jar?sign=${find.sign}" val str = client.get(url).bodyAsText() val newUrl = Jsoup.parse(str).getElementsByTag("a").first()?.attr("href") ?: error("未获取到文件链接") val iis = client.get(newUrl).body() - iis.transferTo(FileOutputStream("tmp${java.io.File.separator}tgbot-1.0-SNAPSHOT-new.jar")) + iis.transferTo(FileOutputStream("tmp${java.io.File.separator}tgbot-new.jar")) "kuku".toByteArray().inputStream().transferTo(FileOutputStream("update.pid")) editMessageText(""" 下载完成,更新中... diff --git a/src/main/kotlin/me/kuku/telegram/logic/AliDriveLogic.kt b/src/main/kotlin/me/kuku/telegram/logic/AliDriveLogic.kt index 9a8e687..b9c5ab4 100644 --- a/src/main/kotlin/me/kuku/telegram/logic/AliDriveLogic.kt +++ b/src/main/kotlin/me/kuku/telegram/logic/AliDriveLogic.kt @@ -1086,7 +1086,7 @@ class AliDriveLogic( val fileList = fileList(aliDriveEntity, backupDriveId, fileId) val bodies = fileList.items.map { AliDriveBatch.DeleteFileBody(it.driveId.toString(), it.fileId) } batchDeleteFile(aliDriveEntity, bodies) - val bytes = this::class.java.classLoader.getResourceAsStream("video" + File.separator + "BV14s4y1Z7ZAoutput.mp4")!!.readAllBytes() + val bytes = client.get("https://minio.kuku.me/kuku/BV14s4y1Z7ZAoutput.mp4").body() val uploadComplete = uploadFileToBackupDrive( aliDriveEntity, backupDriveId, "BV14s4y1Z7ZAoutput.mp4", bytes, fileId diff --git a/src/main/kotlin/me/kuku/telegram/logic/CaptchaLogic.kt b/src/main/kotlin/me/kuku/telegram/logic/CaptchaLogic.kt index 3766c26..f8e1300 100644 --- a/src/main/kotlin/me/kuku/telegram/logic/CaptchaLogic.kt +++ b/src/main/kotlin/me/kuku/telegram/logic/CaptchaLogic.kt @@ -4,13 +4,13 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.JsonNode import io.ktor.client.call.* import io.ktor.client.request.* -import io.ktor.client.statement.* import kotlinx.coroutines.delay import me.kuku.telegram.config.TelegramConfig import me.kuku.telegram.entity.BotConfigService import me.kuku.telegram.entity.ConfigService +import me.kuku.utils.Jackson import me.kuku.utils.client -import me.kuku.utils.convertValue +import me.kuku.utils.setJsonBody import org.springframework.stereotype.Service @Service @@ -20,44 +20,61 @@ class TwoCaptchaLogic( private val configService: ConfigService ) { - private suspend inline fun captcha(tgId: Long? = null, map: Map): T { + private suspend inline fun captcha(tgId: Long? = null, task: Map): T { val newKey = run { tgId?.let { val configEntity = configService.findByTgId(tgId) configEntity?.twoCaptchaKey() } } ?: botConfigService.findByToken(telegramConfig.token)?.twoCaptchaKey() ?: error("未设置2captcha的key") - val text = client.get("http://2captcha.com/in.php") { - url { - parameters.append("key", newKey) - map.forEach { (k, v) -> parameters.append(k, v) } - } - }.bodyAsText() - val arr = text.split("|") - if (arr[0] != "OK") error("无法识别验证码") - val code = arr[1] + val paramNode = Jackson.createObjectNode() + paramNode.put("clientKey", newKey) + paramNode.putPOJO("task", task) + val jsonNode = client.post("https://api.2captcha.com/createTask") { + setJsonBody(paramNode) + }.body() + if (jsonNode["errorId"].asInt() != 0) error("识别验证码失败:" + jsonNode["errorDescription"].asText()) + val code = jsonNode["taskId"].asLong() var i = 0 while (true) { if (i++ > 35) error("无法识别验证码") delay(2000) - val jsonNode = client.get("http://2captcha.com/res.php?key=$newKey&action=get&json=1&id=$code").body() - if (jsonNode["status"].asInt() == 1) return jsonNode["request"].convertValue() + val resultJsonNode = client.post("https://api.2captcha.com/getTaskResult") { + setJsonBody(""" + { + "clientKey": "$newKey", + "taskId": $code + } + """.trimIndent()) + }.body() + val resultCode = resultJsonNode["errorId"].asInt() + if (resultCode == 0) { + val status = resultJsonNode["status"].asText() + if (status == "processing") continue + else return Jackson.convertValue(resultJsonNode["solution"]) + } else { + error("识别验证码失败:" + resultJsonNode["errorDescription"].asText()) + } } } suspend fun geeTest(gt: String, challenge: String, pageUrl: String, tgId: Long? = null): GeeTest { - return captcha(tgId, mapOf("method" to "geetest", "gt" to gt, "challenge" to challenge, "pageurl" to pageUrl)) + return captcha(tgId, + mapOf("type" to "GeeTestTaskProxyless", "gt" to gt, "challenge" to challenge, "websiteURL" to pageUrl)) } - suspend fun geeTestV4(captchaId: String, pageUrl: String, tgId: Long? = null): GeeTestV4 { - return captcha(tgId, mapOf("method" to "geetest_v4", "id" to captchaId, "pageurl" to pageUrl)) + suspend fun geeTestV4(captchaId: String, pageUrl: String, extraParams: Map = mapOf(), tgId: Long? = null): GeeTestV4 { + return captcha(tgId, + mapOf("type" to "GeeTestTaskProxyless", "captcha_id" to captchaId, "websiteURL" to pageUrl, "version" to 4, + "initParameters" to mutableMapOf("captcha_id" to captchaId).also { it.putAll(extraParams) } + )) } } -data class GeeTest(@JsonProperty("geetest_challenge") val challenge: String, - @JsonProperty("geetest_validate") val validate: String, - @JsonProperty("geetest_seccode") val secCode: String) +data class GeeTest(@JsonProperty("challenge") val challenge: String, + @JsonProperty("validate") val validate: String, + @JsonProperty("seccode") val secCode: String) data class GeeTestV4(@JsonProperty("lot_number") val lotNumber: String, diff --git a/src/main/kotlin/me/kuku/telegram/logic/ECloudLogic.kt b/src/main/kotlin/me/kuku/telegram/logic/ECloudLogic.kt index bfd14dc..63f0abe 100644 --- a/src/main/kotlin/me/kuku/telegram/logic/ECloudLogic.kt +++ b/src/main/kotlin/me/kuku/telegram/logic/ECloudLogic.kt @@ -6,6 +6,7 @@ import io.ktor.client.request.* import io.ktor.client.request.headers import io.ktor.client.statement.* import io.ktor.util.* +import kotlinx.coroutines.delay import me.kuku.telegram.entity.ECloudEntity import me.kuku.telegram.entity.ECloudService import me.kuku.utils.* @@ -17,13 +18,13 @@ class ECloudLogic( ) { suspend fun login(username: String, password: String): ECloudEntity { - val (cookie, lt, reqId, refererUrl) = client.get("https://cloud.189.cn/api/portal/loginUrl.action?redirectURL=https%3A%2F%2Fcloud.189.cn%2Fweb%2Fredirect.html") + val (cookie, lt, reqId, refererUrl) = client.get("https://cloud.189.cn/api/portal/loginUrl.action?redirectURL=https%3A%2F%2Fcloud.189.cn%2Fweb%2Fredirect.html&defaultSaveName=3&defaultSaveNameCheck=uncheck&browserId=c7044c4577d2d903bbb74a956c11274d") .let { val location = it.headers["location"] ?: error("未能成功跳转") client.get(location).let { response -> val ltUrl = response.headers["location"] ?: error("未能成功跳转") val lt = MyUtils.regex("lt=", "&", ltUrl) ?: error("未能成功获取lt") - val reqId = MyUtils.regex("(?<=reqId=).*", ltUrl) ?: error("未能成功获取reqId") + val reqId = MyUtils.regex("reqId=", "&", ltUrl) ?: error("未能成功获取reqId") listOf(response.cookie(), lt, reqId, ltUrl) } } @@ -38,14 +39,16 @@ class ECloudLogic( append("version", "2.0") append("appKey", "cloud") } - headers { appendAll(headers) } + headers { + appendAll(headers) + } }.bodyAsText().toJsonNode() val encryptJsonNode = client.post("https://open.e.189.cn/api/logbox/config/encryptConf.do") { setFormDataContent { append("appId", "cloud") } }.bodyAsText().toJsonNode() - val paramId = configJsonNode["data"]["paramId"].asText() + val paramId = configJsonNode["data"]?.get("paramId")?.asText() ?: error("not found paramId") val encryptData = encryptJsonNode["data"] val pre = encryptData["pre"].asText() val pubKey = encryptData["pubKey"].asText() @@ -95,7 +98,7 @@ class ECloudLogic( } private fun JsonNode.check() { - if (this.has("errorCode")) error(this["errorMsg"].asText()) + if (this.has("errorCode") && this["errorCode"].asText() != "User_Not_Chance") error(this["errorMsg"].asText()) } private suspend fun updateCookie(entity: ECloudEntity) { @@ -130,10 +133,12 @@ class ECloudLogic( headers { appendAll(sv) } }.bodyAsText().toJsonNode() jsonNode1.check() + delay(5000) val jsonNode2 = client.get("https://m.cloud.189.cn/v2/drawPrizeMarketDetails.action?taskId=TASK_SIGNIN_PHOTOS&activityId=ACT_SIGNIN") { headers { appendAll(sv) } }.bodyAsText().toJsonNode() jsonNode2.check() + delay(5000) val jsonNode3 = client.get("https://m.cloud.189.cn/v2/drawPrizeMarketDetails.action?taskId=TASK_2022_FLDFS_KJ&activityId=ACT_SIGNIN") { headers { appendAll(sv) } }.bodyAsText().toJsonNode() diff --git a/src/main/kotlin/me/kuku/telegram/logic/MiHoYoLogic.kt b/src/main/kotlin/me/kuku/telegram/logic/MiHoYoLogic.kt index 177b056..bc87a4e 100644 --- a/src/main/kotlin/me/kuku/telegram/logic/MiHoYoLogic.kt +++ b/src/main/kotlin/me/kuku/telegram/logic/MiHoYoLogic.kt @@ -136,6 +136,8 @@ class MiHoYoLogic( val userInfo = data["user_info"] entity.aid = userInfo["aid"].asText() entity.mid = userInfo["mid"].asText() + val token = OkUtils.cookie(cookie, "cookie_token_v2") ?: "" + entity.token = token CommonResult.success(entity) } else -> error("米游社登陆失败,未知的状态:$status") @@ -211,43 +213,44 @@ class MiHoYoLogic( } suspend fun webLogin(account: String, password: String, tgId: Long? = null): MiHoYoEntity { - val beforeJsonNode = OkHttpKtUtils.getJson("https://webapi.account.mihoyo.com/Api/create_mmt?scene_type=1&now=${System.currentTimeMillis()}&reason=bbs.mihoyo.com") - val dataJsonNode = beforeJsonNode["data"]["mmt_data"] - val challenge = dataJsonNode.getString("challenge") - val gt = dataJsonNode.getString("gt") - val mmtKey = dataJsonNode.getString("mmt_key") - val rr = twoCaptchaLogic.geeTest(gt, challenge,"https://bbs.mihoyo.com/ys/", tgId = tgId) - val cha = rr.challenge - val validate = rr.validate + val fix = MiHoYoFix() val rsaKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDvekdPMHN3AYhm/vktJT+YJr7cI5DcsNKqdsx5DZX0gDuWFuIjzdwButrIYPNmRJ1G8ybDIF7oDW2eEpm5sMbL9zs9ExXCdvqrn51qELbqj0XxtMTIpaCHFSI50PfPpTFV9Xt/hmyVwokoOXFlAEgCn+QCgGs52bFoYMtyi+xEQIDAQAB" - val enPassword = password.rsaEncrypt(rsaKey) - val map = mapOf("is_bh2" to "false", "account" to account, "password" to enPassword, - "mmt_key" to mmtKey, "is_crypto" to "true", "geetest_challenge" to cha, "geetest_validate" to validate, - "geetest_seccode" to "${validate}|jordan") - val response = OkHttpKtUtils.post("https://webapi.account.mihoyo.com/Api/login_by_password", map, OkUtils.ua(UA.PC)) - val loginJsonNode = OkUtils.json(response) - val infoDataJsonNode = loginJsonNode["data"] - if (infoDataJsonNode.getInteger("status") != 1) error(infoDataJsonNode.getString("msg")) - var cookie = OkUtils.cookie(response) - val infoJsonNode = infoDataJsonNode["account_info"] - val accountId = infoJsonNode.getString("account_id") - val ticket = infoJsonNode.getString("weblogin_token") - val cookieJsonNode = OkHttpKtUtils.getJson("https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket=$ticket&t=${System.currentTimeMillis()}", - OkUtils.headers(cookie, "", UA.PC)) - val cookieToken = cookieJsonNode["data"]["cookie_info"]["cookie_token"].asText() - cookie += "cookie_token=$cookieToken; account_id=$accountId; " + var response = client.post("https://passport-api.miyoushe.com/account/ma-cn-passport/web/loginByPassword") { + setJsonBody("""{"account":"${account.rsaEncrypt(rsaKey)}","password":"${password.rsaEncrypt(rsaKey)}"}""") + fix.loginHeader() + } + var cookie = response.cookie() + var loginJsonNode = response.body() + val code = loginJsonNode["retcode"].asInt() + if (code == -3101) { + val captchaJsonNode = response.headers["X-Rpc-Aigis"]!!.toJsonNode() + val sessionId = captchaJsonNode["session_id"].asText() + val captchaDataJsonNode = captchaJsonNode["data"].asText().toJsonNode() + val captchaId = captchaDataJsonNode["gt"].asText() + val riskType = captchaDataJsonNode["risk_type"].asText() + twoCaptchaLogic.geeTestV4(captchaId, "https://user.mihoyo.com/", + mapOf("captcha_id" to captchaId, "session_id" to sessionId, "risk_type" to riskType), tgId) + response = client.post("https://passport-api.miyoushe.com/account/ma-cn-passport/web/loginByPassword") { + setJsonBody("""{"account":"${account.rsaEncrypt(rsaKey)}","password":"${password.rsaEncrypt(rsaKey)}"}""") + fix.loginHeader() + } + cookie = response.cookie() + loginJsonNode = response.body() + } + if (loginJsonNode["retcode"].asInt() != 0) error(loginJsonNode["message"].asText()) + val infoDataJsonNode = loginJsonNode["data"]["user_info"] + val aid = infoDataJsonNode["aid"].asText() + val mid = infoDataJsonNode["mid"].asText() val loginResponse = OkHttpKtUtils.post("https://bbs-api.mihoyo.com/user/wapi/login", OkUtils.json("{\"gids\":\"2\"}"), OkUtils.cookie(cookie)).also { it.close() } val finaCookie = OkUtils.cookie(loginResponse) cookie += finaCookie - cookie += "login_ticket=$ticket; " val entity = MiHoYoEntity().also { it.cookie = cookie - it.aid = accountId - it.ticket = ticket + it.aid = aid + it.mid = mid + it.token = "" } - val sToken = sToken(entity) - entity.sToken = sToken return entity } @@ -256,6 +259,8 @@ class MiHoYoLogic( val fix = this@MiHoYoFix headers { referer("https://user.mihoyo.com/") + origin("https://user.mihoyo.com") + append("x-rpc-app_id", fix.app) append("X-Rpc-Client_type", "4") append("X-Rpc-Device_fp", fix.fp) append("X-Rpc-Device_id", fix.device) @@ -269,47 +274,6 @@ class MiHoYoLogic( } } - suspend fun webNewLogin(account: String, password: String, tgId: Long? = null): MiHoYoEntity { - val fix = MiHoYoFix() - val beforeJsonNode = client.get("https://webapi.account.mihoyo.com/Api/create_mmt?scene_type=1&now=${System.currentTimeMillis()}&reason=user.mihoyo.com%23%2Flogin%2Fpassword&action_type=login_by_password&account=$account&t=${System.currentTimeMillis()}") { - fix.loginHeader() - }.body() - val dataJsonNode = beforeJsonNode["data"]["mmt_data"] - val mmtKey = dataJsonNode.getString("mmt_key") - val rr = twoCaptchaLogic.geeTestV4(mmtKey, "https://user.mihoyo.com/", tgId = tgId) - val rsaKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDvekdPMHN3AYhm/vktJT+YJr7cI5DcsNKqdsx5DZX0gDuWFuIjzdwButrIYPNmRJ1G8ybDIF7oDW2eEpm5sMbL9zs9ExXCdvqrn51qELbqj0XxtMTIpaCHFSI50PfPpTFV9Xt/hmyVwokoOXFlAEgCn+QCgGs52bFoYMtyi+xEQIDAQAB" - val enPassword = password.rsaEncrypt(rsaKey) - val data = Jackson.toJsonString(rr) - val response = client.post("https://webapi.account.mihoyo.com/Api/login_by_password") { - setFormDataContent { - append("account", account) - append("password", enPassword) - append("is_crypto", "true") - append("mmt_key", mmtKey) - append("geetest_v4_data", data) - append("source", "user.mihoyo.com") - append("t", System.currentTimeMillis().toString()) - } - fix.loginHeader() - } - val loginJsonNode = response.body() - if (loginJsonNode["data"]["status"].asInt() != 1) error(loginJsonNode["data"]["msg"].asText()) - val infoDataJsonNode = loginJsonNode["data"] - val cookie = response.cookie() - val infoJsonNode = infoDataJsonNode["account_info"] - val accountId = infoJsonNode.getString("account_id") - val ticket = infoJsonNode.getString("weblogin_token") - val cookieResponse = client.get("https://api-takumi.mihoyo.com/account/auth/api/getAccountInfoByLoginTicket") { - cookieString(cookie) - } - val accountCookie = cookieResponse.cookie() - return MiHoYoEntity().also { - it.ticket = ticket - it.aid = accountId - it.cookie = cookie + accountCookie - } - } - private fun webDs(): MiHoYoDs { val salt = "mx1x4xCahVMVUDJIkJ9H3jsHcUsiASGZ" val time = System.currentTimeMillis() / 1000 @@ -450,7 +414,7 @@ class MiHoYoLogic( val data = jsonNode["data"] val challenge = data["challenge"].asText() val gt = data["gt"].asText() - val rr = twoCaptchaLogic.geeTest(gt, "https://bbs.mihoyo.com", challenge, tgId = miHoYoEntity.tgId) + val rr = twoCaptchaLogic.geeTest(gt, challenge, "https://bbs.mihoyo.com", tgId = miHoYoEntity.tgId) val verifyJsonNode = client.post("https://bbs-api.miyoushe.com/misc/api/verifyVerification") { miHoYoEntity.fix.hubNewAppend() cookieString(miHoYoEntity.hubCookie()) @@ -483,7 +447,7 @@ class MiHoYoLogic( } } - private suspend fun sToken(miHoYoEntity: MiHoYoEntity): String { + suspend fun sToken(miHoYoEntity: MiHoYoEntity): String { val ticket = miHoYoEntity.ticket.ifEmpty { error("请重新使用账号或密码登陆") } val accountId = miHoYoEntity.aid.ifEmpty { error("请重新使用账号或密码登陆") } val jsonNode = client.get("https://api-takumi.mihoyo.com/auth/api/getMultiTokenByLoginTicket?login_ticket=$ticket&token_types=3&uid=$accountId") diff --git a/src/main/kotlin/me/kuku/telegram/logic/NetEaseLogic.kt b/src/main/kotlin/me/kuku/telegram/logic/NetEaseLogic.kt index e503478..04233a8 100644 --- a/src/main/kotlin/me/kuku/telegram/logic/NetEaseLogic.kt +++ b/src/main/kotlin/me/kuku/telegram/logic/NetEaseLogic.kt @@ -10,6 +10,7 @@ import me.kuku.pojo.CommonResult import me.kuku.pojo.UA import me.kuku.telegram.config.api import me.kuku.telegram.entity.NetEaseEntity +import me.kuku.telegram.entity.NetEaseSmallEntity import me.kuku.utils.* import okhttp3.internal.toHexString @@ -141,6 +142,7 @@ object NetEaseLogic { return jsonNode["playlist"]["trackIds"] } + @Suppress("DuplicatedCode") suspend fun listenMusic(netEaseEntity: NetEaseEntity) { val playList = recommend(netEaseEntity) val ids = Jackson.createArrayNode() @@ -168,6 +170,26 @@ object NetEaseLogic { if (jsonNode.getInteger("code") != 200) error(jsonNode.getString("message")) } + @Suppress("DuplicatedCode") + suspend fun listenMusic(netEaseSmallEntity: NetEaseSmallEntity, id: Int) { + val ids = Jackson.createArrayNode() + val jsonNode = Jackson.createObjectNode() + jsonNode.put("download", 0) + jsonNode.put("end", "playend") + jsonNode.put("id", id) + jsonNode.put("sourceId", "") + jsonNode.put("time", 240) + jsonNode.put("type", "song") + jsonNode.put("wifi", "0") + val totalJsonNode = Jackson.createObjectNode() + totalJsonNode.set("json", jsonNode) + totalJsonNode.put("action", "play") + ids.add(totalJsonNode) + val resultJsonNode = OkHttpKtUtils.postJson("$domain/weapi/feedback/weblog", prepare(mapOf("logs" to ids.toString())), + OkUtils.headers(netEaseSmallEntity.cookie(), domain, UA.PC)) + if (resultJsonNode.getInteger("code") != 200) error(resultJsonNode.getString("message")) + } + private suspend fun musicianStageMission(netEaseEntity: NetEaseEntity): MutableList { val jsonNode = OkHttpKtUtils.postJson("$domain/weapi/nmusician/workbench/mission/stage/list", prepare(mapOf()), OkUtils.headers(netEaseEntity.cookie(), domain, UA.PC)) @@ -224,7 +246,7 @@ object NetEaseLogic { error("没有找到音乐人签到任务") } - private suspend fun myMusic(netEaseEntity: NetEaseEntity): List { + suspend fun myMusic(netEaseEntity: NetEaseEntity): List { val jsonNode = OkHttpKtUtils.postJson("$domain/weapi/nmusician/production/common/artist/song/item/list/get?csrf_token=${netEaseEntity.csrf}", prepare(mapOf("fromBackend" to "0", "limit" to "10", "offset" to "0", "online" to "1")), mapOf("user-agent" to UA.PC.value, "cookie" to netEaseEntity.cookie(), "referer" to "https://music.163.com/nmusician/web/albums/work/actor/song/self/pub")) @@ -478,8 +500,8 @@ object NetEaseLogic { removeDy(netEaseEntity, commentId) delay(5000) finishStageMission(netEaseEntity, "发布动态") - finishCycleMission(netEaseEntity, "在动态分享歌曲") - finishCycleMission(netEaseEntity, "在自己动态下发布评论") +// finishCycleMission(netEaseEntity, "在动态分享歌曲") +// finishCycleMission(netEaseEntity, "在自己动态下发布评论") } } diff --git a/src/main/kotlin/me/kuku/telegram/logic/NetEaseSmallLogic.kt b/src/main/kotlin/me/kuku/telegram/logic/NetEaseSmallLogic.kt new file mode 100644 index 0000000..055f1ba --- /dev/null +++ b/src/main/kotlin/me/kuku/telegram/logic/NetEaseSmallLogic.kt @@ -0,0 +1,41 @@ +package me.kuku.telegram.logic + +import kotlinx.coroutines.delay +import me.kuku.telegram.entity.NetEaseSmallService +import org.springframework.stereotype.Service + +@Service +class NetEaseSmallLogic( + private val netEaseSmallService: NetEaseSmallService +) { + + suspend fun check() { + val list = netEaseSmallService.findAll() + for (netEaseSmallEntity in list) { + if (netEaseSmallEntity.csrf.isEmpty()) { + val loginResult = NetEaseLogic.login(netEaseSmallEntity.username, netEaseSmallEntity.password) + delay(1000) + if (loginResult.success()) { + val newEntity = loginResult.data() + netEaseSmallEntity.csrf = newEntity.csrf + netEaseSmallEntity.musicU = newEntity.musicU + netEaseSmallService.save(netEaseSmallEntity) + } else { + netEaseSmallService.delete(netEaseSmallEntity) + } + } + } + } + + suspend fun listenMusic(id: Int) { + val list = netEaseSmallService.findAll() + for (netEaseSmallEntity in list) { + if (netEaseSmallEntity.csrf.isNotEmpty()) { + NetEaseLogic.listenMusic(netEaseSmallEntity, id) + delay(2000) + } + } + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/me/kuku/telegram/scheduled/KuGouScheduled.kt b/src/main/kotlin/me/kuku/telegram/scheduled/KuGouScheduled.kt index d89d736..aca359e 100644 --- a/src/main/kotlin/me/kuku/telegram/scheduled/KuGouScheduled.kt +++ b/src/main/kotlin/me/kuku/telegram/scheduled/KuGouScheduled.kt @@ -18,7 +18,7 @@ class KuGouScheduled( val list = kuGouService.findBySign(Status.ON) for (kuGouEntity in list) { logService.log(kuGouEntity, LogType.KuGou) { - kuGouLogic.musicianSign(kuGouEntity) +// kuGouLogic.musicianSign(kuGouEntity) kuGouLogic.listenMusic(kuGouEntity) repeat(8) { delay(1000 * 25) diff --git a/src/main/kotlin/me/kuku/telegram/scheduled/NetEaseSmallScheduled.kt b/src/main/kotlin/me/kuku/telegram/scheduled/NetEaseSmallScheduled.kt new file mode 100644 index 0000000..c6b60a5 --- /dev/null +++ b/src/main/kotlin/me/kuku/telegram/scheduled/NetEaseSmallScheduled.kt @@ -0,0 +1,31 @@ +package me.kuku.telegram.scheduled + +import kotlinx.coroutines.delay +import me.kuku.telegram.entity.NetEaseService +import me.kuku.telegram.entity.Status +import me.kuku.telegram.logic.NetEaseLogic +import me.kuku.telegram.logic.NetEaseSmallLogic +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Component +import java.util.concurrent.TimeUnit + +@Component +class NetEaseSmallScheduled( + private val netEaseSmallLogic: NetEaseSmallLogic, + private val netEaseService: NetEaseService +) { + + @Scheduled(fixedDelay = 12, initialDelay = 1, timeUnit = TimeUnit.HOURS) + suspend fun listenMusic() { + netEaseSmallLogic.check() + val list = netEaseService.findByListen(Status.ON) + for (netEaseEntity in list) { + val myMusicList = NetEaseLogic.myMusic(netEaseEntity) + for (netEaseSong in myMusicList) { + netEaseSmallLogic.listenMusic(netEaseSong.songId.toInt()) + delay(2000) + } + } + } + +} \ No newline at end of file diff --git a/src/main/resources/video/BV14s4y1Z7ZAoutput.mp4 b/src/main/resources/video/BV14s4y1Z7ZAoutput.mp4 deleted file mode 100644 index 1eecb71..0000000 Binary files a/src/main/resources/video/BV14s4y1Z7ZAoutput.mp4 and /dev/null differ