From 94f7437ad2b3b4e596f1b867846cfa836508ed98 Mon Sep 17 00:00:00 2001 From: Dmitry Verkhoturov Date: Wed, 14 Jul 2021 23:27:07 +0200 Subject: [PATCH] move item-related functions from proc to feed module --- app/feed/item.go | 45 +++++++++++++++++++++++++++ app/feed/item_test.go | 64 +++++++++++++++++++++++++++++++++++++++ app/feed/parser.go | 18 ----------- app/proc/telegram.go | 25 ++------------- app/proc/telegram_test.go | 55 --------------------------------- 5 files changed, 112 insertions(+), 95 deletions(-) create mode 100644 app/feed/item.go create mode 100644 app/feed/item_test.go diff --git a/app/feed/item.go b/app/feed/item.go new file mode 100644 index 00000000..db106e9d --- /dev/null +++ b/app/feed/item.go @@ -0,0 +1,45 @@ +package feed + +import ( + "html/template" + "io" + "net/http" + "path" + "time" +) + +// Item for rss +type Item struct { + // Required + Title string `xml:"title"` + Link string `xml:"link"` + Description template.HTML `xml:"description"` + // Optional + Content template.HTML `xml:"encoded"` + PubDate string `xml:"pubDate"` + Comments string `xml:"comments"` + Enclosure Enclosure `xml:"enclosure"` + GUID string `xml:"guid"` + + // Internal + DT time.Time `xml:"-"` + Junk bool `xml:"-"` +} + +// DownloadAudio return httpBody for Item's Enclosure.URL +func (item Item) DownloadAudio(timeout time.Duration) (io.ReadCloser, error) { + clientHTTP := &http.Client{Timeout: timeout} + + resp, err := clientHTTP.Get(item.Enclosure.URL) + if err != nil { + return nil, err + } + + return resp.Body, nil +} + +// GetFilename returns the filename for Item's Enclosure.URL +func (item Item) GetFilename() string { + _, filename := path.Split(item.Enclosure.URL) + return filename +} diff --git a/app/feed/item_test.go b/app/feed/item_test.go new file mode 100644 index 00000000..505eeebf --- /dev/null +++ b/app/feed/item_test.go @@ -0,0 +1,64 @@ +package feed + +import ( + "fmt" + "net/http" + "net/http/httptest" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestGetFilename(t *testing.T) { + tbl := []struct { + url, expected string + }{ + {"https://example.com/100500/song.mp3", "song.mp3"}, + {"https://example.com//song.mp3", "song.mp3"}, + {"https://example.com/song.mp3", "song.mp3"}, + {"https://example.com/song.mp3/", ""}, + {"https://example.com/", ""}, + } + + for i, tt := range tbl { + i := i + tt := tt + t.Run(strconv.Itoa(i), func(t *testing.T) { + item := Item{Enclosure: Enclosure{URL: tt.url}} + fname := item.GetFilename() + assert.Equal(t, tt.expected, fname) + }) + } +} + +func TestDownloadAudioIfRequestError(t *testing.T) { + var ts *httptest.Server + ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ts.CloseClientConnections() + })) + + defer ts.Close() + + item := Item{Enclosure: Enclosure{URL: ts.URL}} + got, err := item.DownloadAudio(time.Minute) + + assert.Nil(t, got) + assert.EqualError(t, err, fmt.Sprintf("Get %q: EOF", ts.URL)) +} + +func TestDownloadAudio(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Length", "4") + fmt.Fprint(w, "abcd") + })) + defer ts.Close() + + item := Item{Enclosure: Enclosure{URL: ts.URL}} + got, err := item.DownloadAudio(time.Minute) + + assert.NotNil(t, got) + assert.Nil(t, err) +} diff --git a/app/feed/parser.go b/app/feed/parser.go index 5e168ee5..a7725655 100644 --- a/app/feed/parser.go +++ b/app/feed/parser.go @@ -32,24 +32,6 @@ type Rss2 struct { ItemList []Item `xml:"channel>item"` } -// Item for rss -type Item struct { - // Required - Title string `xml:"title"` - Link string `xml:"link"` - Description template.HTML `xml:"description"` - // Optional - Content template.HTML `xml:"encoded"` - PubDate string `xml:"pubDate"` - Comments string `xml:"comments"` - Enclosure Enclosure `xml:"enclosure"` - GUID string `xml:"guid"` - - // Internal - DT time.Time `xml:"-"` - Junk bool `xml:"-"` -} - // Enclosure element from item type Enclosure struct { URL string `xml:"url,attr"` diff --git a/app/proc/telegram.go b/app/proc/telegram.go index 0d4b73a3..bc93fd28 100644 --- a/app/proc/telegram.go +++ b/app/proc/telegram.go @@ -3,16 +3,15 @@ package proc import ( "bytes" "fmt" - "github.com/tcolgate/mp3" "io" "net/http" - "path" "strings" "time" log "github.com/go-pkgz/lgr" "github.com/microcosm-cc/bluemonday" "github.com/pkg/errors" + "github.com/tcolgate/mp3" "golang.org/x/net/html" tb "gopkg.in/tucnak/telebot.v2" @@ -85,7 +84,7 @@ func (client TelegramClient) sendText(channelID string, item feed.Item) (*tb.Mes } func (client TelegramClient) sendAudio(channelID string, item feed.Item) (*tb.Message, error) { - httpBody, err := client.downloadAudio(item.Enclosure.URL) + httpBody, err := item.DownloadAudio(client.Timeout) if err != nil { return nil, err } @@ -96,7 +95,7 @@ func (client TelegramClient) sendAudio(channelID string, item feed.Item) (*tb.Me audio := tb.Audio{ File: tb.FromReader(&httpBodyCopy), - FileName: client.getFilenameByURL(item.Enclosure.URL), + FileName: item.GetFilename(), MIME: "audio/mpeg", Caption: client.getMessageHTML(item, false), Title: item.Title, @@ -114,19 +113,6 @@ func (client TelegramClient) sendAudio(channelID string, item feed.Item) (*tb.Me return message, err } -func (client TelegramClient) downloadAudio(url string) (io.ReadCloser, error) { - clientHTTP := &http.Client{Timeout: client.Timeout * time.Second} - - resp, err := clientHTTP.Get(url) - if err != nil { - return nil, err - } - - log.Printf("[DEBUG] start download audio: %s", url) - - return resp.Body, err -} - // https://core.telegram.org/bots/api#html-style func (client TelegramClient) tagLinkOnlySupport(htmlText string) string { p := bluemonday.NewPolicy() @@ -164,11 +150,6 @@ func (client TelegramClient) getMessageHTML(item feed.Item, withMp3Link bool) st return messageHTML } -func (client TelegramClient) getFilenameByURL(url string) string { - _, filename := path.Split(url) - return filename -} - // duration scans MP3 file from provided io.Reader and returns it's duration in seconds, ignoring possible errors func (client TelegramClient) duration(r io.Reader) int { d := mp3.NewDecoder(r) diff --git a/app/proc/telegram_test.go b/app/proc/telegram_test.go index 0bd3cb1d..8405140c 100644 --- a/app/proc/telegram_test.go +++ b/app/proc/telegram_test.go @@ -2,9 +2,6 @@ package proc import ( "bytes" - "fmt" - "net/http" - "net/http/httptest" "strconv" "testing" "testing/iotest" @@ -164,58 +161,6 @@ func TestRecipientChannelIDNotStartWithAt(t *testing.T) { } } -func TestGetFilenameByURL(t *testing.T) { - tbl := []struct { - url, expected string - }{ - {"https://example.com/100500/song.mp3", "song.mp3"}, - {"https://example.com//song.mp3", "song.mp3"}, - {"https://example.com/song.mp3", "song.mp3"}, - {"https://example.com/song.mp3/", ""}, - {"https://example.com/", ""}, - } - - for i, tt := range tbl { - i := i - tt := tt - t.Run(strconv.Itoa(i), func(t *testing.T) { - client := TelegramClient{} - fname := client.getFilenameByURL(tt.url) - assert.Equal(t, tt.expected, fname) - }) - } -} - -func TestDownloadAudioIfRequestError(t *testing.T) { - var ts *httptest.Server - ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ts.CloseClientConnections() - })) - - defer ts.Close() - - client := TelegramClient{} - got, err := client.downloadAudio(ts.URL) - - assert.Nil(t, got) - assert.EqualError(t, err, fmt.Sprintf("Get %q: EOF", ts.URL)) -} - -func TestDownloadAudio(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Header().Set("Content-Length", "4") - fmt.Fprint(w, "abcd") - })) - defer ts.Close() - - client := TelegramClient{} - got, err := client.downloadAudio(ts.URL) - - assert.NotNil(t, got) - assert.NoError(t, err) -} - func TestDurationBadReader(t *testing.T) { r := iotest.ErrReader(bytes.ErrTooLarge) client := TelegramClient{}