fix: classify selected Discord DMs from desktop cache

This commit is contained in:
Peter Steinberger 2026-05-01 08:32:08 +01:00
parent 0487ccc1e0
commit 41b675d5f4
No known key found for this signature in database
2 changed files with 86 additions and 5 deletions

View File

@ -348,6 +348,7 @@ func collectValue(snap snapshot, channelLookup map[string]store.ChannelRecord, v
switch typed := value.(type) {
case map[string]any:
collectUserLabel(snap, typed)
collectSelectedDirectMessageRoutes(snap, typed)
if channel, ok := parseChannel(typed); ok {
snap.channels[channel.ID] = channel
channelLookup[channel.ID] = channel
@ -380,14 +381,46 @@ func collectChannelRoutes(snap snapshot, data []byte) {
if !looksSnowflake(channelID) {
continue
}
if existing, ok := snap.routes[channelID]; ok && existing != guildID {
snap.routes[channelID] = ""
continue
}
snap.routes[channelID] = guildID
collectChannelRoute(snap, channelID, guildID)
}
}
func collectSelectedDirectMessageRoutes(snap snapshot, raw map[string]any) {
for _, candidate := range selectedChannelRouteCandidates(raw) {
if selected, _ := candidate["selectedChannelIds"].(map[string]any); selected != nil {
if channelID := stringField(selected, "null"); looksSnowflake(channelID) {
collectChannelRoute(snap, channelID, DirectMessageGuildID)
}
}
if guildValue, hasGuild := candidate["selectedGuildId"]; hasGuild && guildValue == nil {
if channelID := stringField(candidate, "selectedChannelId"); looksSnowflake(channelID) {
collectChannelRoute(snap, channelID, DirectMessageGuildID)
}
}
}
}
func selectedChannelRouteCandidates(raw map[string]any) []map[string]any {
candidates := []map[string]any{raw}
for _, key := range []string{"_state", "state"} {
if child, _ := raw[key].(map[string]any); child != nil {
candidates = append(candidates, child)
}
}
return candidates
}
func collectChannelRoute(snap snapshot, channelID, guildID string) {
if !looksSnowflake(channelID) || guildID == "" {
return
}
if existing, ok := snap.routes[channelID]; ok && existing != guildID {
snap.routes[channelID] = ""
return
}
snap.routes[channelID] = guildID
}
func parseChannel(raw map[string]any) (store.ChannelRecord, bool) {
id := stringField(raw, "id")
if !looksSnowflake(id) {

View File

@ -228,6 +228,54 @@ func TestImportExtractsCompressedUnknownMessageArrayFromChromiumCache(t *testing
require.Empty(t, results)
}
func TestImportClassifiesCachedAPIMessageArrayFromSelectedDMRoute(t *testing.T) {
ctx := context.Background()
dir := t.TempDir()
cachePath := filepath.Join(dir, "Cache", "Cache_Data")
storagePath := filepath.Join(dir, "Local Storage", "leveldb")
require.NoError(t, os.MkdirAll(cachePath, 0o755))
require.NoError(t, os.MkdirAll(storagePath, 0o755))
require.NoError(t, os.WriteFile(filepath.Join(storagePath, "000001.log"), []byte(`noise
{"_state":{"selectedGuildId":null,"selectedChannelId":"1459084628458471569","selectedChannelIds":{"null":"1459084628458471569"}}}
`), 0o600))
messages := `[
{"id":"1499513741308461240","channel_id":"1459084628458471569","content":"changed your mind later","timestamp":"2026-04-30T20:52:15.546Z","author":{"id":"1395396685148061737","username":"onur_tc","global_name":"onur"}},
{"id":"1499513741308461241","channel_id":"1459084628458471569","content":"please correct me","timestamp":"2026-04-30T20:52:16.546Z","author":{"id":"1395396685148061737","username":"onur_tc","global_name":"onur"}},
{"id":"1499562787343278080","channel_id":"1459084628458471569","content":"I know you are going through a rough time","timestamp":"2026-05-01T00:08:34.929Z","author":{"id":"999999999999999991","username":"steipete","global_name":"Peter"}}
]`
var compressed bytes.Buffer
zw := gzip.NewWriter(&compressed)
_, err := zw.Write([]byte(messages))
require.NoError(t, err)
require.NoError(t, zw.Close())
cacheBlob := append([]byte("https://discord.com/api/v9/channels/1459084628458471569/messages?limit=14\x00"), compressed.Bytes()...)
cacheBlob = append(cacheBlob, []byte("chromium trailing metadata")...)
require.NoError(t, os.WriteFile(filepath.Join(cachePath, "entry_0"), cacheBlob, 0o600))
dbPath := filepath.Join(dir, "discrawl.db")
st, err := store.Open(ctx, dbPath)
require.NoError(t, err)
defer func() { _ = st.Close() }()
stats, err := Import(ctx, st, Options{Path: dir})
require.NoError(t, err)
require.Equal(t, 2, stats.FilesScanned)
require.Equal(t, 3, stats.Messages)
require.Equal(t, 3, stats.DMMessages)
require.Equal(t, 1, stats.DMChannels)
require.Equal(t, 0, stats.SkippedMessages)
results, err := st.SearchMessages(ctx, store.SearchOptions{Query: "changed your mind", Limit: 10})
require.NoError(t, err)
require.Len(t, results, 1)
require.Equal(t, DirectMessageGuildID, results[0].GuildID)
require.Equal(t, "onur", results[0].ChannelName)
require.Equal(t, "onur", results[0].AuthorName)
}
func TestImportReconcilesMessagesWithLaterGuildChannelMetadata(t *testing.T) {
ctx := context.Background()
dir := t.TempDir()