b6110d577ff2b3186660eeec1e83a13d488d1ff3
[bloat] / mastodon / status.go
1 package mastodon
2
3 import (
4         "context"
5         "fmt"
6         "io"
7         "mime/multipart"
8         "net/http"
9         "net/url"
10         "time"
11 )
12
13 // Status is struct to hold status.
14 type Status struct {
15         ID                 string       `json:"id"`
16         URI                string       `json:"uri"`
17         URL                string       `json:"url"`
18         Account            Account      `json:"account"`
19         InReplyToID        interface{}  `json:"in_reply_to_id"`
20         InReplyToAccountID interface{}  `json:"in_reply_to_account_id"`
21         Reblog             *Status      `json:"reblog"`
22         Content            string       `json:"content"`
23         CreatedAt          time.Time    `json:"created_at"`
24         Emojis             []Emoji      `json:"emojis"`
25         RepliesCount       int64        `json:"replies_count"`
26         ReblogsCount       int64        `json:"reblogs_count"`
27         FavouritesCount    int64        `json:"favourites_count"`
28         Reblogged          interface{}  `json:"reblogged"`
29         Favourited         interface{}  `json:"favourited"`
30         Muted              interface{}  `json:"muted"`
31         Sensitive          bool         `json:"sensitive"`
32         SpoilerText        string       `json:"spoiler_text"`
33         Visibility         string       `json:"visibility"`
34         MediaAttachments   []Attachment `json:"media_attachments"`
35         Mentions           []Mention    `json:"mentions"`
36         Tags               []Tag        `json:"tags"`
37         Card               *Card        `json:"card"`
38         Application        Application  `json:"application"`
39         Language           string       `json:"language"`
40         Pinned             interface{}  `json:"pinned"`
41 }
42
43 // Context hold information for mastodon context.
44 type Context struct {
45         Ancestors   []*Status `json:"ancestors"`
46         Descendants []*Status `json:"descendants"`
47 }
48
49 // Card hold information for mastodon card.
50 type Card struct {
51         URL          string `json:"url"`
52         Title        string `json:"title"`
53         Description  string `json:"description"`
54         Image        string `json:"image"`
55         Type         string `json:"type"`
56         AuthorName   string `json:"author_name"`
57         AuthorURL    string `json:"author_url"`
58         ProviderName string `json:"provider_name"`
59         ProviderURL  string `json:"provider_url"`
60         HTML         string `json:"html"`
61         Width        int64  `json:"width"`
62         Height       int64  `json:"height"`
63 }
64
65 // GetFavourites return the favorite list of the current user.
66 func (c *Client) GetFavourites(ctx context.Context, pg *Pagination) ([]*Status, error) {
67         var statuses []*Status
68         err := c.doAPI(ctx, http.MethodGet, "/api/v1/favourites", nil, &statuses, pg)
69         if err != nil {
70                 return nil, err
71         }
72         return statuses, nil
73 }
74
75 // GetStatus return status specified by id.
76 func (c *Client) GetStatus(ctx context.Context, id string) (*Status, error) {
77         var status Status
78         err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%s", id), nil, &status, nil)
79         if err != nil {
80                 return nil, err
81         }
82         return &status, nil
83 }
84
85 // GetStatusContext return status specified by id.
86 func (c *Client) GetStatusContext(ctx context.Context, id string) (*Context, error) {
87         var context Context
88         err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%s/context", id), nil, &context, nil)
89         if err != nil {
90                 return nil, err
91         }
92         return &context, nil
93 }
94
95 // GetStatusCard return status specified by id.
96 func (c *Client) GetStatusCard(ctx context.Context, id string) (*Card, error) {
97         var card Card
98         err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%s/card", id), nil, &card, nil)
99         if err != nil {
100                 return nil, err
101         }
102         return &card, nil
103 }
104
105 // GetRebloggedBy returns the account list of the user who reblogged the toot of id.
106 func (c *Client) GetRebloggedBy(ctx context.Context, id string, pg *Pagination) ([]*Account, error) {
107         var accounts []*Account
108         err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%s/reblogged_by", id), nil, &accounts, pg)
109         if err != nil {
110                 return nil, err
111         }
112         return accounts, nil
113 }
114
115 // GetFavouritedBy returns the account list of the user who liked the toot of id.
116 func (c *Client) GetFavouritedBy(ctx context.Context, id string, pg *Pagination) ([]*Account, error) {
117         var accounts []*Account
118         err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%s/favourited_by", id), nil, &accounts, pg)
119         if err != nil {
120                 return nil, err
121         }
122         return accounts, nil
123 }
124
125 // Reblog is reblog the toot of id and return status of reblog.
126 func (c *Client) Reblog(ctx context.Context, id string) (*Status, error) {
127         var status Status
128         err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%s/reblog", id), nil, &status, nil)
129         if err != nil {
130                 return nil, err
131         }
132         return &status, nil
133 }
134
135 // Unreblog is unreblog the toot of id and return status of the original toot.
136 func (c *Client) Unreblog(ctx context.Context, id string) (*Status, error) {
137         var status Status
138         err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%s/unreblog", id), nil, &status, nil)
139         if err != nil {
140                 return nil, err
141         }
142         return &status, nil
143 }
144
145 // Favourite is favourite the toot of id and return status of the favourite toot.
146 func (c *Client) Favourite(ctx context.Context, id string) (*Status, error) {
147         var status Status
148         err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%s/favourite", id), nil, &status, nil)
149         if err != nil {
150                 return nil, err
151         }
152         return &status, nil
153 }
154
155 // Unfavourite is unfavourite the toot of id and return status of the unfavourite toot.
156 func (c *Client) Unfavourite(ctx context.Context, id string) (*Status, error) {
157         var status Status
158         err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%s/unfavourite", id), nil, &status, nil)
159         if err != nil {
160                 return nil, err
161         }
162         return &status, nil
163 }
164
165 // GetTimelineHome return statuses from home timeline.
166 func (c *Client) GetTimelineHome(ctx context.Context, pg *Pagination) ([]*Status, error) {
167         var statuses []*Status
168         err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/home", nil, &statuses, pg)
169         if err != nil {
170                 return nil, err
171         }
172         return statuses, nil
173 }
174
175 // GetTimelinePublic return statuses from public timeline.
176 func (c *Client) GetTimelinePublic(ctx context.Context, isLocal bool, pg *Pagination) ([]*Status, error) {
177         params := url.Values{}
178         if isLocal {
179                 params.Set("local", "t")
180         }
181
182         var statuses []*Status
183         err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/public", params, &statuses, pg)
184         if err != nil {
185                 return nil, err
186         }
187         return statuses, nil
188 }
189
190 // GetTimelineHashtag return statuses from tagged timeline.
191 func (c *Client) GetTimelineHashtag(ctx context.Context, tag string, isLocal bool, pg *Pagination) ([]*Status, error) {
192         params := url.Values{}
193         if isLocal {
194                 params.Set("local", "t")
195         }
196
197         var statuses []*Status
198         err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/timelines/tag/%s", url.PathEscape(tag)), params, &statuses, pg)
199         if err != nil {
200                 return nil, err
201         }
202         return statuses, nil
203 }
204
205 // GetTimelineList return statuses from a list timeline.
206 func (c *Client) GetTimelineList(ctx context.Context, id string, pg *Pagination) ([]*Status, error) {
207         var statuses []*Status
208         err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/timelines/list/%s", url.PathEscape(string(id))), nil, &statuses, pg)
209         if err != nil {
210                 return nil, err
211         }
212         return statuses, nil
213 }
214
215 // GetTimelineMedia return statuses from media timeline.
216 // NOTE: This is an experimental feature of pawoo.net.
217 func (c *Client) GetTimelineMedia(ctx context.Context, isLocal bool, pg *Pagination) ([]*Status, error) {
218         params := url.Values{}
219         params.Set("media", "t")
220         if isLocal {
221                 params.Set("local", "t")
222         }
223
224         var statuses []*Status
225         err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/public", params, &statuses, pg)
226         if err != nil {
227                 return nil, err
228         }
229         return statuses, nil
230 }
231
232 // PostStatus post the toot.
233 func (c *Client) PostStatus(ctx context.Context, toot *Toot) (*Status, error) {
234         params := url.Values{}
235         params.Set("status", toot.Status)
236         if toot.InReplyToID != "" {
237                 params.Set("in_reply_to_id", string(toot.InReplyToID))
238         }
239         if toot.MediaIDs != nil {
240                 for _, media := range toot.MediaIDs {
241                         params.Add("media_ids[]", string(media))
242                 }
243         }
244         if toot.Visibility != "" {
245                 params.Set("visibility", fmt.Sprint(toot.Visibility))
246         }
247         if toot.Sensitive {
248                 params.Set("sensitive", "true")
249         }
250         if toot.SpoilerText != "" {
251                 params.Set("spoiler_text", toot.SpoilerText)
252         }
253
254         var status Status
255         err := c.doAPI(ctx, http.MethodPost, "/api/v1/statuses", params, &status, nil)
256         if err != nil {
257                 return nil, err
258         }
259         return &status, nil
260 }
261
262 // DeleteStatus delete the toot.
263 func (c *Client) DeleteStatus(ctx context.Context, id string) error {
264         return c.doAPI(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/statuses/%s", id), nil, nil, nil)
265 }
266
267 // Search search content with query.
268 func (c *Client) Search(ctx context.Context, q string, resolve bool) (*Results, error) {
269         params := url.Values{}
270         params.Set("q", q)
271         params.Set("resolve", fmt.Sprint(resolve))
272         var results Results
273         err := c.doAPI(ctx, http.MethodGet, "/api/v1/search", params, &results, nil)
274         if err != nil {
275                 return nil, err
276         }
277         return &results, nil
278 }
279
280 // UploadMedia upload a media attachment from a file.
281 func (c *Client) UploadMedia(ctx context.Context, file string) (*Attachment, error) {
282         var attachment Attachment
283         err := c.doAPI(ctx, http.MethodPost, "/api/v1/media", file, &attachment, nil)
284         if err != nil {
285                 return nil, err
286         }
287         return &attachment, nil
288 }
289
290 // UploadMediaFromReader uploads a media attachment from a io.Reader.
291 func (c *Client) UploadMediaFromReader(ctx context.Context, reader io.Reader) (*Attachment, error) {
292         var attachment Attachment
293         err := c.doAPI(ctx, http.MethodPost, "/api/v1/media", reader, &attachment, nil)
294         if err != nil {
295                 return nil, err
296         }
297         return &attachment, nil
298 }
299
300 // UploadMediaFromReader uploads a media attachment from a io.Reader.
301 func (c *Client) UploadMediaFromMultipartFileHeader(ctx context.Context, fh *multipart.FileHeader) (*Attachment, error) {
302         var attachment Attachment
303         err := c.doAPI(ctx, http.MethodPost, "/api/v1/media", fh, &attachment, nil)
304         if err != nil {
305                 return nil, err
306         }
307         return &attachment, nil
308 }