Add a MessageClipped option to set your own clipped message. Closes #1359 (#1487)

This commit is contained in:
Wim 2021-05-27 21:45:23 +02:00 committed by GitHub
parent efec01a92f
commit c86137449e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 124 additions and 105 deletions

View File

@ -283,7 +283,7 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st
// Upload a file if it exists // Upload a file if it exists
if msg.Extra != nil { if msg.Extra != nil {
for _, rmsg := range helper.HandleExtra(msg, b.General) { for _, rmsg := range helper.HandleExtra(msg, b.General) {
rmsg.Text = helper.ClipMessage(rmsg.Text, MessageLength) rmsg.Text = helper.ClipMessage(rmsg.Text, MessageLength, b.GetString("MessageClipped"))
if _, err := b.c.ChannelMessageSend(channelID, rmsg.Username+rmsg.Text); err != nil { if _, err := b.c.ChannelMessageSend(channelID, rmsg.Username+rmsg.Text); err != nil {
b.Log.Errorf("Could not send message %#v: %s", rmsg, err) b.Log.Errorf("Could not send message %#v: %s", rmsg, err)
} }
@ -294,7 +294,7 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st
} }
} }
msg.Text = helper.ClipMessage(msg.Text, MessageLength) msg.Text = helper.ClipMessage(msg.Text, MessageLength, b.GetString("MessageClipped"))
msg.Text = b.replaceUserMentions(msg.Text) msg.Text = b.replaceUserMentions(msg.Text)
// Edit message // Edit message

View File

@ -116,7 +116,7 @@ func (b *Bdiscord) handleEventWebhook(msg *config.Message, channelID string) (st
return "", nil return "", nil
} }
msg.Text = helper.ClipMessage(msg.Text, MessageLength) msg.Text = helper.ClipMessage(msg.Text, MessageLength, b.GetString("MessageClipped"))
msg.Text = b.replaceUserMentions(msg.Text) msg.Text = b.replaceUserMentions(msg.Text)
// discord username must be [0..32] max // discord username must be [0..32] max
if len(msg.Username) > 32 { if len(msg.Username) > 32 {

View File

@ -82,8 +82,10 @@ func DownloadFileAuthRocket(url, token, userID string) (*[]byte, error) {
// TODO: The current implementation has the inconvenient that it disregards // TODO: The current implementation has the inconvenient that it disregards
// word boundaries when splitting but this is hard to solve without potentially // word boundaries when splitting but this is hard to solve without potentially
// breaking formatting and other stylistic effects. // breaking formatting and other stylistic effects.
func GetSubLines(message string, maxLineLength int) []string { func GetSubLines(message string, maxLineLength int, clippingMessage string) []string {
const clippingMessage = " <clipped message>" if clippingMessage == "" {
clippingMessage = " <clipped message>"
}
var lines []string var lines []string
for _, line := range strings.Split(strings.TrimSpace(message), "\n") { for _, line := range strings.Split(strings.TrimSpace(message), "\n") {
@ -193,8 +195,11 @@ func RemoveEmptyNewLines(msg string) string {
// ClipMessage trims a message to the specified length if it exceeds it and adds a warning // ClipMessage trims a message to the specified length if it exceeds it and adds a warning
// to the message in case it does so. // to the message in case it does so.
func ClipMessage(text string, length int) string { func ClipMessage(text string, length int, clippingMessage string) string {
const clippingMessage = " <clipped message>" if clippingMessage == "" {
clippingMessage = " <clipped message>"
}
if len(text) > length { if len(text) > length {
text = text[:length-len(clippingMessage)] text = text[:length-len(clippingMessage)]
if r, size := utf8.DecodeLastRuneInString(text); r == utf8.RuneError { if r, size := utf8.DecodeLastRuneInString(text); r == utf8.RuneError {

View File

@ -10,98 +10,96 @@ import (
const testLineLength = 64 const testLineLength = 64
var ( var lineSplittingTestCases = map[string]struct {
lineSplittingTestCases = map[string]struct { input string
input string splitOutput []string
splitOutput []string nonSplitOutput []string
nonSplitOutput []string }{
}{ "Short single-line message": {
"Short single-line message": { input: "short",
input: "short", splitOutput: []string{"short"},
splitOutput: []string{"short"}, nonSplitOutput: []string{"short"},
nonSplitOutput: []string{"short"}, },
"Long single-line message": {
input: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
splitOutput: []string{
"Lorem ipsum dolor sit amet, consectetur adipis <clipped message>",
"cing elit, sed do eiusmod tempor incididunt ut <clipped message>",
" labore et dolore magna aliqua.",
}, },
"Long single-line message": { nonSplitOutput: []string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."},
input: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", },
splitOutput: []string{ "Short multi-line message": {
"Lorem ipsum dolor sit amet, consectetur adipis <clipped message>", input: "I\ncan't\nget\nno\nsatisfaction!",
"cing elit, sed do eiusmod tempor incididunt ut <clipped message>", splitOutput: []string{
" labore et dolore magna aliqua.", "I",
}, "can't",
nonSplitOutput: []string{"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."}, "get",
"no",
"satisfaction!",
}, },
"Short multi-line message": { nonSplitOutput: []string{
input: "I\ncan't\nget\nno\nsatisfaction!", "I",
splitOutput: []string{ "can't",
"I", "get",
"can't", "no",
"get", "satisfaction!",
"no",
"satisfaction!",
},
nonSplitOutput: []string{
"I",
"can't",
"get",
"no",
"satisfaction!",
},
}, },
"Long multi-line message": { },
input: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n" + "Long multi-line message": {
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n" + input: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n" +
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n" + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n" +
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n" +
splitOutput: []string{ "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
"Lorem ipsum dolor sit amet, consectetur adipis <clipped message>", splitOutput: []string{
"cing elit, sed do eiusmod tempor incididunt ut <clipped message>", "Lorem ipsum dolor sit amet, consectetur adipis <clipped message>",
" labore et dolore magna aliqua.", "cing elit, sed do eiusmod tempor incididunt ut <clipped message>",
"Ut enim ad minim veniam, quis nostrud exercita <clipped message>", " labore et dolore magna aliqua.",
"tion ullamco laboris nisi ut aliquip ex ea com <clipped message>", "Ut enim ad minim veniam, quis nostrud exercita <clipped message>",
"modo consequat.", "tion ullamco laboris nisi ut aliquip ex ea com <clipped message>",
"Duis aute irure dolor in reprehenderit in volu <clipped message>", "modo consequat.",
"ptate velit esse cillum dolore eu fugiat nulla <clipped message>", "Duis aute irure dolor in reprehenderit in volu <clipped message>",
" pariatur.", "ptate velit esse cillum dolore eu fugiat nulla <clipped message>",
"Excepteur sint occaecat cupidatat non proident <clipped message>", " pariatur.",
", sunt in culpa qui officia deserunt mollit an <clipped message>", "Excepteur sint occaecat cupidatat non proident <clipped message>",
"im id est laborum.", ", sunt in culpa qui officia deserunt mollit an <clipped message>",
}, "im id est laborum.",
nonSplitOutput: []string{
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
},
}, },
"Message ending with new-line.": { nonSplitOutput: []string{
input: "Newline ending\n", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
splitOutput: []string{"Newline ending"}, "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
nonSplitOutput: []string{"Newline ending"}, "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
}, },
"Long message containing UTF-8 multi-byte runes": { },
input: "不布人個我此而及單石業喜資富下我河下日沒一我臺空達的常景便物沒為……子大我別名解成?生賣的全直黑,我自我結毛分洲了世當,是政福那是東;斯說", "Message ending with new-line.": {
splitOutput: []string{ input: "Newline ending\n",
"不布人個我此而及單石業喜資富下 <clipped message>", splitOutput: []string{"Newline ending"},
"我河下日沒一我臺空達的常景便物 <clipped message>", nonSplitOutput: []string{"Newline ending"},
"沒為……子大我別名解成?生賣的 <clipped message>", },
"全直黑,我自我結毛分洲了世當, <clipped message>", "Long message containing UTF-8 multi-byte runes": {
"是政福那是東;斯說", input: "不布人個我此而及單石業喜資富下我河下日沒一我臺空達的常景便物沒為……子大我別名解成?生賣的全直黑,我自我結毛分洲了世當,是政福那是東;斯說",
}, splitOutput: []string{
nonSplitOutput: []string{"不布人個我此而及單石業喜資富下我河下日沒一我臺空達的常景便物沒為……子大我別名解成?生賣的全直黑,我自我結毛分洲了世當,是政福那是東;斯說"}, "不布人個我此而及單石業喜資富下 <clipped message>",
"我河下日沒一我臺空達的常景便物 <clipped message>",
"沒為……子大我別名解成?生賣的 <clipped message>",
"全直黑,我自我結毛分洲了世當, <clipped message>",
"是政福那是東;斯說",
}, },
} nonSplitOutput: []string{"不布人個我此而及單石業喜資富下我河下日沒一我臺空達的常景便物沒為……子大我別名解成?生賣的全直黑,我自我結毛分洲了世當,是政福那是東;斯說"},
) },
}
func TestGetSubLines(t *testing.T) { func TestGetSubLines(t *testing.T) {
for testname, testcase := range lineSplittingTestCases { for testname, testcase := range lineSplittingTestCases {
splitLines := GetSubLines(testcase.input, testLineLength) splitLines := GetSubLines(testcase.input, testLineLength, "")
assert.Equalf(t, testcase.splitOutput, splitLines, "'%s' testcase should give expected lines with splitting.", testname) assert.Equalf(t, testcase.splitOutput, splitLines, "'%s' testcase should give expected lines with splitting.", testname)
for _, splitLine := range splitLines { for _, splitLine := range splitLines {
byteLength := len([]byte(splitLine)) byteLength := len([]byte(splitLine))
assert.True(t, byteLength <= testLineLength, "Splitted line '%s' of testcase '%s' should not exceed the maximum byte-length (%d vs. %d).", splitLine, testcase, byteLength, testLineLength) assert.True(t, byteLength <= testLineLength, "Splitted line '%s' of testcase '%s' should not exceed the maximum byte-length (%d vs. %d).", splitLine, testcase, byteLength, testLineLength)
} }
nonSplitLines := GetSubLines(testcase.input, 0) nonSplitLines := GetSubLines(testcase.input, 0, "")
assert.Equalf(t, testcase.nonSplitOutput, nonSplitLines, "'%s' testcase should give expected lines without splitting.", testname) assert.Equalf(t, testcase.nonSplitOutput, nonSplitLines, "'%s' testcase should give expected lines without splitting.", testname)
} }
} }
@ -110,16 +108,19 @@ func TestConvertWebPToPNG(t *testing.T) {
if os.Getenv("LOCAL_TEST") == "" { if os.Getenv("LOCAL_TEST") == "" {
t.Skip() t.Skip()
} }
input, err := ioutil.ReadFile("test.webp") input, err := ioutil.ReadFile("test.webp")
if err != nil { if err != nil {
t.Fail() t.Fail()
} }
d := &input d := &input
err = ConvertWebPToPNG(d) err = ConvertWebPToPNG(d)
if err != nil { if err != nil {
t.Fail() t.Fail()
} }
err = ioutil.WriteFile("test.png", *d, 0644)
err = ioutil.WriteFile("test.png", *d, 0o644) // nolint:gosec
if err != nil { if err != nil {
t.Fail() t.Fail()
} }

View File

@ -167,9 +167,9 @@ func (b *Birc) Send(msg config.Message) (string, error) {
} }
if b.GetBool("MessageSplit") { if b.GetBool("MessageSplit") {
msgLines = helper.GetSubLines(msg.Text, b.MessageLength) msgLines = helper.GetSubLines(msg.Text, b.MessageLength, b.GetString("MessageClipped"))
} else { } else {
msgLines = helper.GetSubLines(msg.Text, 0) msgLines = helper.GetSubLines(msg.Text, 0, b.GetString("MessageClipped"))
} }
for i := range msgLines { for i := range msgLines {
if len(b.Local) >= b.MessageQueue { if len(b.Local) >= b.MessageQueue {
@ -316,12 +316,16 @@ func (b *Birc) endNames(client *girc.Client, event girc.Event) {
sort.Strings(b.names[channel]) sort.Strings(b.names[channel])
maxNamesPerPost := (300 / b.nicksPerRow()) * b.nicksPerRow() maxNamesPerPost := (300 / b.nicksPerRow()) * b.nicksPerRow()
for len(b.names[channel]) > maxNamesPerPost { for len(b.names[channel]) > maxNamesPerPost {
b.Remote <- config.Message{Username: b.Nick, Text: b.formatnicks(b.names[channel][0:maxNamesPerPost]), b.Remote <- config.Message{
Channel: channel, Account: b.Account} Username: b.Nick, Text: b.formatnicks(b.names[channel][0:maxNamesPerPost]),
Channel: channel, Account: b.Account,
}
b.names[channel] = b.names[channel][maxNamesPerPost:] b.names[channel] = b.names[channel][maxNamesPerPost:]
} }
b.Remote <- config.Message{Username: b.Nick, Text: b.formatnicks(b.names[channel]), b.Remote <- config.Message{
Channel: channel, Account: b.Account} Username: b.Nick, Text: b.formatnicks(b.names[channel]),
Channel: channel, Account: b.Account,
}
b.names[channel] = nil b.names[channel] = nil
b.i.Handlers.Clear(girc.RPL_NAMREPLY) b.i.Handlers.Clear(girc.RPL_NAMREPLY)
b.i.Handlers.Clear(girc.RPL_ENDOFNAMES) b.i.Handlers.Clear(girc.RPL_ENDOFNAMES)

View File

@ -248,9 +248,9 @@ func (b *Bmumble) processMessage(msg *config.Message) {
// If there is a maximum message length, split and truncate the lines // If there is a maximum message length, split and truncate the lines
var msgLines []string var msgLines []string
if maxLength := b.serverConfig.MaximumMessageLength; maxLength != nil { if maxLength := b.serverConfig.MaximumMessageLength; maxLength != nil {
msgLines = helper.GetSubLines(msg.Text, *maxLength-len(msg.Username)) msgLines = helper.GetSubLines(msg.Text, *maxLength-len(msg.Username), b.GetString("MessageClipped"))
} else { } else {
msgLines = helper.GetSubLines(msg.Text, 0) msgLines = helper.GetSubLines(msg.Text, 0, b.GetString("MessageClipped"))
} }
// Send the individual lindes // Send the individual lindes
for i := range msgLines { for i := range msgLines {

View File

@ -195,7 +195,7 @@ func (b *Bslack) Send(msg config.Message) (string, error) {
b.Log.Debugf("=> Receiving %#v", msg) b.Log.Debugf("=> Receiving %#v", msg)
} }
msg.Text = helper.ClipMessage(msg.Text, messageLength) msg.Text = helper.ClipMessage(msg.Text, messageLength, b.GetString("MessageClipped"))
msg.Text = b.replaceCodeFence(msg.Text) msg.Text = b.replaceCodeFence(msg.Text)
// Make a action /me of the message // Make a action /me of the message

View File

@ -76,20 +76,24 @@ MessageDelay=1300
#Maximum amount of messages to hold in queue. If queue is full #Maximum amount of messages to hold in queue. If queue is full
#messages will be dropped. #messages will be dropped.
#<message clipped> will be add to the message that fills the queue. #<clipped message> will be add to the message that fills the queue.
#OPTIONAL (default 30) #OPTIONAL (default 30)
MessageQueue=30 MessageQueue=30
#Maximum length of message sent to irc server. If it exceeds #Maximum length of message sent to irc server. If it exceeds
#<message clipped> will be add to the message. #<clipped message> will be add to the message.
#OPTIONAL (default 400) #OPTIONAL (default 400)
MessageLength=400 MessageLength=400
#Split messages on MessageLength instead of showing the <message clipped> #Split messages on MessageLength instead of showing the <clipped message>
#WARNING: this could lead to flooding #WARNING: this could lead to flooding
#OPTIONAL (default false) #OPTIONAL (default false)
MessageSplit=false MessageSplit=false
#Message to show when a message is too big
#Default "<clipped message>"
MessageClipped="<clipped message>"
#Delay in seconds to rejoin a channel when kicked #Delay in seconds to rejoin a channel when kicked
#OPTIONAL (default 0) #OPTIONAL (default 0)
RejoinDelay=0 RejoinDelay=0
@ -826,6 +830,10 @@ PreserveThreading=false
#OPTIONAL (default false) #OPTIONAL (default false)
ShowUserTyping=false ShowUserTyping=false
#Message to show when a message is too big
#Default "<clipped message>"
MessageClipped="<clipped message>"
################################################################### ###################################################################
#discord section #discord section
################################################################### ###################################################################
@ -961,6 +969,10 @@ ShowTopicChange=false
# Supported from the following bridges: slack # Supported from the following bridges: slack
SyncTopic=false SyncTopic=false
#Message to show when a message is too big
#Default "<clipped message>"
MessageClipped="<clipped message>"
################################################################### ###################################################################
#telegram section #telegram section
################################################################### ###################################################################
@ -1435,9 +1447,7 @@ StripNick=false
ShowTopicChange=false ShowTopicChange=false
################################################################### ###################################################################
#
# NCTalk (Nextcloud Talk) # NCTalk (Nextcloud Talk)
#
################################################################### ###################################################################
[nctalk.bridge] [nctalk.bridge]
@ -1460,9 +1470,7 @@ Password = "talkuserpass"
GuestSuffix = " (Guest)" GuestSuffix = " (Guest)"
################################################################### ###################################################################
#
# Mumble # Mumble
#
################################################################### ###################################################################
[mumble.bridge] [mumble.bridge]
@ -1505,9 +1513,14 @@ TLSCACertificate=mumble-ca.crt
# OPTIONAL (default false) # OPTIONAL (default false)
SkipTLSVerify=false SkipTLSVerify=false
#Message to show when a message is too big
#Default "<clipped message>"
MessageClipped="<clipped message>"
################################################################### ###################################################################
#VK #VK
################################################################### ###################################################################
#
[vk.myvk] [vk.myvk]
#Group access token #Group access token
#See https://vk.com/dev/bots_docs #See https://vk.com/dev/bots_docs
@ -1518,9 +1531,7 @@ Token="Yourtokenhere"
GroupID=123456789 GroupID=123456789
################################################################### ###################################################################
#
# WhatsApp # WhatsApp
#
################################################################### ###################################################################
[whatsapp.bridge] [whatsapp.bridge]
@ -1547,9 +1558,7 @@ Label="Organization"
################################################################### ###################################################################
#
# zulip # zulip
#
################################################################### ###################################################################
[zulip] [zulip]