added scheduling & media upload
This commit is contained in:
parent
f5c1694211
commit
3c23a975da
7 changed files with 431 additions and 7 deletions
58
README.md
58
README.md
|
|
@ -31,6 +31,10 @@ You can use this library to get tweets, profiles, and trends trivially.
|
||||||
- [Get trends](#get-trends)
|
- [Get trends](#get-trends)
|
||||||
- [Get following](#get-following)
|
- [Get following](#get-following)
|
||||||
- [Get followers](#get-followers)
|
- [Get followers](#get-followers)
|
||||||
|
- [Get scheduled tweets](#get-scheduled-tweets)
|
||||||
|
- [Create scheduled tweet](#create-scheduled-tweet)
|
||||||
|
- [Delete scheduled tweet](#delete-scheduled-tweet)
|
||||||
|
- [Upload media](#upload-media)
|
||||||
- [Connection](#connection)
|
- [Connection](#connection)
|
||||||
- [Proxy](#proxy)
|
- [Proxy](#proxy)
|
||||||
- [HTTP(s)](#https)
|
- [HTTP(s)](#https)
|
||||||
|
|
@ -345,7 +349,7 @@ trends, err := scraper.GetTrends()
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
var cursor string
|
var cursor string
|
||||||
users, cursor, err := testScraper.FetchFollowing("Support", 20, cursor)
|
users, cursor, err := scraper.FetchFollowing("Support", 20, cursor)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Get followers
|
### Get followers
|
||||||
|
|
@ -357,7 +361,57 @@ users, cursor, err := testScraper.FetchFollowing("Support", 20, cursor)
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
var cursor string
|
var cursor string
|
||||||
users, cursor, err := testScraper.FetchFollowers("Support", 20, cursor)
|
users, cursor, err := scraper.FetchFollowers("Support", 20, cursor)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get scheduled tweets
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Requires authentication!
|
||||||
|
|
||||||
|
500 requests / 15 minutes
|
||||||
|
|
||||||
|
```golang
|
||||||
|
tweets, err := scraper.FetchScheduledTweets()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create scheduled tweet
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Requires authentication!
|
||||||
|
|
||||||
|
500 requests / 15 minutes
|
||||||
|
|
||||||
|
```golang
|
||||||
|
tweets, err := scraper.CreateScheduledTweet(twitterscraper.TweetSchedule{
|
||||||
|
Text: "New scheduled tweet text",
|
||||||
|
Date: time.Now().Add(time.Hour * 24 * 31),
|
||||||
|
Medias: nil,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Delete scheduled tweet
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Requires authentication!
|
||||||
|
|
||||||
|
500 requests / 15 minutes
|
||||||
|
|
||||||
|
```golang
|
||||||
|
err := scraper.DeleteScheduledTweet("123")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Upload media
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Requires authentication!
|
||||||
|
|
||||||
|
50 requests / 15 minutes
|
||||||
|
|
||||||
|
Uploads photo, video or gif for further posting or scheduling. Expires in 24 hours if not used.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
media, err := scraper.UploadMedia("./files/movie.mp4")
|
||||||
```
|
```
|
||||||
|
|
||||||
## Connection
|
## Connection
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -3,6 +3,7 @@ module github.com/imperatrona/twitter-scraper
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/AlexEidt/Vidio v1.5.1 // indirect
|
||||||
github.com/google/go-cmp v0.5.9
|
github.com/google/go-cmp v0.5.9
|
||||||
golang.org/x/net v0.17.0
|
golang.org/x/net v0.17.0
|
||||||
)
|
)
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -1,3 +1,5 @@
|
||||||
|
github.com/AlexEidt/Vidio v1.5.1 h1:tovwvtgQagUz1vifiL9OeWkg1fP/XUzFazFKh7tFtaE=
|
||||||
|
github.com/AlexEidt/Vidio v1.5.1/go.mod h1:djhIMnWMqPrC3X6nB6ymGX6uWWlgw+VayYGKE1bNwmI=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
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=
|
||||||
|
|
|
||||||
25
schedule.go
25
schedule.go
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -109,6 +110,12 @@ type scheduleTweets struct {
|
||||||
} `json:"data"`
|
} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TweetSchedule struct {
|
||||||
|
Text string
|
||||||
|
Date time.Time
|
||||||
|
Medias []*Media
|
||||||
|
}
|
||||||
|
|
||||||
func (timeline *scheduleTweets) parseTweets() []*ScheduledTweet {
|
func (timeline *scheduleTweets) parseTweets() []*ScheduledTweet {
|
||||||
var tweets []*ScheduledTweet
|
var tweets []*ScheduledTweet
|
||||||
|
|
||||||
|
|
@ -185,8 +192,8 @@ func (s *Scraper) DeleteScheduledTweet(id string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateScheduledTweet schedule new tweet.
|
// CreateScheduledTweet schedule new tweet.
|
||||||
func (s *Scraper) CreateScheduledTweet(text string, date time.Time) (string, error) {
|
func (s *Scraper) CreateScheduledTweet(schedule TweetSchedule) (string, error) {
|
||||||
if date.Unix() <= time.Now().Unix() {
|
if schedule.Date.Unix() <= time.Now().Unix() {
|
||||||
return "", errors.New("date can't be in past")
|
return "", errors.New("date can't be in past")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,14 +206,24 @@ func (s *Scraper) CreateScheduledTweet(text string, date time.Time) (string, err
|
||||||
|
|
||||||
post_tweet_request := map[string]interface{}{
|
post_tweet_request := map[string]interface{}{
|
||||||
"auto_populate_reply_metadata": false,
|
"auto_populate_reply_metadata": false,
|
||||||
"status": text,
|
"status": schedule.Text,
|
||||||
"exclude_reply_user_ids": []string{},
|
"exclude_reply_user_ids": []string{},
|
||||||
"media_ids": []string{},
|
"media_ids": []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(schedule.Medias) > 0 {
|
||||||
|
var media_ids []string
|
||||||
|
|
||||||
|
for _, media := range schedule.Medias {
|
||||||
|
media_ids = append(media_ids, strconv.Itoa(media.ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
post_tweet_request["media_ids"] = media_ids
|
||||||
|
}
|
||||||
|
|
||||||
variables := map[string]interface{}{
|
variables := map[string]interface{}{
|
||||||
"post_tweet_request": post_tweet_request,
|
"post_tweet_request": post_tweet_request,
|
||||||
"execute_at": date.Unix(),
|
"execute_at": schedule.Date.Unix(),
|
||||||
}
|
}
|
||||||
|
|
||||||
body := map[string]interface{}{
|
body := map[string]interface{}{
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
twitterscraper "github.com/imperatrona/twitter-scraper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFetchScheduledTweets(t *testing.T) {
|
func TestFetchScheduledTweets(t *testing.T) {
|
||||||
|
|
@ -27,7 +29,12 @@ func TestCreateScheduledTweets(t *testing.T) {
|
||||||
t.Skip("Skipping test due to environment variable")
|
t.Skip("Skipping test due to environment variable")
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
id, err = testScraper.CreateScheduledTweet("new tweet", time.Now().Add(time.Hour*24*31))
|
|
||||||
|
id, err = testScraper.CreateScheduledTweet(twitterscraper.TweetSchedule{
|
||||||
|
Text: "new tweet",
|
||||||
|
Date: time.Now().Add(time.Hour * 24 * 31),
|
||||||
|
Medias: nil,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
230
upload.go
Normal file
230
upload.go
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
package twitterscraper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
vidio "github.com/AlexEidt/Vidio"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Media struct {
|
||||||
|
ID int
|
||||||
|
Type string
|
||||||
|
Size int
|
||||||
|
Parts int
|
||||||
|
ExpiresAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type uploadInitResponse struct {
|
||||||
|
ID int `json:"media_id"`
|
||||||
|
ExpiresAfter int `json:"expires_after_secs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessingInfo struct {
|
||||||
|
State string `json:"state"`
|
||||||
|
CheckAfter int `json:"check_after_secs"`
|
||||||
|
Progress int `json:"progress_percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type uploadStatusResponse struct {
|
||||||
|
ProcessingInfo ProcessingInfo `json:"processing_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uploads photo, video or gif for further posting or scheduling. Expires in 24 hours if not used.
|
||||||
|
func (s *Scraper) UploadMedia(filePath string) (*Media, error) {
|
||||||
|
fileContent, err := os.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
media, err := s.uploadInit(filePath, fileContent)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.uploadAppend(media, fileContent)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var status *ProcessingInfo
|
||||||
|
|
||||||
|
status, err = s.uploadFinalize(media)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(media.Type, "image") {
|
||||||
|
return media, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for status.State != "succeeded" {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
status, err = s.uploadStatus(media)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return media, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scraper) uploadInit(filePath string, fileContent []byte) (*Media, error) {
|
||||||
|
var (
|
||||||
|
videoDuration float64
|
||||||
|
fileType string
|
||||||
|
mediaCategory = "tweet_"
|
||||||
|
)
|
||||||
|
|
||||||
|
fileType = http.DetectContentType(fileContent)
|
||||||
|
|
||||||
|
if fileType == "image/jpeg" || fileType == "image/png" {
|
||||||
|
mediaCategory += "image"
|
||||||
|
} else if fileType == "image/gif" {
|
||||||
|
mediaCategory += "gif"
|
||||||
|
} else if fileType == "video/mp4" || fileType == "video/quicktime" {
|
||||||
|
mediaCategory += "video"
|
||||||
|
|
||||||
|
video, err := vidio.NewVideo(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
videoDuration = video.Duration()
|
||||||
|
video.Close()
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("file type %s unsupported by twitter, make sure you uploading photo, video or gif", fileType)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.newRequest("POST", "https://upload.twitter.com/i/media/upload.json")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := url.Values{}
|
||||||
|
query.Set("command", "INIT")
|
||||||
|
query.Set("total_bytes", strconv.Itoa(len(fileContent)))
|
||||||
|
query.Set("media_type", fileType)
|
||||||
|
query.Set("media_category", mediaCategory)
|
||||||
|
if mediaCategory == "tweet_video" {
|
||||||
|
query.Set("video_duration_ms", strconv.FormatFloat(videoDuration*1000, 'f', -1, 64))
|
||||||
|
}
|
||||||
|
req.URL.RawQuery = query.Encode()
|
||||||
|
req.Header.Set("Origin", "https://twitter.com")
|
||||||
|
req.Header.Set("Referer", "https://twitter.com/")
|
||||||
|
|
||||||
|
var uploadInit uploadInitResponse
|
||||||
|
|
||||||
|
err = s.RequestAPI(req, &uploadInit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Media{
|
||||||
|
ID: uploadInit.ID,
|
||||||
|
Type: fileType,
|
||||||
|
Size: len(fileContent),
|
||||||
|
ExpiresAt: time.Now().Add(time.Duration(uploadInit.ExpiresAfter) * time.Second),
|
||||||
|
Parts: len(fileContent) / 2_000_000,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scraper) uploadAppend(media *Media, fileContent []byte) error {
|
||||||
|
for i := 0; i <= media.Parts; i++ {
|
||||||
|
var partData []byte
|
||||||
|
|
||||||
|
if i+1 <= media.Parts {
|
||||||
|
partData = fileContent[i*2_000_000 : (i+1)*2_000_000]
|
||||||
|
} else {
|
||||||
|
partData = fileContent[i*2_000_000:]
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
w := multipart.NewWriter(&buf)
|
||||||
|
fw, err := w.CreateFormFile("media", "blob")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err = io.Copy(fw, bytes.NewReader(partData)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
req, err := s.newRequest("POST", "https://upload.twitter.com/i/media/upload.json")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := url.Values{}
|
||||||
|
query.Set("command", "APPEND")
|
||||||
|
query.Set("media_id", strconv.Itoa(media.ID))
|
||||||
|
query.Set("segment_index", strconv.Itoa(i))
|
||||||
|
req.URL.RawQuery = query.Encode()
|
||||||
|
req.Header.Set("Content-Type", w.FormDataContentType())
|
||||||
|
req.Header.Set("Origin", "https://twitter.com")
|
||||||
|
req.Header.Set("Referer", "https://twitter.com/")
|
||||||
|
req.Body = io.NopCloser(&buf)
|
||||||
|
|
||||||
|
err = s.RequestAPI(req, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scraper) uploadFinalize(media *Media) (*ProcessingInfo, error) {
|
||||||
|
req, err := s.newRequest("POST", "https://upload.twitter.com/i/media/upload.json")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := url.Values{}
|
||||||
|
query.Set("command", "FINALIZE")
|
||||||
|
query.Set("media_id", strconv.Itoa(media.ID))
|
||||||
|
query.Set("allow_async", "true")
|
||||||
|
req.URL.RawQuery = query.Encode()
|
||||||
|
req.Header.Set("Origin", "https://twitter.com")
|
||||||
|
req.Header.Set("Referer", "https://twitter.com/")
|
||||||
|
|
||||||
|
var response uploadStatusResponse
|
||||||
|
|
||||||
|
err = s.RequestAPI(req, &response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response.ProcessingInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scraper) uploadStatus(media *Media) (*ProcessingInfo, error) {
|
||||||
|
req, err := s.newRequest("GET", "https://upload.twitter.com/i/media/upload.json")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := url.Values{}
|
||||||
|
query.Set("command", "STATUS")
|
||||||
|
query.Set("media_id", strconv.Itoa(media.ID))
|
||||||
|
req.URL.RawQuery = query.Encode()
|
||||||
|
req.Header.Set("Origin", "https://twitter.com")
|
||||||
|
req.Header.Set("Referer", "https://twitter.com/")
|
||||||
|
|
||||||
|
var response uploadStatusResponse
|
||||||
|
|
||||||
|
err = s.RequestAPI(req, &response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response.ProcessingInfo, nil
|
||||||
|
}
|
||||||
113
upload_test.go
Normal file
113
upload_test.go
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
package twitterscraper_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPhotoUpload(t *testing.T) {
|
||||||
|
if skipAuthTest {
|
||||||
|
t.Skip("Skipping test due to environment variable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create temp file
|
||||||
|
f, err := os.CreateTemp("", "tmp_*.png")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
defer os.Remove(f.Name())
|
||||||
|
|
||||||
|
resp, err := http.Get("https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(f, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
media, err := testScraper.UploadMedia(f.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if media.ID == 0 {
|
||||||
|
t.Error("Media ID shouldn't be 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVideoUpload(t *testing.T) {
|
||||||
|
if skipAuthTest {
|
||||||
|
t.Skip("Skipping test due to environment variable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create temp file
|
||||||
|
f, err := os.CreateTemp("", "tmp_*.mp4")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
defer os.Remove(f.Name())
|
||||||
|
|
||||||
|
resp, err := http.Get("https://github.com/chthomos/video-media-samples/raw/master/big-buck-bunny-480p-30sec.mp4")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(f, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
media, err := testScraper.UploadMedia(f.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if media.ID == 0 {
|
||||||
|
t.Error("Media ID shouldn't be 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGifUpload(t *testing.T) {
|
||||||
|
if skipAuthTest {
|
||||||
|
t.Skip("Skipping test due to environment variable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create temp file
|
||||||
|
f, err := os.CreateTemp("", "tmp_*.gif")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
defer os.Remove(f.Name())
|
||||||
|
|
||||||
|
resp, err := http.Get("https://i.giphy.com/dNKC0e3QFNPZC.gif")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(f, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
media, err := testScraper.UploadMedia(f.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if media.ID == 0 {
|
||||||
|
t.Error("Media ID shouldn't be 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue