OSDN Git Service

2eff94165d24bd2115b8173ec76b6a82ae4f944b
[opentween/open-tween.git] / OpenTween / Api / TwitterApi.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2016 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
4 //
5 // This file is part of OpenTween.
6 //
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
10 // any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 // for more details.
16 //
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
21
22 using System;
23 using System.Collections.Generic;
24 using System.Linq;
25 using System.Text;
26 using System.Threading;
27 using System.Threading.Tasks;
28 using OpenTween.Api.DataModel;
29 using OpenTween.Connection;
30
31 namespace OpenTween.Api
32 {
33     public sealed class TwitterApi : IDisposable
34     {
35         public long CurrentUserId { get; private set; }
36         public string CurrentScreenName { get; private set; }
37
38         internal IApiConnection apiConnection;
39
40         public void Initialize(string accessToken, string accessSecret, long userId, string screenName)
41         {
42             var newInstance = new TwitterApiConnection(accessToken, accessSecret);
43             var oldInstance = Interlocked.Exchange(ref this.apiConnection, newInstance);
44             oldInstance?.Dispose();
45
46             this.CurrentUserId = userId;
47             this.CurrentScreenName = screenName;
48         }
49
50         public Task<TwitterStatus[]> StatusesHomeTimeline(int? count = null, long? maxId = null, long? sinceId = null)
51         {
52             var endpoint = new Uri("statuses/home_timeline.json", UriKind.Relative);
53             var param = new Dictionary<string, string>
54             {
55                 ["include_entities"] = "true",
56                 ["include_ext_alt_text"] = "true",
57             };
58
59             if (count != null)
60                 param["count"] = count.ToString();
61             if (maxId != null)
62                 param["max_id"] = maxId.ToString();
63             if (sinceId != null)
64                 param["since_id"] = sinceId.ToString();
65
66             return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/statuses/home_timeline");
67         }
68
69         public Task<TwitterStatus[]> StatusesMentionsTimeline(int? count = null, long? maxId = null, long? sinceId = null)
70         {
71             var endpoint = new Uri("statuses/mentions_timeline.json", UriKind.Relative);
72             var param = new Dictionary<string, string>
73             {
74                 ["include_entities"] = "true",
75                 ["include_ext_alt_text"] = "true",
76             };
77
78             if (count != null)
79                 param["count"] = count.ToString();
80             if (maxId != null)
81                 param["max_id"] = maxId.ToString();
82             if (sinceId != null)
83                 param["since_id"] = sinceId.ToString();
84
85             return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/statuses/mentions_timeline");
86         }
87
88         public Task<TwitterStatus[]> StatusesUserTimeline(string screenName, int? count = null, long? maxId = null, long? sinceId = null)
89         {
90             var endpoint = new Uri("statuses/user_timeline.json", UriKind.Relative);
91             var param = new Dictionary<string, string>
92             {
93                 ["screen_name"] = screenName,
94                 ["include_rts"] = "true",
95                 ["include_entities"] = "true",
96                 ["include_ext_alt_text"] = "true",
97             };
98
99             if (count != null)
100                 param["count"] = count.ToString();
101             if (maxId != null)
102                 param["max_id"] = maxId.ToString();
103             if (sinceId != null)
104                 param["since_id"] = sinceId.ToString();
105
106             return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/statuses/user_timeline");
107         }
108
109         public Task<TwitterStatus> StatusesShow(long statusId)
110         {
111             var endpoint = new Uri("statuses/show.json", UriKind.Relative);
112             var param = new Dictionary<string, string>
113             {
114                 ["id"] = statusId.ToString(),
115                 ["include_entities"] = "true",
116                 ["include_ext_alt_text"] = "true",
117             };
118
119             return this.apiConnection.GetAsync<TwitterStatus>(endpoint, param, "/statuses/show/:id");
120         }
121
122         public Task<LazyJson<TwitterStatus>> StatusesUpdate(string status, long? replyToId, IReadOnlyList<long> mediaIds)
123         {
124             var endpoint = new Uri("statuses/update.json", UriKind.Relative);
125             var param = new Dictionary<string, string>
126             {
127                 ["status"] = status,
128                 ["include_entities"] = "true",
129                 ["include_ext_alt_text"] = "true",
130             };
131
132             if (replyToId != null)
133                 param["in_reply_to_status_id"] = replyToId.ToString();
134             if (mediaIds != null && mediaIds.Count > 0)
135                 param.Add("media_ids", string.Join(",", mediaIds));
136
137             return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
138         }
139
140         public Task<LazyJson<TwitterStatus>> StatusesDestroy(long statusId)
141         {
142             var endpoint = new Uri("statuses/destroy.json", UriKind.Relative);
143             var param = new Dictionary<string, string>
144             {
145                 ["id"] = statusId.ToString(),
146             };
147
148             return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
149         }
150
151         public Task<LazyJson<TwitterStatus>> StatusesRetweet(long statusId)
152         {
153             var endpoint = new Uri("statuses/retweet.json", UriKind.Relative);
154             var param = new Dictionary<string, string>
155             {
156                 ["id"] = statusId.ToString(),
157                 ["include_entities"] = "true",
158                 ["include_ext_alt_text"] = "true",
159             };
160
161             return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
162         }
163
164         public Task<TwitterStatus[]> ListsStatuses(long listId, int? count = null, long? maxId = null, long? sinceId = null, bool? includeRTs = null)
165         {
166             var endpoint = new Uri("lists/statuses.json", UriKind.Relative);
167             var param = new Dictionary<string, string>
168             {
169                 ["list_id"] = listId.ToString(),
170                 ["include_entities"] = "true",
171                 ["include_ext_alt_text"] = "true",
172             };
173
174             if (count != null)
175                 param["count"] = count.ToString();
176             if (maxId != null)
177                 param["max_id"] = maxId.ToString();
178             if (sinceId != null)
179                 param["since_id"] = sinceId.ToString();
180             if (includeRTs != null)
181                 param["include_rts"] = includeRTs.Value ? "true" : "false";
182
183             return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/lists/statuses");
184         }
185
186         public Task<LazyJson<TwitterDirectMessage>> DirectMessagesNew(string status, string sendTo)
187         {
188             var endpoint = new Uri("direct_messages/new.json", UriKind.Relative);
189             var param = new Dictionary<string, string>
190             {
191                 ["text"] = status,
192                 ["screen_name"] = sendTo,
193             };
194
195             return this.apiConnection.PostLazyAsync<TwitterDirectMessage>(endpoint, param);
196         }
197
198         public Task<LazyJson<TwitterDirectMessage>> DirectMessagesDestroy(long statusId)
199         {
200             var endpoint = new Uri("direct_messages/destroy.json", UriKind.Relative);
201             var param = new Dictionary<string, string>
202             {
203                 ["id"] = statusId.ToString(),
204             };
205
206             return this.apiConnection.PostLazyAsync<TwitterDirectMessage>(endpoint, param);
207         }
208
209         public Task<TwitterUser> UsersShow(string screenName)
210         {
211             var endpoint = new Uri("users/show.json", UriKind.Relative);
212             var param = new Dictionary<string, string>
213             {
214                 ["screen_name"] = screenName,
215                 ["include_entities"] = "true",
216                 ["include_ext_alt_text"] = "true",
217             };
218
219             return this.apiConnection.GetAsync<TwitterUser>(endpoint, param, "/users/show/:id");
220         }
221
222         public Task<LazyJson<TwitterUser>> UsersReportSpam(string screenName)
223         {
224             var endpoint = new Uri("users/report_spam.json", UriKind.Relative);
225             var param = new Dictionary<string, string>
226             {
227                 ["screen_name"] = screenName,
228             };
229
230             return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
231         }
232
233         public Task<LazyJson<TwitterStatus>> FavoritesCreate(long statusId)
234         {
235             var endpoint = new Uri("favorites/create.json", UriKind.Relative);
236             var param = new Dictionary<string, string>
237             {
238                 ["id"] = statusId.ToString(),
239             };
240
241             return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
242         }
243
244         public Task<LazyJson<TwitterStatus>> FavoritesDestroy(long statusId)
245         {
246             var endpoint = new Uri("favorites/destroy.json", UriKind.Relative);
247             var param = new Dictionary<string, string>
248             {
249                 ["id"] = statusId.ToString(),
250             };
251
252             return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
253         }
254
255         public Task<TwitterFriendship> FriendshipsShow(string sourceScreenName, string targetScreenName)
256         {
257             var endpoint = new Uri("friendships/show.json", UriKind.Relative);
258             var param = new Dictionary<string, string>
259             {
260                 ["source_screen_name"] = sourceScreenName,
261                 ["target_screen_name"] = targetScreenName,
262             };
263
264             return this.apiConnection.GetAsync<TwitterFriendship>(endpoint, param, "/friendships/show");
265         }
266
267         public Task<LazyJson<TwitterFriendship>> FriendshipsCreate(string screenName)
268         {
269             var endpoint = new Uri("friendships/create.json", UriKind.Relative);
270             var param = new Dictionary<string, string>
271             {
272                 ["screen_name"] = screenName,
273             };
274
275             return this.apiConnection.PostLazyAsync<TwitterFriendship>(endpoint, param);
276         }
277
278         public Task<LazyJson<TwitterFriendship>> FriendshipsDestroy(string screenName)
279         {
280             var endpoint = new Uri("friendships/destroy.json", UriKind.Relative);
281             var param = new Dictionary<string, string>
282             {
283                 ["screen_name"] = screenName,
284             };
285
286             return this.apiConnection.PostLazyAsync<TwitterFriendship>(endpoint, param);
287         }
288
289         public Task<long[]> NoRetweetIds(long? cursor = null)
290         {
291             var endpoint = new Uri("friendships/no_retweets/ids.json", UriKind.Relative);
292
293             return this.apiConnection.GetAsync<long[]>(endpoint, null, "/friendships/no_retweets/ids");
294         }
295
296         public Task<TwitterIds> FollowersIds(long? cursor = null)
297         {
298             var endpoint = new Uri("followers/ids.json", UriKind.Relative);
299             var param = new Dictionary<string, string>();
300
301             if (cursor != null)
302                 param["cursor"] = cursor.ToString();
303
304             return this.apiConnection.GetAsync<TwitterIds>(endpoint, param, "/followers/ids");
305         }
306
307         public Task<TwitterIds> MutesUsersIds(long? cursor = null)
308         {
309             var endpoint = new Uri("mutes/users/ids.json", UriKind.Relative);
310             var param = new Dictionary<string, string>();
311
312             if (cursor != null)
313                 param["cursor"] = cursor.ToString();
314
315             return this.apiConnection.GetAsync<TwitterIds>(endpoint, param, "/mutes/users/ids");
316         }
317
318         public Task<TwitterIds> BlocksIds(long? cursor = null)
319         {
320             var endpoint = new Uri("blocks/ids.json", UriKind.Relative);
321             var param = new Dictionary<string, string>();
322
323             if (cursor != null)
324                 param["cursor"] = cursor.ToString();
325
326             return this.apiConnection.GetAsync<TwitterIds>(endpoint, param, "/blocks/ids");
327         }
328
329         public Task<LazyJson<TwitterUser>> BlocksCreate(string screenName)
330         {
331             var endpoint = new Uri("blocks/create.json", UriKind.Relative);
332             var param = new Dictionary<string, string>
333             {
334                 ["screen_name"] = screenName,
335             };
336
337             return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
338         }
339
340         public Task<LazyJson<TwitterUser>> BlocksDestroy(string screenName)
341         {
342             var endpoint = new Uri("blocks/destroy.json", UriKind.Relative);
343             var param = new Dictionary<string, string>
344             {
345                 ["screen_name"] = screenName,
346             };
347
348             return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
349         }
350
351         public Task<LazyJson<TwitterUser>> AccountUpdateProfile(string name, string url, string location, string description)
352         {
353             var endpoint = new Uri("account/update_profile.json", UriKind.Relative);
354             var param = new Dictionary<string, string>
355             {
356                 ["include_entities"] = "true",
357                 ["include_ext_alt_text"] = "true",
358             };
359
360             if (name != null)
361                 param["name"] = name;
362             if (url != null)
363                 param["url"] = url;
364             if (location != null)
365                 param["location"] = location;
366
367             if (description != null)
368             {
369                 // name, location, description に含まれる < > " の文字はTwitter側で除去されるが、
370                 // twitter.com の挙動では description でのみ &lt; 等の文字参照を使って表示することができる
371                 var escapedDescription = description.Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "&quot;");
372                 param["description"] = escapedDescription;
373             }
374
375             return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
376         }
377
378         public Task<LazyJson<TwitterUser>> AccountUpdateProfileImage(IMediaItem image)
379         {
380             var endpoint = new Uri("account/update_profile_image.json", UriKind.Relative);
381             var param = new Dictionary<string, string>
382             {
383                 ["include_entities"] = "true",
384                 ["include_ext_alt_text"] = "true",
385             };
386             var paramMedia = new Dictionary<string, IMediaItem>
387             {
388                 ["image"] = image,
389             };
390
391             return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param, paramMedia);
392         }
393
394         public Task<TwitterConfiguration> Configuration()
395         {
396             var endpoint = new Uri("help/configuration.json", UriKind.Relative);
397
398             return this.apiConnection.GetAsync<TwitterConfiguration>(endpoint, null, "/help/configuration");
399         }
400
401         public Task<LazyJson<TwitterUploadMediaResult>> MediaUpload(IMediaItem media)
402         {
403             var endpoint = new Uri("https://upload.twitter.com/1.1/media/upload.json");
404             var paramMedia = new Dictionary<string, IMediaItem>
405             {
406                 ["media"] = media,
407             };
408
409             return this.apiConnection.PostLazyAsync<TwitterUploadMediaResult>(endpoint, null, paramMedia);
410         }
411
412         public void Dispose()
413         {
414             this.apiConnection?.Dispose();
415         }
416     }
417 }