浏览代码

Use MentionedJIDs metadata instead of assuming everything is a mention

Tulir Asokan 4 年之前
父节点
当前提交
9671b6c39a
共有 4 个文件被更改,包括 45 次插入28 次删除
  1. 26 18
      formatting.go
  2. 2 2
      go.mod
  3. 4 0
      go.sum
  4. 13 8
      portal.go

+ 26 - 18
formatting.go

@@ -34,7 +34,8 @@ var italicRegex = regexp.MustCompile("([\\s>~*]|^)_(.+?)_([^a-zA-Z\\d]|$)")
 var boldRegex = regexp.MustCompile("([\\s>_~]|^)\\*(.+?)\\*([^a-zA-Z\\d]|$)")
 var strikethroughRegex = regexp.MustCompile("([\\s>_*]|^)~(.+?)~([^a-zA-Z\\d]|$)")
 var codeBlockRegex = regexp.MustCompile("```(?:.|\n)+?```")
-var mentionRegex = regexp.MustCompile("@[0-9]+")
+
+const mentionedJIDsContextKey = "net.maunium.whatsapp.mentioned_jids"
 
 type Formatter struct {
 	bridge *Bridge
@@ -53,28 +54,34 @@ func NewFormatter(bridge *Bridge) *Formatter {
 			TabsToSpaces: 4,
 			Newline:      "\n",
 
-			PillConverter: func(mxid, eventID string) string {
+			PillConverter: func(mxid, eventID string, ctx format.Context) string {
 				if mxid[0] == '@' {
 					puppet := bridge.GetPuppetByMXID(id.UserID(mxid))
 					if puppet != nil {
+						jids, ok := ctx[mentionedJIDsContextKey].([]types.WhatsAppID)
+						if !ok {
+							ctx[mentionedJIDsContextKey] = []types.WhatsAppID{puppet.JID}
+						} else {
+							ctx[mentionedJIDsContextKey] = append(jids, puppet.JID)
+						}
 						return "@" + puppet.PhoneNumber()
 					}
 				}
 				return mxid
 			},
-			BoldConverter: func(text string) string {
+			BoldConverter: func(text string, _ format.Context) string {
 				return fmt.Sprintf("*%s*", text)
 			},
-			ItalicConverter: func(text string) string {
+			ItalicConverter: func(text string, _ format.Context) string {
 				return fmt.Sprintf("_%s_", text)
 			},
-			StrikethroughConverter: func(text string) string {
+			StrikethroughConverter: func(text string, _ format.Context) string {
 				return fmt.Sprintf("~%s~", text)
 			},
-			MonospaceConverter: func(text string) string {
+			MonospaceConverter: func(text string, _ format.Context) string {
 				return fmt.Sprintf("```%s```", text)
 			},
-			MonospaceBlockConverter: func(text, language string) string {
+			MonospaceBlockConverter: func(text, language string, _ format.Context) string {
 				return fmt.Sprintf("```%s```", text)
 			},
 		},
@@ -92,16 +99,8 @@ func NewFormatter(bridge *Bridge) *Formatter {
 			}
 			return fmt.Sprintf("<code>%s</code>", str)
 		},
-		mentionRegex: func(str string) string {
-			mxid, displayname := formatter.getMatrixInfoByJID(str[1:] + whatsappExt.NewUserSuffix)
-			return fmt.Sprintf(`<a href="https://matrix.to/#/%s">%s</a>`, mxid, displayname)
-		},
 	}
 	formatter.waReplFuncText = map[*regexp.Regexp]func(string) string{
-		mentionRegex: func(str string) string {
-			_, displayname := formatter.getMatrixInfoByJID(str[1:] + whatsappExt.NewUserSuffix)
-			return displayname
-		},
 	}
 	return formatter
 }
@@ -117,7 +116,7 @@ func (formatter *Formatter) getMatrixInfoByJID(jid types.WhatsAppID) (mxid id.Us
 	return
 }
 
-func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent) {
+func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent, mentionedJIDs []types.WhatsAppID) {
 	output := html.EscapeString(content.Body)
 	for regex, replacement := range formatter.waReplString {
 		output = regex.ReplaceAllString(output, replacement)
@@ -125,6 +124,12 @@ func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent) {
 	for regex, replacer := range formatter.waReplFunc {
 		output = regex.ReplaceAllStringFunc(output, replacer)
 	}
+	for _, jid := range mentionedJIDs {
+		mxid, displayname := formatter.getMatrixInfoByJID(jid)
+		number := "@" + strings.Replace(jid, whatsappExt.NewUserSuffix, "", 1)
+		output = strings.Replace(output, number, fmt.Sprintf(`<a href="https://matrix.to/#/%s">%s</a>`, mxid, displayname), -1)
+		content.Body = strings.Replace(content.Body, number, displayname, -1)
+	}
 	if output != content.Body {
 		output = strings.Replace(output, "\n", "<br/>", -1)
 		content.FormattedBody = output
@@ -135,6 +140,9 @@ func (formatter *Formatter) ParseWhatsApp(content *event.MessageEventContent) {
 	}
 }
 
-func (formatter *Formatter) ParseMatrix(html string) string {
-	return formatter.matrixHTMLParser.Parse(html)
+func (formatter *Formatter) ParseMatrix(html string) (string, []types.WhatsAppID) {
+	ctx := make(format.Context)
+	result := formatter.matrixHTMLParser.Parse(html, ctx)
+	mentionedJIDs := ctx[mentionedJIDsContextKey].([]types.WhatsAppID)
+	return result, mentionedJIDs
 }

+ 2 - 2
go.mod

@@ -16,7 +16,7 @@ require (
 	gopkg.in/yaml.v2 v2.3.0
 	maunium.net/go/mauflag v1.0.0
 	maunium.net/go/maulogger/v2 v2.1.1
-	maunium.net/go/mautrix v0.6.1
+	maunium.net/go/mautrix v0.7.0-rc.2
 )
 
-replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.6
+replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.7

+ 4 - 0
go.sum

@@ -121,6 +121,8 @@ github.com/tulir/go-whatsapp v0.3.5 h1:cFw8MWhoLTqR0h2kSkSvz866rggRIAx4X2l8I65gA
 github.com/tulir/go-whatsapp v0.3.5/go.mod h1:7yGOBdWidM6gsmbAFwgkwHEIhzVrm01+6UbImpMWfTM=
 github.com/tulir/go-whatsapp v0.3.6 h1:RtyNh8TFX48ClMvi2J8oS3qmH7b1t9SIKA5jucG2lbk=
 github.com/tulir/go-whatsapp v0.3.6/go.mod h1:7yGOBdWidM6gsmbAFwgkwHEIhzVrm01+6UbImpMWfTM=
+github.com/tulir/go-whatsapp v0.3.7 h1:6YoHsAlO+Y1SnU0bOntDmuvJQziEnBjFKO+1fOH2VIw=
+github.com/tulir/go-whatsapp v0.3.7/go.mod h1:7yGOBdWidM6gsmbAFwgkwHEIhzVrm01+6UbImpMWfTM=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
@@ -212,3 +214,5 @@ maunium.net/go/mautrix v0.6.0 h1:V32l4aygKk2XcH3fi8Yd0pFeSyYZJNRIvr8vdA2GtC8=
 maunium.net/go/mautrix v0.6.0/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo=
 maunium.net/go/mautrix v0.6.1 h1:OFxAEnjEtkstE5J3RLv+vVrUORY6UTXV8pD/qWRBTPI=
 maunium.net/go/mautrix v0.6.1/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo=
+maunium.net/go/mautrix v0.7.0-rc.2 h1:139raRbbLft9i+g0zGVOT8rrHKRQmeo0SsZnFpZDEXE=
+maunium.net/go/mautrix v0.7.0-rc.2/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo=

+ 13 - 8
portal.go

@@ -1189,7 +1189,7 @@ func (portal *Portal) HandleTextMessage(source *User, message whatsapp.TextMessa
 		MsgType: event.MsgText,
 	}
 
-	portal.bridge.Formatter.ParseWhatsApp(content)
+	portal.bridge.Formatter.ParseWhatsApp(content, message.ContextInfo.MentionedJID)
 	portal.SetReply(content, message.ContextInfo)
 
 	_, _ = intent.UserTyping(portal.MXID, false, 0)
@@ -1554,7 +1554,7 @@ func (portal *Portal) HandleMediaMessage(source *User, msg mediaMessage) {
 			MsgType: event.MsgNotice,
 		}
 
-		portal.bridge.Formatter.ParseWhatsApp(captionContent)
+		portal.bridge.Formatter.ParseWhatsApp(captionContent, msg.context.MentionedJID)
 
 		_, err := portal.sendMessage(intent, event.EventMessage, captionContent, ts)
 		if err != nil {
@@ -1658,8 +1658,9 @@ func (portal *Portal) convertGifToVideo(gif []byte) ([]byte, error) {
 
 func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool, content *event.MessageEventContent, eventID id.EventID, mediaType whatsapp.MediaType) *MediaUpload {
 	var caption string
+	var mentionedJIDs []types.WhatsAppID
 	if relaybotFormatted {
-		caption = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
+		caption, mentionedJIDs = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
 	}
 
 	var file *event.EncryptedFileInfo
@@ -1702,6 +1703,7 @@ func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool
 
 	return &MediaUpload{
 		Caption:       caption,
+		MentionedJIDs: mentionedJIDs,
 		URL:           url,
 		MediaKey:      mediaKey,
 		FileEncSHA256: fileEncSHA256,
@@ -1713,6 +1715,7 @@ func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool
 
 type MediaUpload struct {
 	Caption       string
+	MentionedJIDs []types.WhatsAppID
 	URL           string
 	MediaKey      []byte
 	FileEncSHA256 []byte
@@ -1819,15 +1822,11 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
 	case event.MsgText, event.MsgEmote, event.MsgNotice:
 		text := content.Body
 		if content.Format == event.FormatHTML {
-			text = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
+			text, ctxInfo.MentionedJid = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
 		}
 		if content.MsgType == event.MsgEmote && !relaybotFormatted {
 			text = "/me " + text
 		}
-		ctxInfo.MentionedJid = mentionRegex.FindAllString(text, -1)
-		for index, mention := range ctxInfo.MentionedJid {
-			ctxInfo.MentionedJid[index] = mention[1:] + whatsappExt.NewUserSuffix
-		}
 		if ctxInfo.StanzaId != nil || ctxInfo.MentionedJid != nil {
 			info.Message.ExtendedTextMessage = &waProto.ExtendedTextMessage{
 				Text:        &text,
@@ -1841,7 +1840,9 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
 		if media == nil {
 			return nil, sender
 		}
+		ctxInfo.MentionedJid = media.MentionedJIDs
 		info.Message.ImageMessage = &waProto.ImageMessage{
+			ContextInfo:   ctxInfo,
 			Caption:       &media.Caption,
 			JpegThumbnail: media.Thumbnail,
 			Url:           &media.URL,
@@ -1858,7 +1859,9 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
 			return nil, sender
 		}
 		duration := uint32(content.GetInfo().Duration)
+		ctxInfo.MentionedJid = media.MentionedJIDs
 		info.Message.VideoMessage = &waProto.VideoMessage{
+			ContextInfo:   ctxInfo,
 			Caption:       &media.Caption,
 			JpegThumbnail: media.Thumbnail,
 			Url:           &media.URL,
@@ -1877,6 +1880,7 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
 		}
 		duration := uint32(content.GetInfo().Duration)
 		info.Message.AudioMessage = &waProto.AudioMessage{
+			ContextInfo:   ctxInfo,
 			Url:           &media.URL,
 			MediaKey:      media.MediaKey,
 			Mimetype:      &content.GetInfo().MimeType,
@@ -1891,6 +1895,7 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waP
 			return nil, sender
 		}
 		info.Message.DocumentMessage = &waProto.DocumentMessage{
+			ContextInfo:   ctxInfo,
 			Url:           &media.URL,
 			FileName:      &content.Body,
 			MediaKey:      media.MediaKey,