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