This commit is contained in:
2026-10-29 16:36:43 +08:00
parent 0cf352cabb
commit 2582f9ba3e
11 changed files with 428 additions and 49 deletions
@@ -17,14 +17,16 @@ import kotlin.random.Random
object Uploader {
private const val CHUNK_SIZE = 1024 * 1024
suspend fun tryUpload(result: CaptureResult) {
val entries = UploadStore.load().filter { it.enabled }
suspend fun tryUpload(result: CaptureResult, onlyProfileIds: Set<String>? = null) {
val entries = UploadStore.load()
.filter { it.enabled }
.filter { onlyProfileIds == null || it.profile.id in onlyProfileIds }
if (entries.isEmpty()) return
VpnLog.info("${result.step.name} 开始上传(${entries.size} 个配置,串行)")
for ((_, profile) in entries) {
try {
val uploaded = uploadChunked(profile, result.url, result.file)
val uploaded = uploadChunked(profile, result.url, result.file, result.step.uploadType)
if (uploaded) {
VpnLog.success("[${profile.id}] ${result.step.name} 上传完成")
} else {
@@ -43,18 +45,20 @@ object Uploader {
profile: UploadProfile,
originalUrl: String,
file: File,
type: String? = null,
): Boolean = withContext(Dispatchers.IO) {
require(file.exists()) { "文件不存在: ${file.absolutePath}" }
val type = when (file.name) {
val uploadType = type ?: when (file.name) {
"suite" -> "suite"
"mysekai" -> "mysekai"
"mysekai_birthday" -> "birthday"
else -> {
VpnLog.error("${profile.id} 未知的文件类型 ${file.name}")
return@withContext false
}
else -> null
}
val url = profile.getUploadUrl(type)?.takeIf { it.isNotBlank() }
if (uploadType == null) {
VpnLog.error("${profile.id} 未知的文件类型 ${file.name}")
return@withContext false
}
val url = profile.getUploadUrl(uploadType)?.takeIf { it.isNotBlank() }
?: return@withContext false
val uploadId = randomUploadId()
@@ -160,6 +164,27 @@ enum class UploadProfileType(val displayName: String) {
CUSTOM("自定义")
}
/** mixin:在自定义上传配置里顺带定义抓包配置。 */
data class UploadMixin(
val profiles: List<UploadMixinProfile>,
)
data class UploadMixinProfile(
val name: String,
val steps: List<UploadMixinStep>,
)
/**
* name: 步骤显示名(同一 profile 内同名步骤会合并)
* hosts: 域名列表,可以填 `cn` 这样的预设别名
* target: `suite` / `mysekai` / `birthday` 快捷方式,或直接填请求路径正则
*/
data class UploadMixinStep(
val name: String,
val hosts: List<String>,
val target: String,
)
sealed interface UploadProfile {
val id: String
val type: UploadProfileType
@@ -274,8 +299,12 @@ class UploadProfile8823(override val id: String) : UploadProfile {
override val extraInfo: Map<String, String> = emptyMap()
}
class UploadProfileCustom(override val id: String, val uploadUrl: UploadUrl, val customHeaders: Map<String, String>) :
UploadProfile {
class UploadProfileCustom(
override val id: String,
val uploadUrl: UploadUrl,
val customHeaders: Map<String, String>,
val mixin: UploadMixin? = null,
) : UploadProfile {
override val type: UploadProfileType = UploadProfileType.CUSTOM
override val helpText: String? = null