package app import ( "log" "os" "regexp" "strings" "time" "vrc_osc_go/internal/config" "vrc_osc_go/internal/osc" ) var ( selfJoinPattern = regexp.MustCompile(`OnPlayerJoined\s+(.+?)\s+\(usr_[0-9a-fA-F-]+\)`) selfLeftPattern = regexp.MustCompile(`OnPlayerLeft\s+(.+?)\s+\(usr_[0-9a-fA-F-]+\)`) ) func startSelfMonitor(cfg *config.Config, state *discordMuteState) { if cfg.VrcLog.SelfName == "" { return } go func() { lastState := "" for { path, err := findLatestVrchatLog() if err != nil { time.Sleep(2 * time.Second) continue } text, err := os.ReadFile(path) if err != nil { time.Sleep(2 * time.Second) continue } nextState := extractLatestSelfLogState(string(text), cfg.VrcLog.SelfName) if nextState != "" && nextState != lastState { if nextState == "joined" { if err := handleDiscordSend(state, []osc.Value{{Type: 'T', Bool: true}}); err != nil { log.Printf("self monitor discord mute failed: %v", err) } } else if nextState == "left" { if err := handleDiscordSend(state, []osc.Value{{Type: 'F', Bool: false}}); err != nil { log.Printf("self monitor discord mute failed: %v", err) } } lastState = nextState } time.Sleep(2 * time.Second) } }() } func extractLatestSelfLogState(text, selfName string) string { if selfName == "" { return "" } state := "" for _, rawLine := range strings.Split(text, "\n") { if m := selfJoinPattern.FindStringSubmatch(rawLine); len(m) == 2 && strings.TrimSpace(m[1]) == selfName { state = "joined" continue } if m := selfLeftPattern.FindStringSubmatch(rawLine); len(m) == 2 && strings.TrimSpace(m[1]) == selfName { state = "left" } } return state }