X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/add3cf6416e33c24331fd1e90e99284f44d2aae2..f6f0febc2c599ed7bb2a2653215a74d8de1abace:/whatsapp_inbox.go diff --git a/whatsapp_inbox.go b/whatsapp_inbox.go index 9d2183e..c9ca81b 100644 --- a/whatsapp_inbox.go +++ b/whatsapp_inbox.go @@ -2,9 +2,9 @@ package main import ( "context" - "crypto/sha256" "fmt" "log/slog" + "path/filepath" "slices" "strings" "sync" @@ -34,13 +34,16 @@ const ( // newWhatsAppInbox returns the inbox of the batches in state, with clock for // the times of the batch texts and groups for the names of the groups. images -// holds shared images, and logger gets image failures. +// holds shared images, and logger gets image failures. Audio shares the data +// directory of state. func newWhatsAppInbox(state *WhatsAppState, clock func() time.Time, groups *WhatsAppGroups, images *ImageStore, logger *slog.Logger) *WhatsAppInbox { return &WhatsAppInbox{ state: state, clock: clock, groups: groups, images: images, + voices: &VoiceStore{dir: filepath.Join(filepath.Dir(filepath.Dir(state.path)), voiceDirName)}, + voice: &VoiceTranscriber{}, logger: logger, wake: make(chan struct{}, 1), failures: make(chan error, 1), @@ -74,6 +77,8 @@ type WhatsAppInbox struct { clock func() time.Time groups *WhatsAppGroups images *ImageStore + voices *VoiceStore + voice *VoiceTranscriber logger *slog.Logger wake chan struct{} failures chan error @@ -225,10 +230,10 @@ func (i *WhatsAppInbox) startCatchup() { }) } -// receive stores an image before its batch and wakes Run. link gives the device -// and the own IDs. It returns false when the state file cannot hold the -// message, so that the library does not acknowledge it, and Run stops the -// daemon. An image that cannot be downloaded or stored gets a text marker. A +// receive stores images and transcribed voice notes before their batches and +// wakes Run. link gives the device and the own IDs. It returns false when the +// state file cannot hold the message, so that the library does not acknowledge +// it, and Run stops the daemon. Failed media input gets a text marker. A // message that the batches do not take is handled with nothing to do. func (i *WhatsAppInbox) receive(ctx context.Context, link WhatsAppLink, event *events.Message) bool { lookupCtx, cancel := context.WithTimeout(ctx, whatsappContactLookupTimeout) @@ -244,6 +249,8 @@ func (i *WhatsAppInbox) receive(ctx context.Context, link WhatsAppLink, event *e defer cancel() message.Text = i.imageText(ctx, link, event, message.Text) + } else if event.Message.GetAudioMessage().GetPTT() { + message.Text = whatsappRedact(link.own, whatsappVoice(ctx, link.client, i.voices, i.voice, event.Message.GetAudioMessage())) } _, err := i.state.Add(chat, message, time.Now()) @@ -271,9 +278,8 @@ func (i *WhatsAppInbox) imageText(ctx context.Context, link WhatsAppLink, event name, err := whatsappImage(ctx, link.client, i.images, event.Message.GetImageMessage()) if err != nil { chat := event.Info.Chat.ToNonAD() - digest := sha256.Sum256([]byte(chat.String())) redact := append(slices.Clone(link.own), chat.User) - i.logger.Error("image receive failed", "chat", fmt.Sprintf("%x", digest[:6]), "err", whatsappRedact(redact, err.Error())) + i.logger.Error("image receive failed", "chat", whatsappChatHash(chat), "err", whatsappRedact(redact, err.Error())) text := "(image not downloaded)" if caption != "" { @@ -358,7 +364,7 @@ func whatsappMessage(ctx context.Context, device *store.Device, own []string, ev chatJID := info.Chat.ToNonAD() switch { case device == nil: - case event.IsEdit, info.Edit != "", event.IsEphemeral, event.IsViewOnce, event.Message.GetImageMessage().GetViewOnce(), event.Message.GetVideoMessage().GetViewOnce(), event.SourceWebMsg != nil: + case event.IsEdit, info.Edit != "", event.IsEphemeral, event.IsViewOnce, event.Message.GetImageMessage().GetViewOnce(), event.Message.GetVideoMessage().GetViewOnce(), event.Message.GetAudioMessage().GetViewOnce(), event.SourceWebMsg != nil: case chatJID.Server != types.DefaultUserServer && chatJID.Server != types.HiddenUserServer && chatJID.Server != types.GroupServer: case slices.Contains(own, chatJID.User): default: @@ -369,7 +375,8 @@ func whatsappMessage(ctx context.Context, device *store.Device, own []string, ev } // whatsappText returns the chat and the batch message of event, a message that -// the batches take. An image returns its caption until receive stores it. +// the batches take. An image returns its caption until receive stores it. A +// voice note returns a marker until receive transcribes it. func whatsappText(ctx context.Context, device *store.Device, own []string, event *events.Message) (WhatsAppChat, WhatsAppMessage, bool) { info := event.Info text := event.Message.GetConversation() @@ -380,6 +387,9 @@ func whatsappText(ctx context.Context, device *store.Device, own []string, event contextInfo := extended.GetContextInfo() switch { + case event.Message.GetAudioMessage().GetPTT(): + text = "(voice not downloaded)" + contextInfo = event.Message.GetAudioMessage().GetContextInfo() case event.Message.GetImageMessage() != nil: image := event.Message.GetImageMessage() text = image.GetCaption()