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;
26 using System.Threading;
27 using System.Threading.Tasks;
28 using OpenTween.Api.DataModel;
29 using OpenTween.Connection;
31 namespace OpenTween.Api
33 public sealed class TwitterApi : IDisposable
35 public long CurrentUserId { get; private set; }
36 public string CurrentScreenName { get; private set; }
38 internal IApiConnection apiConnection;
40 public void Initialize(string accessToken, string accessSecret, long userId, string screenName)
42 var newInstance = new TwitterApiConnection(accessToken, accessSecret);
43 var oldInstance = Interlocked.Exchange(ref this.apiConnection, newInstance);
44 oldInstance?.Dispose();
46 this.CurrentUserId = userId;
47 this.CurrentScreenName = screenName;
50 public Task<TwitterStatus[]> StatusesHomeTimeline(int? count = null, long? maxId = null, long? sinceId = null)
52 var endpoint = new Uri("statuses/home_timeline.json", UriKind.Relative);
53 var param = new Dictionary<string, string>
55 ["include_entities"] = "true",
56 ["include_ext_alt_text"] = "true",
60 param["count"] = count.ToString();
62 param["max_id"] = maxId.ToString();
64 param["since_id"] = sinceId.ToString();
66 return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/statuses/home_timeline");
69 public Task<TwitterStatus[]> StatusesMentionsTimeline(int? count = null, long? maxId = null, long? sinceId = null)
71 var endpoint = new Uri("statuses/mentions_timeline.json", UriKind.Relative);
72 var param = new Dictionary<string, string>
74 ["include_entities"] = "true",
75 ["include_ext_alt_text"] = "true",
79 param["count"] = count.ToString();
81 param["max_id"] = maxId.ToString();
83 param["since_id"] = sinceId.ToString();
85 return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/statuses/mentions_timeline");
88 public Task<TwitterStatus[]> StatusesUserTimeline(string screenName, int? count = null, long? maxId = null, long? sinceId = null)
90 var endpoint = new Uri("statuses/user_timeline.json", UriKind.Relative);
91 var param = new Dictionary<string, string>
93 ["screen_name"] = screenName,
94 ["include_rts"] = "true",
95 ["include_entities"] = "true",
96 ["include_ext_alt_text"] = "true",
100 param["count"] = count.ToString();
102 param["max_id"] = maxId.ToString();
104 param["since_id"] = sinceId.ToString();
106 return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/statuses/user_timeline");
109 public Task<TwitterStatus> StatusesShow(long statusId)
111 var endpoint = new Uri("statuses/show.json", UriKind.Relative);
112 var param = new Dictionary<string, string>
114 ["id"] = statusId.ToString(),
115 ["include_entities"] = "true",
116 ["include_ext_alt_text"] = "true",
119 return this.apiConnection.GetAsync<TwitterStatus>(endpoint, param, "/statuses/show/:id");
122 public Task<LazyJson<TwitterStatus>> StatusesUpdate(string status, long? replyToId, IReadOnlyList<long> mediaIds)
124 var endpoint = new Uri("statuses/update.json", UriKind.Relative);
125 var param = new Dictionary<string, string>
128 ["include_entities"] = "true",
129 ["include_ext_alt_text"] = "true",
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));
137 return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
140 public Task<LazyJson<TwitterStatus>> StatusesDestroy(long statusId)
142 var endpoint = new Uri("statuses/destroy.json", UriKind.Relative);
143 var param = new Dictionary<string, string>
145 ["id"] = statusId.ToString(),
148 return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
151 public Task<LazyJson<TwitterStatus>> StatusesRetweet(long statusId)
153 var endpoint = new Uri("statuses/retweet.json", UriKind.Relative);
154 var param = new Dictionary<string, string>
156 ["id"] = statusId.ToString(),
157 ["include_entities"] = "true",
158 ["include_ext_alt_text"] = "true",
161 return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
164 public Task<TwitterStatus[]> ListsStatuses(long listId, int? count = null, long? maxId = null, long? sinceId = null, bool? includeRTs = null)
166 var endpoint = new Uri("lists/statuses.json", UriKind.Relative);
167 var param = new Dictionary<string, string>
169 ["list_id"] = listId.ToString(),
170 ["include_entities"] = "true",
171 ["include_ext_alt_text"] = "true",
175 param["count"] = count.ToString();
177 param["max_id"] = maxId.ToString();
179 param["since_id"] = sinceId.ToString();
180 if (includeRTs != null)
181 param["include_rts"] = includeRTs.Value ? "true" : "false";
183 return this.apiConnection.GetAsync<TwitterStatus[]>(endpoint, param, "/lists/statuses");
186 public Task<LazyJson<TwitterDirectMessage>> DirectMessagesNew(string status, string sendTo)
188 var endpoint = new Uri("direct_messages/new.json", UriKind.Relative);
189 var param = new Dictionary<string, string>
192 ["screen_name"] = sendTo,
195 return this.apiConnection.PostLazyAsync<TwitterDirectMessage>(endpoint, param);
198 public Task<LazyJson<TwitterDirectMessage>> DirectMessagesDestroy(long statusId)
200 var endpoint = new Uri("direct_messages/destroy.json", UriKind.Relative);
201 var param = new Dictionary<string, string>
203 ["id"] = statusId.ToString(),
206 return this.apiConnection.PostLazyAsync<TwitterDirectMessage>(endpoint, param);
209 public Task<TwitterUser> UsersShow(string screenName)
211 var endpoint = new Uri("users/show.json", UriKind.Relative);
212 var param = new Dictionary<string, string>
214 ["screen_name"] = screenName,
215 ["include_entities"] = "true",
216 ["include_ext_alt_text"] = "true",
219 return this.apiConnection.GetAsync<TwitterUser>(endpoint, param, "/users/show/:id");
222 public Task<LazyJson<TwitterUser>> UsersReportSpam(string screenName)
224 var endpoint = new Uri("users/report_spam.json", UriKind.Relative);
225 var param = new Dictionary<string, string>
227 ["screen_name"] = screenName,
230 return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
233 public Task<LazyJson<TwitterStatus>> FavoritesCreate(long statusId)
235 var endpoint = new Uri("favorites/create.json", UriKind.Relative);
236 var param = new Dictionary<string, string>
238 ["id"] = statusId.ToString(),
241 return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
244 public Task<LazyJson<TwitterStatus>> FavoritesDestroy(long statusId)
246 var endpoint = new Uri("favorites/destroy.json", UriKind.Relative);
247 var param = new Dictionary<string, string>
249 ["id"] = statusId.ToString(),
252 return this.apiConnection.PostLazyAsync<TwitterStatus>(endpoint, param);
255 public Task<TwitterFriendship> FriendshipsShow(string sourceScreenName, string targetScreenName)
257 var endpoint = new Uri("friendships/show.json", UriKind.Relative);
258 var param = new Dictionary<string, string>
260 ["source_screen_name"] = sourceScreenName,
261 ["target_screen_name"] = targetScreenName,
264 return this.apiConnection.GetAsync<TwitterFriendship>(endpoint, param, "/friendships/show");
267 public Task<LazyJson<TwitterFriendship>> FriendshipsCreate(string screenName)
269 var endpoint = new Uri("friendships/create.json", UriKind.Relative);
270 var param = new Dictionary<string, string>
272 ["screen_name"] = screenName,
275 return this.apiConnection.PostLazyAsync<TwitterFriendship>(endpoint, param);
278 public Task<LazyJson<TwitterFriendship>> FriendshipsDestroy(string screenName)
280 var endpoint = new Uri("friendships/destroy.json", UriKind.Relative);
281 var param = new Dictionary<string, string>
283 ["screen_name"] = screenName,
286 return this.apiConnection.PostLazyAsync<TwitterFriendship>(endpoint, param);
289 public Task<long[]> NoRetweetIds(long? cursor = null)
291 var endpoint = new Uri("friendships/no_retweets/ids.json", UriKind.Relative);
293 return this.apiConnection.GetAsync<long[]>(endpoint, null, "/friendships/no_retweets/ids");
296 public Task<TwitterIds> FollowersIds(long? cursor = null)
298 var endpoint = new Uri("followers/ids.json", UriKind.Relative);
299 var param = new Dictionary<string, string>();
302 param["cursor"] = cursor.ToString();
304 return this.apiConnection.GetAsync<TwitterIds>(endpoint, param, "/followers/ids");
307 public Task<TwitterIds> MutesUsersIds(long? cursor = null)
309 var endpoint = new Uri("mutes/users/ids.json", UriKind.Relative);
310 var param = new Dictionary<string, string>();
313 param["cursor"] = cursor.ToString();
315 return this.apiConnection.GetAsync<TwitterIds>(endpoint, param, "/mutes/users/ids");
318 public Task<TwitterIds> BlocksIds(long? cursor = null)
320 var endpoint = new Uri("blocks/ids.json", UriKind.Relative);
321 var param = new Dictionary<string, string>();
324 param["cursor"] = cursor.ToString();
326 return this.apiConnection.GetAsync<TwitterIds>(endpoint, param, "/blocks/ids");
329 public Task<LazyJson<TwitterUser>> BlocksCreate(string screenName)
331 var endpoint = new Uri("blocks/create.json", UriKind.Relative);
332 var param = new Dictionary<string, string>
334 ["screen_name"] = screenName,
337 return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
340 public Task<LazyJson<TwitterUser>> BlocksDestroy(string screenName)
342 var endpoint = new Uri("blocks/destroy.json", UriKind.Relative);
343 var param = new Dictionary<string, string>
345 ["screen_name"] = screenName,
348 return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
351 public Task<LazyJson<TwitterUser>> AccountUpdateProfile(string name, string url, string location, string description)
353 var endpoint = new Uri("account/update_profile.json", UriKind.Relative);
354 var param = new Dictionary<string, string>
356 ["include_entities"] = "true",
357 ["include_ext_alt_text"] = "true",
361 param["name"] = name;
364 if (location != null)
365 param["location"] = location;
367 if (description != null)
369 // name, location, description に含まれる < > " の文字はTwitter側で除去されるが、
370 // twitter.com の挙動では description でのみ < 等の文字参照を使って表示することができる
371 var escapedDescription = description.Replace("<", "<").Replace(">", ">").Replace("\"", """);
372 param["description"] = escapedDescription;
375 return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param);
378 public Task<LazyJson<TwitterUser>> AccountUpdateProfileImage(IMediaItem image)
380 var endpoint = new Uri("account/update_profile_image.json", UriKind.Relative);
381 var param = new Dictionary<string, string>
383 ["include_entities"] = "true",
384 ["include_ext_alt_text"] = "true",
386 var paramMedia = new Dictionary<string, IMediaItem>
391 return this.apiConnection.PostLazyAsync<TwitterUser>(endpoint, param, paramMedia);
394 public Task<TwitterConfiguration> Configuration()
396 var endpoint = new Uri("help/configuration.json", UriKind.Relative);
398 return this.apiConnection.GetAsync<TwitterConfiguration>(endpoint, null, "/help/configuration");
401 public Task<LazyJson<TwitterUploadMediaResult>> MediaUpload(IMediaItem media)
403 var endpoint = new Uri("https://upload.twitter.com/1.1/media/upload.json");
404 var paramMedia = new Dictionary<string, IMediaItem>
409 return this.apiConnection.PostLazyAsync<TwitterUploadMediaResult>(endpoint, null, paramMedia);
412 public void Dispose()
414 this.apiConnection?.Dispose();