diff --git a/core/src/main/kotlin/me/eternal/purrfectsnap/core/features/impl/global/CompanionServer.kt b/core/src/main/kotlin/me/eternal/purrfectsnap/core/features/impl/global/CompanionServer.kt index 8f8d9877..19c078b9 100644 --- a/core/src/main/kotlin/me/eternal/purrfectsnap/core/features/impl/global/CompanionServer.kt +++ b/core/src/main/kotlin/me/eternal/purrfectsnap/core/features/impl/global/CompanionServer.kt @@ -381,10 +381,57 @@ class CompanionServer : Feature("CompanionServer") { } } } - // If still 0 and response is large enough to contain stories, dump hex for inspection + // Strategy E: europe-west1 format — field3→3 → snap descriptors at field 1 + if (parsed == 0) { + var countE = 0 + ProtoReader(buffer).followPath(3)?.followPath(3)?.eachBuffer(1) { + val userId = getString(4, 1) ?: getString(8, 1) ?: getString(1) ?: fallbackUserId + val url = getString(2, 2)?.substringBefore("?") ?: return@eachBuffer + val postedAt = getVarInt(3) ?: return@eachBuffer + val createdAt = getVarInt(27) ?: -1L + val keyB64 = getString(2, 5) ?: return@eachBuffer + val ivB64 = getString(2, 4) ?: return@eachBuffer + if (storeStory(userId, url, postedAt, createdAt, keyB64, ivB64)) countE++ + } + if (countE > 0) parsed = countE + pushStoryDebug("probe", mapOf("endpoint" to endpoint, "strategy" to "E_f3f3f1", "found" to countE)) + } + // Strategy F: europe-west1 format — field3→3 → snap items at field 3 + if (parsed == 0) { + var countF = 0 + ProtoReader(buffer).followPath(3)?.followPath(3)?.eachBuffer(3) { + val userId = getString(4, 1) ?: getString(8, 1) ?: fallbackUserId + val url = getString(2, 2)?.substringBefore("?") ?: return@eachBuffer + val postedAt = getVarInt(3) ?: return@eachBuffer + val createdAt = getVarInt(27) ?: -1L + val keyB64 = getString(2, 5) ?: return@eachBuffer + val ivB64 = getString(2, 4) ?: return@eachBuffer + if (storeStory(userId, url, postedAt, createdAt, keyB64, ivB64)) countF++ + } + if (countF > 0) parsed = countF + pushStoryDebug("probe", mapOf("endpoint" to endpoint, "strategy" to "F_f3f3f3", "found" to countF)) + } + // If still 0, dump hex + first snap descriptor bytes for structure analysis if (parsed == 0 && buffer.size > 1000) { val hexPreview = buffer.take(128).joinToString(" ") { "%02x".format(it) } - pushStoryDebug("no_match", mapOf("endpoint" to endpoint, "hex_preview" to hexPreview, "bytes" to buffer.size)) + val debugMap = mutableMapOf( + "endpoint" to endpoint, + "hex_preview" to hexPreview, + "bytes" to buffer.size + ) + runCatching { + ProtoReader(buffer).followPath(3, 3)?.let { storyList -> + storyList.getByteArray(1)?.let { bytes -> + debugMap["f3f3f1_size"] = bytes.size + debugMap["f3f3f1_hex"] = bytes.take(256).joinToString(" ") { "%02x".format(it) } + } + storyList.getByteArray(3)?.let { bytes -> + debugMap["f3f3f3_size"] = bytes.size + debugMap["f3f3f3_hex"] = bytes.take(256).joinToString(" ") { "%02x".format(it) } + } + } + } + pushStoryDebug("no_match", debugMap) context.log.warn("CompanionServer: [$endpoint] ${buffer.size}B parsed 0 — hex: $hexPreview", "CompanionServer") } }