mirror of
https://salsa.debian.org/mdosch/feed-to-muc.git
synced 2024-11-25 07:28:40 +01:00
Compare commits
5 commits
3d258106bc
...
fb1b94789c
Author | SHA1 | Date | |
---|---|---|---|
|
fb1b94789c | ||
|
1e8f59b84f | ||
|
b2714d0582 | ||
|
91e91b68ae | ||
|
0d28cd318f |
5 changed files with 34 additions and 29 deletions
|
@ -87,7 +87,6 @@ func getArticles(feedURL string, max int, noExcerpt bool, filter []string, filte
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error: Can't create cache file:", err)
|
log.Fatal("Error: Can't create cache file:", err)
|
||||||
}
|
}
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
last = time.Now()
|
last = time.Now()
|
||||||
|
|
||||||
|
@ -96,6 +95,7 @@ func getArticles(feedURL string, max int, noExcerpt bool, filter []string, filte
|
||||||
lastUpdateJSON, _ := json.MarshalIndent(lastUpdate, "", " ")
|
lastUpdateJSON, _ := json.MarshalIndent(lastUpdate, "", " ")
|
||||||
_, err = file.Write(lastUpdateJSON)
|
_, err = file.Write(lastUpdateJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
file.Close()
|
||||||
log.Fatal("Error: Can't write last update time stamp to cache file:", err)
|
log.Fatal("Error: Can't write last update time stamp to cache file:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,21 +103,24 @@ func getArticles(feedURL string, max int, noExcerpt bool, filter []string, filte
|
||||||
|
|
||||||
file, err = os.OpenFile(cacheFile, os.O_RDWR, 0o600)
|
file, err = os.OpenFile(cacheFile, os.O_RDWR, 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
file.Close()
|
||||||
log.Fatal("Error: Can't open cache file:", err)
|
log.Fatal("Error: Can't open cache file:", err)
|
||||||
}
|
}
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
decoder := json.NewDecoder(file)
|
decoder := json.NewDecoder(file)
|
||||||
lastUpdate := feedCache{}
|
lastUpdate := feedCache{}
|
||||||
if err := decoder.Decode(&lastUpdate); err != nil {
|
if err := decoder.Decode(&lastUpdate); err != nil {
|
||||||
|
file.Close()
|
||||||
log.Fatal("Error: Can't decode laste updates time stamp:", err)
|
log.Fatal("Error: Can't decode laste updates time stamp:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
last, err = time.Parse(time.RFC3339, string(lastUpdate.LastChange))
|
last, err = time.Parse(time.RFC3339, string(lastUpdate.LastChange))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
file.Close()
|
||||||
log.Fatal("Error: Can't parse last updates time stamp:", err)
|
log.Fatal("Error: Can't parse last updates time stamp:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
file.Close()
|
||||||
|
|
||||||
fp := gofeed.NewParser()
|
fp := gofeed.NewParser()
|
||||||
feed, err := fp.ParseURL(feedURL)
|
feed, err := fp.ParseURL(feedURL)
|
||||||
|
@ -139,12 +142,10 @@ func getArticles(feedURL string, max int, noExcerpt bool, filter []string, filte
|
||||||
if last.After(*feed.Items[0].UpdatedParsed) {
|
if last.After(*feed.Items[0].UpdatedParsed) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
} else {
|
} else if last.After(*feed.Items[0].PublishedParsed) {
|
||||||
// If cached timestamp is newer than the one of
|
// If cached timestamp is newer than the one of
|
||||||
// the last article return.
|
// the last article return.
|
||||||
if last.After(*feed.Items[0].PublishedParsed) {
|
return "", err
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check last n (defined in config) articles for new ones.
|
// Check last n (defined in config) articles for new ones.
|
||||||
|
@ -188,13 +189,14 @@ func getArticles(feedURL string, max int, noExcerpt bool, filter []string, filte
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error: Can't create cache file:", err)
|
log.Fatal("Error: Can't create cache file:", err)
|
||||||
}
|
}
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
lastUpdateJSON, _ := json.MarshalIndent(lastUpdate, "", " ")
|
lastUpdateJSON, _ := json.MarshalIndent(lastUpdate, "", " ")
|
||||||
_, err = file.Write(lastUpdateJSON)
|
_, err = file.Write(lastUpdateJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
file.Close()
|
||||||
log.Fatal("Error: Can't write last update time stamp to cache file:", err)
|
log.Fatal("Error: Can't write last update time stamp to cache file:", err)
|
||||||
}
|
}
|
||||||
|
file.Close()
|
||||||
|
|
||||||
// Remove redirects and tracking parameters from URL.
|
// Remove redirects and tracking parameters from URL.
|
||||||
cleanURL, _ := removeTracking(article.Link)
|
cleanURL, _ := removeTracking(article.Link)
|
||||||
|
@ -249,7 +251,7 @@ func getArticles(feedURL string, max int, noExcerpt bool, filter []string, filte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove lines only consisting of "> "; thank you reddit.
|
// Remove lines only consisting of "> "; thank you reddit.
|
||||||
description = strings.Replace(description, "> \n", "", -1)
|
description = strings.ReplaceAll(description, "> \n", "")
|
||||||
|
|
||||||
// Split article description/content in single lines.
|
// Split article description/content in single lines.
|
||||||
lines := strings.Split(description, "\n")
|
lines := strings.Split(description, "\n")
|
||||||
|
@ -268,10 +270,10 @@ func getArticles(feedURL string, max int, noExcerpt bool, filter []string, filte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !filterStrike {
|
if !filterStrike {
|
||||||
description = description + line
|
description += line
|
||||||
// Add new line, except for the last line.
|
// Add new line, except for the last line.
|
||||||
if i < descriptionLength-1 {
|
if i < descriptionLength-1 {
|
||||||
description = description + "\n"
|
description += "\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,7 +295,7 @@ func getArticles(feedURL string, max int, noExcerpt bool, filter []string, filte
|
||||||
// Only append article link if it is not yet contained in description (e.g. read more: URL).
|
// Only append article link if it is not yet contained in description (e.g. read more: URL).
|
||||||
if strings.Contains(description, article.Link) {
|
if strings.Contains(description, article.Link) {
|
||||||
// Replace article link with URL cleaned from redirects and trackers.
|
// Replace article link with URL cleaned from redirects and trackers.
|
||||||
description = strings.Replace(description, article.Link, cleanURL, -1)
|
description = strings.ReplaceAll(description, article.Link, cleanURL)
|
||||||
output = output + feed.Title + ": *" + article.Title + "*\n\n" + description
|
output = output + feed.Title + ": *" + article.Title + "*\n\n" + description
|
||||||
} else {
|
} else {
|
||||||
output = output + feed.Title + ": *" + article.Title + "*\n\n" + description + "\n" + cleanURL
|
output = output + feed.Title + ": *" + article.Title + "*\n\n" + description + "\n" + cleanURL
|
||||||
|
@ -301,7 +303,7 @@ func getArticles(feedURL string, max int, noExcerpt bool, filter []string, filte
|
||||||
}
|
}
|
||||||
|
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
output = output + "\n\n---\n\n"
|
output += "\n\n---\n\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
go.mod
6
go.mod
|
@ -22,7 +22,7 @@ require (
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||||
golang.org/x/crypto v0.27.0 // indirect
|
golang.org/x/crypto v0.28.0 // indirect
|
||||||
golang.org/x/net v0.29.0 // indirect
|
golang.org/x/net v0.30.0 // indirect
|
||||||
golang.org/x/text v0.18.0 // indirect
|
golang.org/x/text v0.19.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -42,8 +42,8 @@ github.com/xmppo/go-xmpp v0.2.2/go.mod h1:0ZxTwt7zQQbRkVg9PpBISmGAjmxf+oik0JyAah
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
@ -51,8 +51,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -72,8 +72,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
|
|
@ -62,12 +62,13 @@ func openConfig(configFilePtr *string) configuration {
|
||||||
|
|
||||||
// Read configuration file into variable config.
|
// Read configuration file into variable config.
|
||||||
file, _ := os.Open(configFile)
|
file, _ := os.Open(configFile)
|
||||||
defer file.Close()
|
|
||||||
decoder := json.NewDecoder(file)
|
decoder := json.NewDecoder(file)
|
||||||
config := configuration{}
|
config := configuration{}
|
||||||
if err := decoder.Decode(&config); err != nil {
|
if err := decoder.Decode(&config); err != nil {
|
||||||
|
file.Close()
|
||||||
log.Fatal("Error: Can't decode config: ", err)
|
log.Fatal("Error: Can't decode config: ", err)
|
||||||
}
|
}
|
||||||
|
file.Close()
|
||||||
|
|
||||||
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
||||||
err = os.MkdirAll(configPath, 0o700)
|
err = os.MkdirAll(configPath, 0o700)
|
||||||
|
|
|
@ -24,8 +24,9 @@ func processStanzas(client *xmpp.Client, muc string, mucNick string, feeds []str
|
||||||
case xmpp.Chat:
|
case xmpp.Chat:
|
||||||
var command string
|
var command string
|
||||||
|
|
||||||
|
switch v.Type {
|
||||||
// Check for room mention of the bots nick if the the message type is groupchat.
|
// Check for room mention of the bots nick if the the message type is groupchat.
|
||||||
if v.Type == "groupchat" {
|
case "groupchat":
|
||||||
// Leave if option quiet is set.
|
// Leave if option quiet is set.
|
||||||
if quiet {
|
if quiet {
|
||||||
break
|
break
|
||||||
|
@ -52,9 +53,9 @@ func processStanzas(client *xmpp.Client, muc string, mucNick string, feeds []str
|
||||||
command = strings.ToLower(strings.Split(v.Text, " ")[1])
|
command = strings.ToLower(strings.Split(v.Text, " ")[1])
|
||||||
// If the message type is chat (e.g. private message), the command is the
|
// If the message type is chat (e.g. private message), the command is the
|
||||||
// first word.
|
// first word.
|
||||||
} else if v.Type == "chat" {
|
case "chat":
|
||||||
command = strings.ToLower(strings.Split(v.Text, " ")[0])
|
command = strings.ToLower(strings.Split(v.Text, " ")[0])
|
||||||
} else {
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,8 +205,9 @@ func processStanzas(client *xmpp.Client, muc string, mucNick string, feeds []str
|
||||||
|
|
||||||
if v.Type == "get" {
|
if v.Type == "get" {
|
||||||
// Reply to disco#info requests according to https://xmpp.org/extensions/xep-0030.html.
|
// Reply to disco#info requests according to https://xmpp.org/extensions/xep-0030.html.
|
||||||
if strings.Contains(string(v.Query),
|
switch {
|
||||||
"<query xmlns='http://jabber.org/protocol/disco#info'/>") {
|
case strings.Contains(string(v.Query),
|
||||||
|
"<query xmlns='http://jabber.org/protocol/disco#info'/>"):
|
||||||
_, err := client.RawInformation(client.JID(), v.From, v.ID,
|
_, err := client.RawInformation(client.JID(), v.From, v.ID,
|
||||||
"result", "<query xmlns='http://jabber.org/protocol/disco#info'>"+
|
"result", "<query xmlns='http://jabber.org/protocol/disco#info'>"+
|
||||||
"<identity category='client' type='bot' name='feedbot'/>"+
|
"<identity category='client' type='bot' name='feedbot'/>"+
|
||||||
|
@ -213,13 +215,13 @@ func processStanzas(client *xmpp.Client, muc string, mucNick string, feeds []str
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error: Failed to reply to disco#info:", err)
|
log.Fatal("Error: Failed to reply to disco#info:", err)
|
||||||
}
|
}
|
||||||
} else if strings.Contains(string(v.Query), "<ping xmlns='urn:xmpp:ping'/>") {
|
case strings.Contains(string(v.Query), "<ping xmlns='urn:xmpp:ping'/>"):
|
||||||
// Reply to pings.
|
// Reply to pings.
|
||||||
_, err := client.RawInformation(client.JID(), v.From, v.ID, "result", "")
|
_, err := client.RawInformation(client.JID(), v.From, v.ID, "result", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error: Failed to reply to ping:", err)
|
log.Fatal("Error: Failed to reply to ping:", err)
|
||||||
}
|
}
|
||||||
} else {
|
default:
|
||||||
// Send error replies for all other IQs.
|
// Send error replies for all other IQs.
|
||||||
_, err := client.RawInformation(client.JID(), v.From, v.ID, "error",
|
_, err := client.RawInformation(client.JID(), v.From, v.ID, "error",
|
||||||
"<error type='cancel'><service-unavailable "+
|
"<error type='cancel'><service-unavailable "+
|
||||||
|
|
Loading…
Reference in a new issue