1 // OpenTween - Client of Twitter
2 // Copyright (c) 2016 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
5 // This file is part of OpenTween.
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)
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
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.
23 using System.Collections.Generic;
27 using System.Threading;
28 using System.Threading.Tasks;
29 using OpenTween.Api.DataModel;
30 using OpenTween.Connection;
32 namespace OpenTween.Api
34 public sealed class TwitterApi : IDisposable
36 public long CurrentUserId { get; private set; }
37 public string CurrentScreenName { get; private set; }
39 public IApiConnection Connection => this.apiConnection;
41 internal IApiConnection apiConnection;
43 public void Initialize(string accessToken, string accessSecret, long userId, string screenName)
45 var newInstance = new TwitterApiConnection(accessToken, accessSecret);
46 var oldInstance = Interlocked.Exchange(ref this.apiConnection, newInstance);
47 oldInstance?.Dispose();
49 this.CurrentUserId = userId;
50 this.CurrentScreenName = screenName;
53 public Task<TwitterStatus[]> StatusesHomeTimeline(int? count = null, long? maxId = null, long? sinceId = null)
55 var endpoint = new Uri("statuses/home_timeline.json", UriKind.Relative);
56 var param = new Dictionary<string, string>
58 ["include_entities"] = "true",
59 ["include_ext_alt_text"] = "true",
63 param["count"] = count.ToString();
65 param["max_id"] = maxId.ToString();
67 param["since_id"] = sinceId.ToString();
69 return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/statuses/home_timeline");
72 public Task<TwitterStatus[]> StatusesMentionsTimeline(int? count = null, long? maxId = null, long? sinceId = null)
74 var endpoint = new Uri("statuses/mentions_timeline.json", UriKind.Relative);
75 var param = new Dictionary<string, string>
77 ["include_entities"] = "true",
78 ["include_ext_alt_text"] = "true",
82 param["count"] = count.ToString();
84 param["max_id"] = maxId.ToString();
86 param["since_id"] = sinceId.ToString();
88 return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/statuses/mentions_timeline");
91 public Task<TwitterStatus[]> StatusesUserTimeline(string screenName, int? count = null, long? maxId = null, long? sinceId = null)
93 var endpoint = new Uri("statuses/user_timeline.json", UriKind.Relative);
94 var param = new Dictionary<string, string>
96 ["screen_name"] = screenName,
97 ["include_rts"] = "true",
98 ["include_entities"] = "true",
99 ["include_ext_alt_text"] = "true",
103 param["count"] = count.ToString();
105 param["max_id"] = maxId.ToString();
107 param["since_id"] = sinceId.ToString();
109 return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/statuses/user_timeline");
112 public Task<TwitterStatus> StatusesShow(long statusId)
114 var endpoint = new Uri("statuses/show.json", UriKind.Relative);
115 var param = new Dictionary<string, string>
117 ["id"] = statusId.ToString(),
118 ["include_entities"] = "true",
119 ["include_ext_alt_text"] = "true",
122 return this.apiConnection.GetAsync<TwitterStatus>(endpoint, param, "/statuses/show/:id");
125 public Task<LazyJson<TwitterStatus>> StatusesUpdate(string status, long? replyToId, IReadOnlyList<long> mediaIds)
127 var endpoint = new Uri("statuses/update.json", UriKind.Relative);
128 var param = new Dictionary<string, string>
131 ["include_entities"] = "true",
132 ["include_ext_alt_text"] = "true",
135 if (replyToId != null)
136 param["in_reply_to_status_id"] = replyToId.ToString();
137 if (mediaIds != null && mediaIds.Count > 0)
138 param.Add("media_ids", string.Join(",", mediaIds));
140 return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
143 public Task<LazyJson<TwitterStatus>> StatusesDestroy(long statusId)
145 var endpoint = new Uri("statuses/destroy.json", UriKind.Relative);
146 var param = new Dictionary<string, string>
148 ["id"] = statusId.ToString(),
151 return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
154 public Task<LazyJson<TwitterStatus>> StatusesRetweet(long statusId)
156 var endpoint = new Uri("statuses/retweet.json", UriKind.Relative);
157 var param = new Dictionary<string, string>
159 ["id"] = statusId.ToString(),
160 ["include_entities"] = "true",
161 ["include_ext_alt_text"] = "true",
164 return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
167 public Task<TwitterStatus[]> ListsStatuses(long listId, int? count = null, long? maxId = null, long? sinceId = null, bool? includeRTs = null)
169 var endpoint = new Uri("lists/statuses.json", UriKind.Relative);
170 var param = new Dictionary<string, string>
172 ["list_id"] = listId.ToString(),
173 ["include_entities"] = "true",
174 ["include_ext_alt_text"] = "true",
178 param["count"] = count.ToString();
180 param["max_id"] = maxId.ToString();
182 param["since_id"] = sinceId.ToString();
183 if (includeRTs != null)
184 param["include_rts"] = includeRTs.Value ? "true" : "false";
186 return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/lists/statuses");
189 public Task<TwitterDirectMessage[]> DirectMessagesRecv(int? count = null, long? maxId = null, long? sinceId = null)
191 var endpoint = new Uri("direct_messages.json", UriKind.Relative);
192 var param = new Dictionary<string, string>
194 ["full_text"] = "true",
195 ["include_entities"] = "true",
196 ["include_ext_alt_text"] = "true",
200 param["count"] = count.ToString();
202 param["max_id"] = maxId.ToString();
204 param["since_id"] = sinceId.ToString();
206 return this.apiConnection.GetAsync<TwitterDirectMessage[]>(endpoint, param, "/direct_messages");
209 public Task<TwitterDirectMessage[]> DirectMessagesSent(int? count = null, long? maxId = null, long? sinceId = null)
211 var endpoint = new Uri("direct_messages/sent.json", UriKind.Relative);
212 var param = new Dictionary<string, string>
214 ["full_text"] = "true",
215 ["include_entities"] = "true",
216 ["include_ext_alt_text"] = "true",
220 param["count"] = count.ToString();
222 param["max_id"] = maxId.ToString();
224 param["since_id"] = sinceId.ToString();
226 return this.apiConnection.GetAsync<TwitterDirectMessage[]>(endpoint, param, "/direct_messages/sent");
229 public Task<LazyJson<TwitterDirectMessage>> DirectMessagesNew(string status, string sendTo)
231 var endpoint = new Uri("direct_messages/new.json", UriKind.Relative);
232 var param = new Dictionary<string, string>
235 ["screen_name"] = sendTo,
238 return this.apiConnection.PostLazyAsync<TwitterDirectMessage>(endpoint, param);
241 public Task<LazyJson<TwitterDirectMessage>> DirectMessagesDestroy(long statusId)
243 var endpoint = new Uri("direct_messages/destroy.json", UriKind.Relative);
244 var param = new Dictionary<string, string>
246 ["id"] = statusId.ToString(),
249 return this.apiConnection.PostLazyAsync<TwitterDirectMessage>(endpoint, param);
252 public Task<TwitterUser> UsersShow(string screenName)
254 var endpoint = new Uri("users/show.json", UriKind.Relative);
255 var param = new Dictionary<string, string>
257 ["screen_name"] = screenName,
258 ["include_entities"] = "true",
259 ["include_ext_alt_text"] = "true",
262 return this.apiConnection.GetAsync<TwitterUser>(endpoint, param, "/users/show/:id");
265 public Task<LazyJson<TwitterUser>> UsersReportSpam(string screenName)
267 var endpoint = new Uri("users/report_spam.json", UriKind.Relative);
268 var param = new Dictionary<string, string>
270 ["screen_name"] = screenName,
273 return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
276 public Task<LazyJson<TwitterStatus>> FavoritesCreate(long statusId)
278 var endpoint = new Uri("favorites/create.json", UriKind.Relative);
279 var param = new Dictionary<string, string>
281 ["id"] = statusId.ToString(),
284 return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
287 public Task<LazyJson<TwitterStatus>> FavoritesDestroy(long statusId)
289 var endpoint = new Uri("favorites/destroy.json", UriKind.Relative);
290 var param = new Dictionary<string, string>
292 ["id"] = statusId.ToString(),
295 return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
298 public Task<TwitterFriendship> FriendshipsShow(string sourceScreenName, string targetScreenName)
300 var endpoint = new Uri("friendships/show.json", UriKind.Relative);
301 var param = new Dictionary<string, string>
303 ["source_screen_name"] = sourceScreenName,
304 ["target_screen_name"] = targetScreenName,
307 return this.apiConnection.GetAsync<TwitterFriendship>(endpoint, param, "/friendships/show");
310 public Task<LazyJson<TwitterFriendship>> FriendshipsCreate(string screenName)
312 var endpoint = new Uri("friendships/create.json", UriKind.Relative);
313 var param = new Dictionary<string, string>
315 ["screen_name"] = screenName,
318 return this.apiConnection.PostLazyAsync<TwitterFriendship>(endpoint, param);
321 public Task<LazyJson<TwitterFriendship>> FriendshipsDestroy(string screenName)
323 var endpoint = new Uri("friendships/destroy.json", UriKind.Relative);
324 var param = new Dictionary<string, string>
326 ["screen_name"] = screenName,
329 return this.apiConnection.PostLazyAsync<TwitterFriendship>(endpoint, param);
332 public Task<long[]> NoRetweetIds(long? cursor = null)
334 var endpoint = new Uri("friendships/no_retweets/ids.json", UriKind.Relative);
336 return this.apiConnection.GetAsync<long[]>(endpoint, null, "/friendships/no_retweets/ids");
339 public Task<TwitterIds> FollowersIds(long? cursor = null)
341 var endpoint = new Uri("followers/ids.json", UriKind.Relative);
342 var param = new Dictionary<string, string>();
345 param["cursor"] = cursor.ToString();
347 return this.apiConnection.GetAsync<TwitterIds>(endpoint, param, "/followers/ids");
350 public Task<TwitterIds> MutesUsersIds(long? cursor = null)
352 var endpoint = new Uri("mutes/users/ids.json", UriKind.Relative);
353 var param = new Dictionary<string, string>();
356 param["cursor"] = cursor.ToString();
358 return this.apiConnection.GetAsync<TwitterIds>(endpoint, param, "/mutes/users/ids");
361 public Task<TwitterIds> BlocksIds(long? cursor = null)
363 var endpoint = new Uri("blocks/ids.json", UriKind.Relative);
364 var param = new Dictionary<string, string>();
367 param["cursor"] = cursor.ToString();
369 return this.apiConnection.GetAsync<TwitterIds>(endpoint, param, "/blocks/ids");
372 public Task<LazyJson<TwitterUser>> BlocksCreate(string screenName)
374 var endpoint = new Uri("blocks/create.json", UriKind.Relative);
375 var param = new Dictionary<string, string>
377 ["screen_name"] = screenName,
380 return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
383 public Task<LazyJson<TwitterUser>> BlocksDestroy(string screenName)
385 var endpoint = new Uri("blocks/destroy.json", UriKind.Relative);
386 var param = new Dictionary<string, string>
388 ["screen_name"] = screenName,
391 return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
394 public Task<LazyJson<TwitterUser>> AccountUpdateProfile(string name, string url, string location, string description)
396 var endpoint = new Uri("account/update_profile.json", UriKind.Relative);
397 var param = new Dictionary<string, string>
399 ["include_entities"] = "true",
400 ["include_ext_alt_text"] = "true",
404 param["name"] = name;
407 if (location != null)
408 param["location"] = location;
410 if (description != null)
412 // name, location, description に含まれる < > " の文字はTwitter側で除去されるが、
413 // twitter.com の挙動では description でのみ < 等の文字参照を使って表示することができる
414 var escapedDescription = description.Replace("<", "<").Replace(">", ">").Replace("\"", """);
415 param["description"] = escapedDescription;
418 return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
421 public Task<LazyJson<TwitterUser>> AccountUpdateProfileImage(IMediaItem image)
423 var endpoint = new Uri("account/update_profile_image.json", UriKind.Relative);
424 var param = new Dictionary<string, string>
426 ["include_entities"] = "true",
427 ["include_ext_alt_text"] = "true",
429 var paramMedia = new Dictionary<string, IMediaItem>
434 return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param, paramMedia);
437 public Task<TwitterConfiguration> Configuration()
439 var endpoint = new Uri("help/configuration.json", UriKind.Relative);
441 return this.apiConnection.GetAsync<TwitterConfiguration>(endpoint, null, "/help/configuration");
444 public Task<LazyJson<TwitterUploadMediaResult>> MediaUpload(IMediaItem media)
446 var endpoint = new Uri("https://upload.twitter.com/1.1/media/upload.json");
447 var paramMedia = new Dictionary<string, IMediaItem>
452 return this.apiConnection.PostLazyAsync<TwitterUploadMediaResult>(endpoint, null, paramMedia);
455 public Task<Stream> UserStreams(string replies = null, string track = null)
457 var endpoint = new Uri("https://userstream.twitter.com/1.1/user.json");
458 var param = new Dictionary<string, string>();
461 param["replies"] = replies;
463 param["track"] = track;
465 return this.apiConnection.GetStreamAsync(endpoint, param);
468 public OAuthEchoHandler CreateOAuthEchoHandler(Uri authServiceProvider, Uri realm = null)
470 return ((TwitterApiConnection)this.apiConnection).CreateOAuthEchoHandler(authServiceProvider, realm);
473 public void Dispose()
475 this.apiConnection?.Dispose();