1.0 能用

This commit is contained in:
2026-10-24 14:48:59 +08:00
commit eea818f5f4
48 changed files with 4802 additions and 0 deletions
@@ -0,0 +1,34 @@
package net.bluemangoo.indpjsk.data
import java.io.File
data class CaptureProfile(
val id: String,
val name: String,
val steps: List<CaptureProfileStep>
)
data class CaptureProfileStep(
val id: String,
val name: String,
/** 该步骤可能命中的上游域名;TW/KR 的 cdn / https 两个域名都会出现 */
val hosts: List<String>,
/** 匹配 path + query 的正则(Rust 侧 Regex::is_match) */
val path: String,
val fileName: String,
/**
* 该步骤抓成功后异步执行(不阻塞下一步的监听)。
* 没有填上传码时会走这里;参数是本次抓包的结果。
*/
val postAction: suspend (CaptureResult) -> Unit = {},
)
/** 一步抓包完成后的结果,交给 postAction 用 */
data class CaptureResult(
val profile: CaptureProfile,
val step: CaptureProfileStep,
/** 命中的原始完整 URL(https://host/path?query,MySekai 的 flag 已改写为 True) */
val url: String,
/** 抓到的响应体文件 */
val file: File,
)
@@ -0,0 +1,76 @@
package net.bluemangoo.indpjsk.data
object PredefinedProfiles {
/**
* 两个数据接口的正则(Host 已去掉,Rust 侧是拿 path + query 去匹配的):
*
* 1. Suite(个人信息 / 卡牌 / 仓库主数据)
* Path 模板: /api/suite/user/{uid}
*
* 2. MySekai(烤森房间 / 地图全量数据)
* Path 模板: /api/user/{uid}/mysekai?isForceAllReloadOnlyMysekai=True
*/
private const val SUITE_PATH = "/api/suite/user/(\\d+)(\\?isLogin=true)?\$"
private const val MYSEKAI_PATH =
"/api/user/(\\d+)/mysekai\\?isForceAllReloadOnlyMysekai=True"
private fun suiteStep(hosts: List<String>) = CaptureProfileStep(
id = "suite",
name = "Suite",
hosts = hosts,
path = SUITE_PATH,
fileName = "suite"
)
private fun mysekaiStep(hosts: List<String>) = CaptureProfileStep(
id = "mysekai",
name = "烤森",
hosts = hosts,
path = MYSEKAI_PATH,
fileName = "mysekai"
)
private val CN_HOSTS = listOf("mkcn-prod-public-60001-1.dailygn.com")
private val JP_HOSTS = listOf("production-game-api.sekai.colorfulpalette.org")
private val EN_HOSTS = listOf("n-production-game-api.sekai-en.com")
private val TW_HOSTS = listOf(
"mk-zian-obt-cdn.bytedgame.com",
"mk-zian-obt-https.bytedgame.com"
)
private val KR_HOSTS = listOf(
"mkkorea-obt-prod01-cdn.bytedgame.com",
"mkkorea-obt-prod01-https.bytedgame.com"
)
val all: List<CaptureProfile> = listOf(
// 国服不需要烤森
CaptureProfile(
id = "cn",
name = "国服",
steps = listOf(suiteStep(CN_HOSTS))
),
CaptureProfile(
id = "jp",
name = "日服",
steps = listOf(suiteStep(JP_HOSTS), mysekaiStep(JP_HOSTS))
),
CaptureProfile(
id = "en",
name = "国际服",
steps = listOf(suiteStep(EN_HOSTS), mysekaiStep(EN_HOSTS))
),
CaptureProfile(
id = "tw",
name = "台服",
steps = listOf(suiteStep(TW_HOSTS), mysekaiStep(TW_HOSTS))
),
CaptureProfile(
id = "kr",
name = "韩服",
steps = listOf(suiteStep(KR_HOSTS), mysekaiStep(KR_HOSTS))
),
)
fun byId(id: String): CaptureProfile? = all.firstOrNull { it.id == id }
}
@@ -0,0 +1,23 @@
package net.bluemangoo.indpjsk.data
import android.content.Context
import androidx.core.content.edit
/** 一些零碎的全局设置,暂时只有上传码 */
object SettingsStore {
private const val PREFS = "settings"
private const val KEY_UPLOAD_CODE = "upload_code"
fun loadUploadCode(context: Context): String =
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
.getString(KEY_UPLOAD_CODE, "")
.orEmpty()
fun saveUploadCode(context: Context, code: String) {
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
.edit {
putString(KEY_UPLOAD_CODE, code)
}
}
}
@@ -0,0 +1,54 @@
package net.bluemangoo.indpjsk.data
import android.content.Context
import org.json.JSONObject
import androidx.core.content.edit
/**
* 每个 profile 下每个步骤「要不要抓」的持久化。
*
* 就一个 JSON 字符串塞进 SharedPreferences,键是 "profileId/stepId",值 Boolean,
* 没存过的默认 true(全抓)。
*/
object StepSelectionStore {
private const val PREFS = "step_selection"
private const val KEY_JSON = "json"
fun key(profileId: String, stepId: String) = "$profileId/$stepId"
fun loadAll(context: Context): MutableMap<String, Boolean> {
val raw = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
.getString(KEY_JSON, null) ?: return mutableMapOf()
return try {
val json = JSONObject(raw)
val out = mutableMapOf<String, Boolean>()
json.keys().forEach { k -> out[k] = json.optBoolean(k, true) }
out
} catch (_: Throwable) {
mutableMapOf()
}
}
fun isEnabled(all: Map<String, Boolean>, profileId: String, stepId: String): Boolean =
all[key(profileId, stepId)] ?: true
fun saveAll(context: Context, all: Map<String, Boolean>) {
val json = JSONObject()
all.forEach { (k, v) -> json.put(k, v) }
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
.edit { putString(KEY_JSON, json.toString()) }
}
fun setEnabled(
context: Context,
profileId: String,
stepId: String,
enabled: Boolean
): MutableMap<String, Boolean> {
val all = loadAll(context)
all[key(profileId, stepId)] = enabled
saveAll(context, all)
return all
}
}