From 315df7d9162edb69571e2a877953097f8c431669 Mon Sep 17 00:00:00 2001 From: Masahiro Furudate <178inaba.git@gmail.com> Date: Mon, 27 Jul 2020 02:03:29 +0900 Subject: [PATCH] Add Media struct and UploadMediaFromMedia method --- mastodon.go | 48 ++++-------------------------- status.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 84 insertions(+), 48 deletions(-) diff --git a/mastodon.go b/mastodon.go index bd35202..d642cf3 100644 --- a/mastodon.go +++ b/mastodon.go @@ -2,18 +2,14 @@ package mastodon import ( - "bytes" "context" "encoding/json" "errors" "fmt" "io" - "mime/multipart" "net/http" "net/url" - "os" "path" - "path/filepath" "strings" "time" @@ -58,52 +54,18 @@ func (c *Client) doAPI(ctx context.Context, method string, uri string, params in if err != nil { return err } - } else if file, ok := params.(string); ok { - f, err := os.Open(file) + } else if media, ok := params.(*Media); ok { + r, contentType, err := media.bodyAndContentType() if err != nil { return err } - defer f.Close() - var buf bytes.Buffer - mw := multipart.NewWriter(&buf) - part, err := mw.CreateFormFile("file", filepath.Base(file)) + req, err = http.NewRequest(method, u.String(), r) if err != nil { return err } - _, err = io.Copy(part, f) - if err != nil { - return err - } - err = mw.Close() - if err != nil { - return err - } - req, err = http.NewRequest(method, u.String(), &buf) - if err != nil { - return err - } - ct = mw.FormDataContentType() - } else if reader, ok := params.(io.Reader); ok { - var buf bytes.Buffer - mw := multipart.NewWriter(&buf) - part, err := mw.CreateFormFile("file", "upload") - if err != nil { - return err - } - _, err = io.Copy(part, reader) - if err != nil { - return err - } - err = mw.Close() - if err != nil { - return err - } - req, err = http.NewRequest(method, u.String(), &buf) - if err != nil { - return err - } - ct = mw.FormDataContentType() + + ct = contentType } else { if method == http.MethodGet && pg != nil { u.RawQuery = pg.toValues().Encode() diff --git a/status.go b/status.go index e0d955f..0ca9a97 100644 --- a/status.go +++ b/status.go @@ -1,11 +1,15 @@ package mastodon import ( + "bytes" "context" "fmt" "io" + "mime/multipart" "net/http" "net/url" + "os" + "strings" "time" ) @@ -70,6 +74,71 @@ type Conversation struct { LastStatus *Status `json:"last_status"` } +// Media is struct to hold media. +type Media struct { + File io.Reader + Thumbnail io.Reader + Description string + Focus string +} + +func (m *Media) bodyAndContentType() (io.Reader, string, error) { + var buf bytes.Buffer + mw := multipart.NewWriter(&buf) + + fileName := "upload" + if f, ok := m.File.(*os.File); ok { + fileName = f.Name() + } + file, err := mw.CreateFormFile("file", fileName) + if err != nil { + return nil, "", err + } + if _, err := io.Copy(file, m.File); err != nil { + return nil, "", err + } + + if m.Thumbnail != nil { + thumbName := "upload" + if f, ok := m.Thumbnail.(*os.File); ok { + thumbName = f.Name() + } + thumb, err := mw.CreateFormFile("thumbnail", thumbName) + if err != nil { + return nil, "", err + } + if _, err := io.Copy(thumb, m.Thumbnail); err != nil { + return nil, "", err + } + } + + if m.Description != "" { + desc, err := mw.CreateFormField("description") + if err != nil { + return nil, "", err + } + if _, err := io.Copy(desc, strings.NewReader(m.Description)); err != nil { + return nil, "", err + } + } + + if m.Focus != "" { + focus, err := mw.CreateFormField("focus") + if err != nil { + return nil, "", err + } + if _, err := io.Copy(focus, strings.NewReader(m.Focus)); err != nil { + return nil, "", err + } + } + + if err := mw.Close(); err != nil { + return nil, "", err + } + + return &buf, mw.FormDataContentType(), nil +} + // GetFavourites return the favorite list of the current user. func (c *Client) GetFavourites(ctx context.Context, pg *Pagination) ([]*Status, error) { var statuses []*Status @@ -287,19 +356,24 @@ func (c *Client) Search(ctx context.Context, q string, resolve bool) (*Results, // UploadMedia upload a media attachment from a file. func (c *Client) UploadMedia(ctx context.Context, file string) (*Attachment, error) { - var attachment Attachment - err := c.doAPI(ctx, http.MethodPost, "/api/v1/media", file, &attachment, nil) + f, err := os.Open(file) if err != nil { return nil, err } - return &attachment, nil + defer f.Close() + + return c.UploadMediaFromMedia(ctx, &Media{File: f}) } // UploadMediaFromReader uploads a media attachment from a io.Reader. func (c *Client) UploadMediaFromReader(ctx context.Context, reader io.Reader) (*Attachment, error) { + return c.UploadMediaFromMedia(ctx, &Media{File: reader}) +} + +// UploadMediaFromMedia uploads a media attachment from a Media struct. +func (c *Client) UploadMediaFromMedia(ctx context.Context, media *Media) (*Attachment, error) { var attachment Attachment - err := c.doAPI(ctx, http.MethodPost, "/api/v1/media", reader, &attachment, nil) - if err != nil { + if err := c.doAPI(ctx, http.MethodPost, "/api/v1/media", media, &attachment, nil); err != nil { return nil, err } return &attachment, nil