1 // OpenTween - Client of Twitter
2 // Copyright (c) 2014 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.
22 #nullable enable annotations
25 using System.Collections.Generic;
27 using System.Runtime.Serialization;
29 using System.Threading.Tasks;
31 namespace OpenTween.Api.DataModel
33 // 参照: https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/tweet-object
36 public class TwitterStatus
38 [DataMember(Name = "coordinates", IsRequired = false)]
39 public GeoJsonPoint? Coordinates { get; set; }
41 [DataMember(Name = "created_at")]
42 public string CreatedAt { get; set; }
44 [DataMember(Name = "display_text_range")]
45 public int[] DisplayTextRange { get; set; }
47 [DataMember(Name = "entities")]
48 public TwitterEntities Entities { get; set; }
50 [DataMember(Name = "extended_entities", IsRequired = false)]
51 public TwitterEntities? ExtendedEntities { get; set; }
53 [DataMember(Name = "favorite_count")]
54 public int? FavoriteCount { get; set; }
56 [DataMember(Name = "favorited")]
57 public bool? Favorited { get; set; }
59 [DataMember(Name = "filter_level")]
60 public string FilterLevel { get; set; }
62 [DataMember(Name = "full_text")]
63 public string FullText { get; set; }
65 [DataMember(Name = "id")]
66 public long Id { get; set; }
68 [DataMember(Name = "id_str")]
69 public string IdStr { get; set; }
71 [DataMember(Name = "in_reply_to_screen_name")]
72 public string? InReplyToScreenName { get; set; }
74 [DataMember(Name = "in_reply_to_status_id")]
75 public long? InReplyToStatusId { get; set; }
77 [DataMember(Name = "in_reply_to_status_id_str")]
78 public string? InReplyToStatusIdStr { get; set; }
80 [DataMember(Name = "in_reply_to_user_id")]
81 public long? InReplyToUserId { get; set; }
83 [DataMember(Name = "in_reply_to_user_id_str")]
84 public string? InReplyToUserIdStr { get; set; }
86 [DataMember(Name = "is_quote_status")]
87 public bool IsQuoteStatus { get; set; }
89 [DataMember(Name = "lang")]
90 public string? Lang { get; set; }
92 [DataMember(Name = "place", IsRequired = false)]
93 public TwitterPlace? Place { get; set; }
95 [DataMember(Name = "possibly_sensitive")]
96 public bool? PossiblySensitive { get; set; }
98 [DataMember(Name = "quote_count")]
99 public int? QuoteCount { get; set; }
101 [DataMember(Name = "quoted_status_id", IsRequired = false)]
102 public long? QuotedStatusId { get; set; }
104 [DataMember(Name = "quoted_status_id_str", IsRequired = false)]
105 public string? QuotedStatusIdStr { get; set; }
107 [DataMember(Name = "quoted_status", IsRequired = false)]
108 public TwitterStatus? QuotedStatus { get; set; }
110 [DataMember(Name = "quoted_status_permalink", IsRequired = false)]
111 public TwitterQuotedStatusPermalink? QuotedStatusPermalink { get; set; } // https://twittercommunity.com/t/105473
113 [DataMember(Name = "reply_count")]
114 public int ReplyCount { get; set; }
116 [DataMember(Name = "retweet_count")]
117 public int RetweetCount { get; set; }
119 [DataMember(Name = "retweeted")]
120 public bool Retweeted { get; set; }
122 [DataMember(Name = "retweeted_status", IsRequired = false)]
123 public TwitterStatus? RetweetedStatus { get; set; }
125 [DataMember(Name = "source")]
126 public string Source { get; set; }
128 [DataMember(Name = "truncated")]
129 public bool Truncated { get; set; }
131 [DataMember(Name = "user")]
132 public TwitterUser User { get; set; }
134 [DataMember(Name = "withheld_copyright")]
135 public bool WithheldCopyright { get; set; }
137 [DataMember(Name = "withheld_in_countries")]
138 public string[] WithheldInCountries { get; set; }
140 [DataMember(Name = "withheld_scope")]
141 public string WithheldScope { get; set; }
144 /// Entities と ExtendedEntities をマージした状態のエンティティを返します
147 public TwitterEntities MergedEntities
151 if (this.ExtendedEntities == null)
152 return this.Entities;
154 return new TwitterEntities
156 Hashtags = this.Entities.Hashtags,
157 Media = this.ExtendedEntities.Media ?? this.Entities.Media,
158 Symbols = this.Entities.Symbols,
159 Urls = this.Entities.Urls,
160 UserMentions = this.Entities.UserMentions,
165 /// <exception cref="SerializationException"/>
166 public static TwitterStatus ParseJson(string json)
167 => MyCommon.CreateDataFromJson<TwitterStatus>(json);
169 /// <exception cref="SerializationException"/>
170 public static TwitterStatus[] ParseJsonArray(string json)
171 => MyCommon.CreateDataFromJson<TwitterStatus[]>(json);
175 public class TwitterQuotedStatusPermalink
177 [DataMember(Name = "url")]
178 public string Url { get; set; }
180 [DataMember(Name = "expanded")]
181 public string Expanded { get; set; }
183 [DataMember(Name = "display")]
184 public string Display { get; set; }
188 /// Streaming API または tweet_mode=compat の REST API から返されるツイート (Compatibility mode)
191 public class TwitterStatusCompat
193 [DataMember(Name = "coordinates", IsRequired = false)]
194 public GeoJsonPoint? Coordinates { get; set; }
196 [DataMember(Name = "created_at")]
197 public string CreatedAt { get; set; }
199 [DataMember(Name = "entities")]
200 public TwitterEntities Entities { get; set; }
202 [DataMember(Name = "extended_entities", IsRequired = false)]
203 public TwitterEntities? ExtendedEntities { get; set; }
205 [DataMember(Name = "extended_tweet", IsRequired = false)]
206 public TwitterStatusCompat.Extended? ExtendedTweet { get; set; }
209 public class Extended
211 [DataMember(Name = "display_text_range")]
212 public int[] DisplayTextRange { get; set; }
214 [DataMember(Name = "entities")]
215 public TwitterEntities Entities { get; set; }
217 [DataMember(Name = "extended_entities", IsRequired = false)]
218 public TwitterEntities? ExtendedEntities { get; set; }
220 [DataMember(Name = "full_text")]
221 public string FullText { get; set; }
224 [DataMember(Name = "favorite_count")]
225 public int? FavoriteCount { get; set; }
227 [DataMember(Name = "favorited")]
228 public bool? Favorited { get; set; }
230 [DataMember(Name = "filter_level")]
231 public string FilterLevel { get; set; }
233 [DataMember(Name = "id")]
234 public long Id { get; set; }
236 [DataMember(Name = "id_str")]
237 public string IdStr { get; set; }
239 [DataMember(Name = "in_reply_to_screen_name")]
240 public string? InReplyToScreenName { get; set; }
242 [DataMember(Name = "in_reply_to_status_id")]
243 public long? InReplyToStatusId { get; set; }
245 [DataMember(Name = "in_reply_to_status_id_str")]
246 public string? InReplyToStatusIdStr { get; set; }
248 [DataMember(Name = "in_reply_to_user_id")]
249 public long? InReplyToUserId { get; set; }
251 [DataMember(Name = "in_reply_to_user_id_str")]
252 public string? InReplyToUserIdStr { get; set; }
254 [DataMember(Name = "is_quote_status")]
255 public bool IsQuoteStatus { get; set; }
257 [DataMember(Name = "lang")]
258 public string? Lang { get; set; }
260 [DataMember(Name = "place", IsRequired = false)]
261 public TwitterPlace? Place { get; set; }
263 [DataMember(Name = "possibly_sensitive")]
264 public bool? PossiblySensitive { get; set; }
266 [DataMember(Name = "quote_count")]
267 public int? QuoteCount { get; set; }
269 [DataMember(Name = "quoted_status_id", IsRequired = false)]
270 public long? QuotedStatusId { get; set; }
272 [DataMember(Name = "quoted_status_id_str", IsRequired = false)]
273 public string? QuotedStatusIdStr { get; set; }
275 [DataMember(Name = "quoted_status", IsRequired = false)]
276 public TwitterStatusCompat? QuotedStatus { get; set; }
278 [DataMember(Name = "quoted_status_permalink", IsRequired = false)]
279 public TwitterQuotedStatusPermalink? QuotedStatusPermalink { get; set; } // https://twittercommunity.com/t/105473
281 [DataMember(Name = "reply_count")]
282 public int ReplyCount { get; set; }
284 [DataMember(Name = "retweet_count")]
285 public int RetweetCount { get; set; }
287 [DataMember(Name = "retweeted")]
288 public bool Retweeted { get; set; }
290 [DataMember(Name = "retweeted_status", IsRequired = false)]
291 public TwitterStatusCompat? RetweetedStatus { get; set; }
293 [DataMember(Name = "source")]
294 public string Source { get; set; }
296 [DataMember(Name = "text")]
297 public string Text { get; set; }
299 [DataMember(Name = "truncated")]
300 public bool Truncated { get; set; }
302 [DataMember(Name = "user")]
303 public TwitterUser User { get; set; }
305 [DataMember(Name = "withheld_copyright")]
306 public bool WithheldCopyright { get; set; }
308 [DataMember(Name = "withheld_in_countries")]
309 public string[] WithheldInCountries { get; set; }
311 [DataMember(Name = "withheld_scope")]
312 public string WithheldScope { get; set; }
314 /// <summary>Compatibility Modeのツイートを<see cref="TwitterStatus"/>に変換します</summary>
315 public TwitterStatus Normalize()
317 var normalized = new TwitterStatus
319 Coordinates = this.Coordinates,
320 CreatedAt = this.CreatedAt,
321 FavoriteCount = this.FavoriteCount,
322 Favorited = this.Favorited,
323 FilterLevel = this.FilterLevel,
326 InReplyToScreenName = this.InReplyToScreenName,
327 InReplyToStatusId = this.InReplyToStatusId,
328 InReplyToStatusIdStr = this.InReplyToStatusIdStr,
329 InReplyToUserId = this.InReplyToUserId,
330 InReplyToUserIdStr = this.InReplyToUserIdStr,
331 IsQuoteStatus = this.IsQuoteStatus,
334 PossiblySensitive = this.PossiblySensitive,
335 QuoteCount = this.QuoteCount,
336 QuotedStatusId = this.QuotedStatusId,
337 QuotedStatusIdStr = this.QuotedStatusIdStr,
338 QuotedStatus = this.QuotedStatus?.Normalize(),
339 QuotedStatusPermalink = this.QuotedStatusPermalink,
340 ReplyCount = this.ReplyCount,
341 RetweetCount = this.RetweetCount,
342 Retweeted = this.Retweeted,
343 RetweetedStatus = this.RetweetedStatus?.Normalize(),
344 Source = this.Source,
346 WithheldCopyright = this.WithheldCopyright,
347 WithheldInCountries = this.WithheldInCountries,
348 WithheldScope = this.WithheldScope,
351 if (this.ExtendedTweet != null)
354 normalized.DisplayTextRange = this.ExtendedTweet.DisplayTextRange;
355 normalized.Entities = this.ExtendedTweet.Entities;
356 normalized.ExtendedEntities = this.ExtendedTweet.ExtendedEntities;
357 normalized.FullText = this.ExtendedTweet.FullText;
358 normalized.Truncated = false;
363 normalized.DisplayTextRange = new[] { 0, this.GetCodePointCount(this.Text) };
364 normalized.Entities = this.Entities;
365 normalized.ExtendedEntities = this.ExtendedEntities;
366 normalized.FullText = this.Text;
367 normalized.Truncated = this.Truncated;
373 /// <summary>Unicodeコードポイント単位の文字数を返します</summary>
374 private int GetCodePointCount(string text)
375 => text.Length - text.Sum(x => char.IsHighSurrogate(x) ? 1 : 0);
377 /// <exception cref="SerializationException"/>
378 public static TwitterStatusCompat ParseJson(string json)
379 => MyCommon.CreateDataFromJson<TwitterStatusCompat>(json);
381 /// <exception cref="SerializationException"/>
382 public static TwitterStatusCompat[] ParseJsonArray(string json)
383 => MyCommon.CreateDataFromJson<TwitterStatusCompat[]>(json);
387 public class TwitterDirectMessage
389 [DataMember(Name = "entities", IsRequired = false)]
390 public TwitterEntities? Entities { get; set; }
392 [DataMember(Name = "created_at")]
393 public string CreatedAt { get; set; }
395 [DataMember(Name = "id")]
396 public long Id { get; set; }
398 [DataMember(Name = "id_str")]
399 public string IdStr { get; set; }
401 [DataMember(Name = "text")]
402 public string Text { get; set; }
404 [DataMember(Name = "sender_id")]
405 public long SenderId { get; set; }
407 [DataMember(Name = "sender_id_str")]
408 public string SenderIdStr { get; set; }
410 [DataMember(Name = "sender_screen_name")]
411 public string SenderScreenName { get; set; }
413 [DataMember(Name = "sender", IsRequired = false)]
414 public TwitterUser? Sender { get; set; }
416 [DataMember(Name = "recipient_id")]
417 public long RecipientId { get; set; }
419 [DataMember(Name = "recipient_id_str")]
420 public string RecipientIdStr { get; set; }
422 [DataMember(Name = "recipient_screen_name")]
423 public string RecipientScreenName { get; set; }
425 [DataMember(Name = "recipient", IsRequired = false)]
426 public TwitterUser? Recipient { get; set; }
428 /// <exception cref="SerializationException"/>
429 public static TwitterDirectMessage ParseJson(string json)
430 => MyCommon.CreateDataFromJson<TwitterDirectMessage>(json);
432 /// <exception cref="SerializationException"/>
433 public static TwitterDirectMessage[] ParseJsonArray(string json)
434 => MyCommon.CreateDataFromJson<TwitterDirectMessage[]>(json);