Add initial version
This commit is contained in:
commit
c8681ba96c
|
@ -0,0 +1 @@
|
||||||
|
.idea/
|
|
@ -0,0 +1,13 @@
|
||||||
|
FROM golang:1.14-alpine as build
|
||||||
|
ADD . /app
|
||||||
|
WORKDIR /app
|
||||||
|
RUN go build
|
||||||
|
|
||||||
|
FROM alpine:3.11
|
||||||
|
RUN apk add --no-cache tzdata ca-certificates
|
||||||
|
COPY --from=build /app/JsonFeedToTelegram /bin/
|
||||||
|
WORKDIR /app
|
||||||
|
VOLUME /app/storage
|
||||||
|
EXPOSE 8080
|
||||||
|
ENV LAST_ARTICLE_FILE /app/storage/lastarticle
|
||||||
|
CMD ["JsonFeedToTelegram"]
|
|
@ -0,0 +1,35 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Article struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func LatestArticle(url string) (*Article, error) {
|
||||||
|
jsonFeed := &struct {
|
||||||
|
Items []Article `json:"items"`
|
||||||
|
}{}
|
||||||
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to create req to get json feed")
|
||||||
|
}
|
||||||
|
req.Header.Add("User-Agent", "JsonFeedToTelegram")
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to get json feed")
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&jsonFeed)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to parse json feed")
|
||||||
|
}
|
||||||
|
if len(jsonFeed.Items) < 1 {
|
||||||
|
return nil, errors.New("no articles in feed")
|
||||||
|
}
|
||||||
|
return &jsonFeed.Items[0], nil
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
lastArticleFile, lastArticleFileSet := os.LookupEnv("LAST_ARTICLE_FILE")
|
||||||
|
feed, feedSet := os.LookupEnv("FEED")
|
||||||
|
botToken, botTokenSet := os.LookupEnv("BOT_TOKEN")
|
||||||
|
channel, channelSet := os.LookupEnv("CHANNEL")
|
||||||
|
if lastArticleFileSet && feedSet && botTokenSet && channelSet {
|
||||||
|
telegram := Telegram{botToken: botToken, channel: channel}
|
||||||
|
http.HandleFunc("/hook", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Wrong HTTP method", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("Fetch feed: ", time.Now().Format(time.RFC3339))
|
||||||
|
article, err := LatestArticle(feed)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if lastArticle := lastArticleUrl(lastArticleFile); lastArticle != article.Url {
|
||||||
|
err = telegram.Post(createMessage(article))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = updateLastArticleUrl(lastArticleFile, article.Url)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http.Error(w, errors.New("no new article").Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||||
|
} else {
|
||||||
|
log.Fatal("Not configured")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lastArticleUrl(filename string) string {
|
||||||
|
fileContent, _ := ioutil.ReadFile(filename)
|
||||||
|
return string(fileContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLastArticleUrl(filename, url string) error {
|
||||||
|
return ioutil.WriteFile(filename, []byte(url), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createMessage(article *Article) string {
|
||||||
|
var message bytes.Buffer
|
||||||
|
message.WriteString("🔔 Something new was published")
|
||||||
|
message.WriteString("\n\n")
|
||||||
|
if article.Title != "" {
|
||||||
|
message.WriteString(article.Title)
|
||||||
|
message.WriteString("\n\n")
|
||||||
|
}
|
||||||
|
message.WriteString(article.Url)
|
||||||
|
return message.String()
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Telegram struct {
|
||||||
|
channel string
|
||||||
|
botToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
var telegramBaseUrl = "https://api.telegram.org/bot"
|
||||||
|
|
||||||
|
func (t *Telegram) Post(message string) error {
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("chat_id", t.channel)
|
||||||
|
params.Add("text", message)
|
||||||
|
tgUrl, err := url.Parse(telegramBaseUrl + t.botToken + "/sendMessage")
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to create Telegram request")
|
||||||
|
}
|
||||||
|
tgUrl.RawQuery = params.Encode()
|
||||||
|
req, _ := http.NewRequest(http.MethodPost, tgUrl.String(), nil)
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil || resp.StatusCode != 200 {
|
||||||
|
return errors.New("failed to send Telegram message")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Reference in New Issue